Added show and hide top items

This commit is contained in:
Juan Gilsanz Polo 2024-02-07 19:46:35 +01:00
parent ed0bc65285
commit 3e152db6ac
7 changed files with 317 additions and 104 deletions

View file

@ -769,5 +769,7 @@
"editCustomRules": "Edit custom rules", "editCustomRules": "Edit custom rules",
"savingCustomRules": "Saving custom rules...", "savingCustomRules": "Saving custom rules...",
"customRulesUpdatedSuccessfully": "Custom rules updated successfully", "customRulesUpdatedSuccessfully": "Custom rules updated successfully",
"customRulesNotUpdated": "Custom rules could not be updated" "customRulesNotUpdated": "Custom rules could not be updated",
"reorder": "Reorder",
"showHide": "Show/hide"
} }

View file

@ -769,5 +769,7 @@
"editCustomRules": "Editar reglas personalizadas", "editCustomRules": "Editar reglas personalizadas",
"savingCustomRules": "Guardando reglas personalizadas...", "savingCustomRules": "Guardando reglas personalizadas...",
"customRulesUpdatedSuccessfully": "Reglas personalizadas actualizadas correctamente", "customRulesUpdatedSuccessfully": "Reglas personalizadas actualizadas correctamente",
"customRulesNotUpdated": "Las reglas personalizadas no pudieron ser actualizadas" "customRulesNotUpdated": "Las reglas personalizadas no pudieron ser actualizadas",
"reorder": "Reordenar",
"showHide": "Mostrar/ocultar"
} }

View file

@ -8,7 +8,7 @@ import 'package:provider/provider.dart';
import 'package:store_checker/store_checker.dart'; import 'package:store_checker/store_checker.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/screens/settings/general_settings/reorderable_top_items_home.dart'; import 'package:adguard_home_manager/screens/settings/general_settings/top_items_list/top_items_list_settings.dart';
import 'package:adguard_home_manager/widgets/custom_list_tile.dart'; import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
import 'package:adguard_home_manager/widgets/section_label.dart'; import 'package:adguard_home_manager/widgets/section_label.dart';
@ -199,10 +199,10 @@ class _GeneralSettingsState extends State<GeneralSettings> {
title: AppLocalizations.of(context)!.topItemsOrder, title: AppLocalizations.of(context)!.topItemsOrder,
subtitle: AppLocalizations.of(context)!.topItemsOrderDescription, subtitle: AppLocalizations.of(context)!.topItemsOrderDescription,
onTap: () => widget.splitView == true onTap: () => widget.splitView == true
? SplitView.of(context).push(const ReorderableTopItemsHome()) ? SplitView.of(context).push(const TopItemsListSettings())
: Navigator.of(context).push( : Navigator.of(context).push(
MaterialPageRoute( MaterialPageRoute(
builder: (context) => const ReorderableTopItemsHome() builder: (context) => const TopItemsListSettings()
) )
) )
), ),

View file

