[imp]: Improvement in settings's architecture
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:android_intent_plus/android_intent.dart';
|
||||
import 'package:florid/providers/settings_provider.dart';
|
||||
import 'package:florid/services/update_check_service.dart';
|
||||
import 'package:florid/widgets/m_list.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
@@ -8,22 +11,18 @@ import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../providers/settings_provider.dart';
|
||||
import '../services/update_check_service.dart';
|
||||
import '../widgets/m_list.dart';
|
||||
class AppManagementScreen extends StatefulWidget {
|
||||
const AppManagementScreen({super.key});
|
||||
|
||||
class UpdateSettingsScreen extends StatefulWidget {
|
||||
const UpdateSettingsScreen({super.key});
|
||||
|
||||
@override
|
||||
State<UpdateSettingsScreen> createState() => _UpdateSettingsScreenState();
|
||||
}
|
||||
|
||||
class _UpdateSettingsScreenState extends State<UpdateSettingsScreen> {
|
||||
static const MethodChannel _batteryChannel = MethodChannel(
|
||||
'florid/battery_optimizations',
|
||||
);
|
||||
|
||||
@override
|
||||
State<AppManagementScreen> createState() => _AppManagementScreenState();
|
||||
}
|
||||
|
||||
class _AppManagementScreenState extends State<AppManagementScreen> {
|
||||
bool? _isIgnoringBatteryOptimizations;
|
||||
|
||||
@override
|
||||
@@ -32,12 +31,59 @@ class _UpdateSettingsScreenState extends State<UpdateSettingsScreen> {
|
||||
_loadBatteryOptimizationStatus();
|
||||
}
|
||||
|
||||
String _installMethodLabel(InstallMethod method) {
|
||||
switch (method) {
|
||||
case InstallMethod.shizuku:
|
||||
return 'Shizuku';
|
||||
case InstallMethod.system:
|
||||
return 'System installer';
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _showInstallMethodDialog(
|
||||
BuildContext context,
|
||||
SettingsProvider settings,
|
||||
) async {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('Installation method'),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: InstallMethod.values
|
||||
.map(
|
||||
(method) => RadioListTile<InstallMethod>(
|
||||
value: method,
|
||||
groupValue: settings.installMethod,
|
||||
title: Text(_installMethodLabel(method)),
|
||||
subtitle: method == InstallMethod.shizuku
|
||||
? const Text('Requires Shizuku to be running')
|
||||
: const Text('Uses the standard system installer'),
|
||||
onChanged: (value) async {
|
||||
if (value == null) return;
|
||||
await settings.setInstallMethod(value);
|
||||
if (!context.mounted) return;
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: const Text('Close'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _loadBatteryOptimizationStatus() async {
|
||||
if (!Platform.isAndroid) return;
|
||||
try {
|
||||
final isIgnoring = await _batteryChannel.invokeMethod<bool>(
|
||||
'isIgnoringBatteryOptimizations',
|
||||
);
|
||||
final isIgnoring = await AppManagementScreen._batteryChannel
|
||||
.invokeMethod<bool>('isIgnoringBatteryOptimizations');
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
_isIgnoringBatteryOptimizations = isIgnoring ?? false;
|
||||
@@ -173,7 +219,7 @@ class _UpdateSettingsScreenState extends State<UpdateSettingsScreen> {
|
||||
return Consumer<SettingsProvider>(
|
||||
builder: (context, settings, _) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('Update settings')),
|
||||
appBar: AppBar(title: const Text('App Management')),
|
||||
body: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||
@@ -181,6 +227,72 @@ class _UpdateSettingsScreenState extends State<UpdateSettingsScreen> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
spacing: 16,
|
||||
children: [
|
||||
Column(
|
||||
spacing: 4,
|
||||
children: [
|
||||
MListHeader(title: 'Installation method'),
|
||||
MRadioListView<InstallMethod>(
|
||||
items: InstallMethod.values
|
||||
.map(
|
||||
(method) => MRadioListItemData<InstallMethod>(
|
||||
title: _installMethodLabel(method),
|
||||
subtitle: method == InstallMethod.shizuku
|
||||
? 'Requires Shizuku to be running'
|
||||
: 'Uses the standard system installer',
|
||||
value: method,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
groupValue: settings.installMethod,
|
||||
onChanged: (value) async {
|
||||
await settings.setInstallMethod(value);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
Column(
|
||||
spacing: 4,
|
||||
children: [
|
||||
MListHeader(title: 'Downloads & Storage'),
|
||||
MListView(
|
||||
items: [
|
||||
MListItemData(
|
||||
title: 'Auto-install after download',
|
||||
onTap: () {
|
||||
settings.setAutoInstallApk(
|
||||
!settings.autoInstallApk,
|
||||
);
|
||||
},
|
||||
subtitle:
|
||||
'Install APKs automatically once download finishes',
|
||||
suffix: Switch(
|
||||
value: settings.autoInstallApk,
|
||||
onChanged: (value) {
|
||||
settings.setAutoInstallApk(value);
|
||||
},
|
||||
),
|
||||
),
|
||||
MListItemData(
|
||||
title: 'Delete APK after install',
|
||||
onTap: () {
|
||||
settings.setAutoInstallApk(
|
||||
!settings.autoInstallApk,
|
||||
);
|
||||
},
|
||||
subtitle:
|
||||
'Remove installer files after successful installation',
|
||||
suffix: Switch(
|
||||
value: settings.autoDeleteApk,
|
||||
onChanged: (value) {
|
||||
settings.setAutoDeleteApk(value);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
Column(
|
||||
spacing: 4,
|
||||
children: [
|
||||
@@ -3,6 +3,7 @@ import 'dart:io';
|
||||
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:florid/l10n/app_localizations.dart';
|
||||
import 'package:florid/screens/app_management_screen.dart';
|
||||
import 'package:florid/widgets/m_list.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
@@ -18,9 +19,7 @@ import '../providers/settings_provider.dart';
|
||||
import '../screens/appearance_screen.dart';
|
||||
import '../screens/repositories_screen.dart';
|
||||
import '../screens/troubleshooting_screen.dart';
|
||||
import '../screens/update_settings_screen.dart';
|
||||
import '../services/fdroid_api_service.dart';
|
||||
import '../services/update_check_service.dart';
|
||||
|
||||
class SettingsScreen extends StatefulWidget {
|
||||
const SettingsScreen({super.key});
|
||||
@@ -182,112 +181,6 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
String _updateNetworkPolicyLabel(UpdateNetworkPolicy policy) {
|
||||
switch (policy) {
|
||||
case UpdateNetworkPolicy.wifiOnly:
|
||||
return 'Wi-Fi only';
|
||||
case UpdateNetworkPolicy.wifiAndCharging:
|
||||
return 'Wi-Fi + charging';
|
||||
case UpdateNetworkPolicy.any:
|
||||
default:
|
||||
return 'Mobile data or Wi-Fi';
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _showUpdateNetworkPolicyDialog(
|
||||
BuildContext context,
|
||||
SettingsProvider settings,
|
||||
) async {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('Update network'),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: UpdateNetworkPolicy.values
|
||||
.map(
|
||||
(policy) => RadioListTile<UpdateNetworkPolicy>(
|
||||
value: policy,
|
||||
groupValue: settings.updateNetworkPolicy,
|
||||
title: Text(_updateNetworkPolicyLabel(policy)),
|
||||
onChanged: (value) async {
|
||||
if (value == null) return;
|
||||
await settings.setUpdateNetworkPolicy(value);
|
||||
await UpdateCheckService.scheduleFromPrefs();
|
||||
if (!context.mounted) return;
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: const Text('Close'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
String _updateIntervalLabel(int hours) {
|
||||
switch (hours) {
|
||||
case 1:
|
||||
return 'Every 1 hour';
|
||||
case 2:
|
||||
return 'Every 2 hours';
|
||||
case 3:
|
||||
return 'Every 3 hours';
|
||||
case 6:
|
||||
return 'Every 6 hours';
|
||||
case 12:
|
||||
return 'Every 12 hours';
|
||||
case 24:
|
||||
return 'Daily';
|
||||
default:
|
||||
return 'Every $hours hours';
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _showUpdateIntervalDialog(
|
||||
BuildContext context,
|
||||
SettingsProvider settings,
|
||||
) async {
|
||||
const intervals = [1, 2, 3, 6, 12, 24];
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('Update interval'),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: intervals
|
||||
.map(
|
||||
(hours) => RadioListTile<int>(
|
||||
value: hours,
|
||||
groupValue: settings.updateIntervalHours,
|
||||
title: Text(_updateIntervalLabel(hours)),
|
||||
onChanged: (value) async {
|
||||
if (value == null) return;
|
||||
await settings.setUpdateIntervalHours(value);
|
||||
await UpdateCheckService.scheduleFromPrefs();
|
||||
if (!context.mounted) return;
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: const Text('Close'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Consumer<SettingsProvider>(
|
||||
@@ -306,7 +199,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
children: [
|
||||
MListHeader(
|
||||
title: 'General Settings',
|
||||
icon: Symbols.settings,
|
||||
icon: Symbols.mobile,
|
||||
),
|
||||
MListView(
|
||||
items: [
|
||||
@@ -334,6 +227,19 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
),
|
||||
suffix: Icon(Symbols.chevron_right),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
Column(
|
||||
spacing: 4,
|
||||
children: [
|
||||
MListHeader(
|
||||
title: 'Repositories & Management',
|
||||
icon: Symbols.settings,
|
||||
),
|
||||
MListView(
|
||||
items: [
|
||||
MListItemData(
|
||||
leading: Icon(Symbols.cloud),
|
||||
title: 'Manage repositories',
|
||||
@@ -350,15 +256,16 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
suffix: Icon(Symbols.chevron_right),
|
||||
),
|
||||
MListItemData(
|
||||
leading: Icon(Symbols.update),
|
||||
title: 'Update settings',
|
||||
subtitle: 'Manage background updates',
|
||||
leading: Icon(Symbols.discover_tune),
|
||||
title: 'App Management',
|
||||
subtitle:
|
||||
'Manage settings regarding installs and updates',
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
const UpdateSettingsScreen(),
|
||||
const AppManagementScreen(),
|
||||
),
|
||||
);
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user