@ -1,6 +1,5 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:flutter_reorderable_list/flutter_reorderable_list.dart' as reorderable_list; import 'package:flutter_reorderable_list/flutter_reorderable_list.dart' as reorderable_list;
@ -8,8 +7,6 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/widgets/custom_list_tile.dart'; import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
import 'package:adguard_home_manager/functions/desktop_mode.dart';
import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/constants/enums.dart'; import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
@ -29,7 +26,14 @@ enum DraggingMode {
} }
class ReorderableTopItemsHome extends StatefulWidget { class ReorderableTopItemsHome extends StatefulWidget {
const ReorderableTopItemsHome({super.key}); final List<HomeTopItems> persistHomeTopItems;
final void Function(List<HomeTopItems> value) setPersistHomeTopItems;
const ReorderableTopItemsHome({
super.key,
required this.persistHomeTopItems,
required this.setPersistHomeTopItems,
});
@override @override
State<ReorderableTopItemsHome> createState() => _ReorderableTopItemsHomeState(); State<ReorderableTopItemsHome> createState() => _ReorderableTopItemsHomeState();
@ -37,7 +41,6 @@ class ReorderableTopItemsHome extends StatefulWidget {
class _ReorderableTopItemsHomeState extends State<ReorderableTopItemsHome> { class _ReorderableTopItemsHomeState extends State<ReorderableTopItemsHome> {
List<HomeTopItems> homeTopItemsList = []; List<HomeTopItems> homeTopItemsList = [];
List<HomeTopItems> persistHomeTopItemsList = [];
List<_ItemData> renderItems = []; List<_ItemData> renderItems = [];
int _indexOfKey(Key key) { int _indexOfKey(Key key) {
@ -63,7 +66,7 @@ class _ReorderableTopItemsHomeState extends State<ReorderableTopItemsHome> {
void _reorderDone(Key item) { void _reorderDone(Key item) {
renderItems[_indexOfKey(item)]; renderItems[_indexOfKey(item)];
setState(() => persistHomeTopItemsList = homeTopItemsList); widget.setPersistHomeTopItems(homeTopItemsList);
} }
List<HomeTopItems> reorderEnumItems(int oldIndex, int newIndex) { List<HomeTopItems> reorderEnumItems(int oldIndex, int newIndex) {
@ -75,10 +78,8 @@ class _ReorderableTopItemsHomeState extends State<ReorderableTopItemsHome> {
@override @override
void initState() { void initState() {
final appConfigProvider = Provider.of<AppConfigProvider>(context, listen: false); homeTopItemsList = widget.persistHomeTopItems;
homeTopItemsList = appConfigProvider.homeTopItemsOrder; renderItems = widget.persistHomeTopItems.asMap().entries.map(
persistHomeTopItemsList = appConfigProvider.homeTopItemsOrder;
renderItems = appConfigProvider.homeTopItemsOrder.asMap().entries.map(
(e) => _ItemData( (e) => _ItemData(
key: ValueKey(e.key), key: ValueKey(e.key),
title: e.value, title: e.value,
@ -136,45 +137,22 @@ class _ReorderableTopItemsHomeState extends State<ReorderableTopItemsHome> {
} }
} }
void saveSettings() async {
final result = await appConfigProvider.setHomeTopItemsOrder(homeTopItemsList);
if (!mounted) return;
if (result == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.settingsSaved,
color: Colors.green
);
}
else {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.settingsNotSaved,
color: Colors.red
);
}
}
final draggingMode = Platform.isAndroid final draggingMode = Platform.isAndroid
? DraggingMode.android ? DraggingMode.android
: DraggingMode.iOS; : DraggingMode.iOS;
return Scaffold( return SafeArea(
appBar: AppBar( top: false,
title: Text(AppLocalizations.of(context)!.topItemsOrder), bottom: true,
surfaceTintColor: isDesktop(width) ? Colors.transparent : null, child: Builder(
actions: [ builder: (context) => CustomScrollView(
IconButton( slivers: [
onPressed: !listEquals(appConfigProvider.homeTopItemsOrder, persistHomeTopItemsList) SliverOverlapInjector(
? () => saveSettings() handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
: null,
icon: const Icon(Icons.save_rounded),
tooltip: AppLocalizations.of(context)!.save,
), ),
const SizedBox(width: 8) SliverList.list(
],
),
body: Column(
children: [ children: [
Card( Card(
margin: const EdgeInsets.all(16), margin: const EdgeInsets.all(16),
@ -194,11 +172,13 @@ class _ReorderableTopItemsHomeState extends State<ReorderableTopItemsHome> {
), ),
), ),
), ),
Expanded( reorderable_list.ReorderableList(
child: reorderable_list.ReorderableList(
onReorder: _reorderCallback, onReorder: _reorderCallback,
onReorderDone: _reorderDone, onReorderDone: _reorderDone,
child: ListView.builder( child: ListView.builder(
primary: false,
shrinkWrap: true,
padding: const EdgeInsets.only(top: 0),
itemBuilder: (context, index) => reorderable_list.ReorderableItem( itemBuilder: (context, index) => reorderable_list.ReorderableItem(
key: renderItems[index].key, key: renderItems[index].key,
childBuilder: (context, state) { childBuilder: (context, state) {
@ -227,9 +207,11 @@ class _ReorderableTopItemsHomeState extends State<ReorderableTopItemsHome> {
itemCount: renderItems.length, itemCount: renderItems.length,
) )
), ),
), ]
)
], ],
), ),
),
); );
} }
} }

View file

@ -0,0 +1,87 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/widgets/custom_switch_list_tile.dart';
import 'package:adguard_home_manager/constants/enums.dart';
class ShowHideTopItemsList extends StatelessWidget {
final List<HomeTopItems> enabledHomeTopItems;
final void Function(List<HomeTopItems>) setEnabledHomeTopItems;
const ShowHideTopItemsList({
super.key,
required this.enabledHomeTopItems,
required this.setEnabledHomeTopItems,
});
@override
Widget build(BuildContext context) {
const padding = EdgeInsets.symmetric(horizontal: 16, vertical: 8);
void updateValue(HomeTopItems value, bool newStatus) {
if (newStatus == true) {
setEnabledHomeTopItems([
...enabledHomeTopItems,
value
]);
}
else {
setEnabledHomeTopItems(enabledHomeTopItems.where((e) => e != value).toList());
}
}
return SafeArea(
top: false,
bottom: true,
child: Builder(
builder: (context) => CustomScrollView(
slivers: [
SliverOverlapInjector(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
),
SliverList.list(
children: [
const SizedBox(height: 8),
CustomSwitchListTile(
value: enabledHomeTopItems.contains(HomeTopItems.queriedDomains),
onChanged: (v) => updateValue(HomeTopItems.queriedDomains, v),
title: AppLocalizations.of(context)!.topQueriedDomains,
leadingIcon: Icons.install_desktop_outlined,
padding: padding,
),
CustomSwitchListTile(
value: enabledHomeTopItems.contains(HomeTopItems.blockedDomains),
onChanged: (v) => updateValue(HomeTopItems.blockedDomains, v),
title: AppLocalizations.of(context)!.topBlockedDomains,
leadingIcon: Icons.block_rounded,
padding: padding,
),
CustomSwitchListTile(
value: enabledHomeTopItems.contains(HomeTopItems.recurrentClients),
onChanged: (v) => updateValue(HomeTopItems.recurrentClients, v),
title: AppLocalizations.of(context)!.topClients,
leadingIcon: Icons.smartphone_rounded,
padding: padding,
),
CustomSwitchListTile(
value: enabledHomeTopItems.contains(HomeTopItems.topUpstreams),
onChanged: (v) => updateValue(HomeTopItems.topUpstreams, v),
title: AppLocalizations.of(context)!.topUpstreams,
leadingIcon: Icons.upload_file_rounded,
padding: padding,
),
CustomSwitchListTile(
value: enabledHomeTopItems.contains(HomeTopItems.avgUpstreamResponseTime),
onChanged: (v) => updateValue(HomeTopItems.avgUpstreamResponseTime, v),
title: AppLocalizations.of(context)!.averageUpstreamResponseTime,
leadingIcon: Icons.timer_rounded,
padding: padding,
),
]
)
],
),
)
);
}
}

View file

@ -0,0 +1,131 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/screens/settings/general_settings/top_items_list/show_hide_top_items_list.dart';
import 'package:adguard_home_manager/screens/settings/general_settings/top_items_list/reorderable_top_items_home.dart';
import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/functions/desktop_mode.dart';
import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart';
class TopItemsListSettings extends StatefulWidget {
const TopItemsListSettings({super.key});
@override
State<TopItemsListSettings> createState() => _TopItemsListSettingsState();
}
class _TopItemsListSettingsState extends State<TopItemsListSettings> with TickerProviderStateMixin {
late TabController _tabController;
List<HomeTopItems> persistHomeTopItemsList = [];
@override
void initState() {
final appConfigProvider = Provider.of<AppConfigProvider>(context, listen: false);
persistHomeTopItemsList = appConfigProvider.homeTopItemsOrder;
super.initState();
_tabController = TabController(length: 2, vsync: this);
}
@override
Widget build(BuildContext context) {
final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width;
void saveSettings() async {
final result = await appConfigProvider.setHomeTopItemsOrder(persistHomeTopItemsList);
if (!context.mounted) return;
if (result == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.settingsSaved,
color: Colors.green
);
}
else {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.settingsNotSaved,
color: Colors.red
);
}
}
return Scaffold(
body: DefaultTabController(
length: 2,
child: NestedScrollView(
headerSliverBuilder: (context, innerBoxIsScrolled) => [
SliverOverlapAbsorber(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
sliver: SliverAppBar(
pinned: true,
floating: true,
centerTitle: false,
forceElevated: innerBoxIsScrolled,
surfaceTintColor: isDesktop(width) ? Colors.transparent : null,
title: Text(AppLocalizations.of(context)!.topItemsOrder),
actions: [
IconButton(
onPressed: !listEquals(appConfigProvider.homeTopItemsOrder, persistHomeTopItemsList)
? () => saveSettings()
: null,
icon: const Icon(Icons.save_rounded),
tooltip: AppLocalizations.of(context)!.save,
),
const SizedBox(width: 8)
],
bottom: TabBar(
controller: _tabController,
unselectedLabelColor: Theme.of(context).colorScheme.onSurfaceVariant,
tabs: [
Tab(
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.reorder_rounded),
const SizedBox(width: 8),
Text(AppLocalizations.of(context)!.reorder)
],
),
),
Tab(
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.remove_red_eye_rounded),
const SizedBox(width: 8),
Text(AppLocalizations.of(context)!.showHide)
],
),
),
]
)
),
)
],
body: TabBarView(
controller: _tabController,
children: [
ReorderableTopItemsHome(
persistHomeTopItems: persistHomeTopItemsList,
setPersistHomeTopItems: (v) => setState(() => persistHomeTopItemsList = v),
),
ShowHideTopItemsList(
enabledHomeTopItems: persistHomeTopItemsList,
setEnabledHomeTopItems: (v) => setState(() => persistHomeTopItemsList = v),
)
]
)
),
),
);
}
}

View file

@ -7,16 +7,18 @@ class CustomSwitchListTile extends StatelessWidget {
final String? subtitle; final String? subtitle;
final bool? disabled; final bool? disabled;
final EdgeInsets? padding; final EdgeInsets? padding;
final IconData? leadingIcon;
const CustomSwitchListTile({ const CustomSwitchListTile({
Key? key, super.key,
required this.value, required this.value,
required this.onChanged, required this.onChanged,
required this.title, required this.title,
this.disabled, this.disabled,
this.subtitle, this.subtitle,
this.padding this.padding,
}) : super(key: key); this.leadingIcon,
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -33,6 +35,13 @@ class CustomSwitchListTile extends StatelessWidget {
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
if (leadingIcon != null) ...[
Icon(
leadingIcon,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
const SizedBox(width: 16),
],
Expanded( Expanded(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,