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",
"savingCustomRules": "Saving custom rules...",
"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",
"savingCustomRules": "Guardando reglas personalizadas...",
"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: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/section_label.dart';
@ -199,10 +199,10 @@ class _GeneralSettingsState extends State<GeneralSettings> {
title: AppLocalizations.of(context)!.topItemsOrder,
subtitle: AppLocalizations.of(context)!.topItemsOrderDescription,
onTap: () => widget.splitView == true
? SplitView.of(context).push(const ReorderableTopItemsHome())
? SplitView.of(context).push(const TopItemsListSettings())
: Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const ReorderableTopItemsHome()
builder: (context) => const TopItemsListSettings()
)
)
),

View file

@ -1,6 +1,5 @@
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
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/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/providers/app_config_provider.dart';
@ -29,7 +26,14 @@ enum DraggingMode {
}
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
State<ReorderableTopItemsHome> createState() => _ReorderableTopItemsHomeState();
@ -37,7 +41,6 @@ class ReorderableTopItemsHome extends StatefulWidget {
class _ReorderableTopItemsHomeState extends State<ReorderableTopItemsHome> {
List<HomeTopItems> homeTopItemsList = [];
List<HomeTopItems> persistHomeTopItemsList = [];
List<_ItemData> renderItems = [];
int _indexOfKey(Key key) {
@ -63,7 +66,7 @@ class _ReorderableTopItemsHomeState extends State<ReorderableTopItemsHome> {
void _reorderDone(Key item) {
renderItems[_indexOfKey(item)];
setState(() => persistHomeTopItemsList = homeTopItemsList);
widget.setPersistHomeTopItems(homeTopItemsList);
}
List<HomeTopItems> reorderEnumItems(int oldIndex, int newIndex) {
@ -75,10 +78,8 @@ class _ReorderableTopItemsHomeState extends State<ReorderableTopItemsHome> {
@override
void initState() {
final appConfigProvider = Provider.of<AppConfigProvider>(context, listen: false);
homeTopItemsList = appConfigProvider.homeTopItemsOrder;
persistHomeTopItemsList = appConfigProvider.homeTopItemsOrder;
renderItems = appConfigProvider.homeTopItemsOrder.asMap().entries.map(
homeTopItemsList = widget.persistHomeTopItems;
renderItems = widget.persistHomeTopItems.asMap().entries.map(
(e) => _ItemData(
key: ValueKey(e.key),
title: e.value,
@ -136,99 +137,80 @@ 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
? DraggingMode.android
: DraggingMode.iOS;
return Scaffold(
appBar: AppBar(
title: Text(AppLocalizations.of(context)!.topItemsOrder),
surfaceTintColor: isDesktop(width) ? Colors.transparent : null,
actions: [
IconButton(
onPressed: !listEquals(appConfigProvider.homeTopItemsOrder, persistHomeTopItemsList)
? () => saveSettings()
: null,
icon: const Icon(Icons.save_rounded),
tooltip: AppLocalizations.of(context)!.save,
),
const SizedBox(width: 8)
],
),
body: Column(
children: [
Card(
margin: const EdgeInsets.all(16),
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
Icon(
Icons.info_rounded,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
const SizedBox(width: 16),
Flexible(
child: Text(AppLocalizations.of(context)!.topItemsReorderInfo)
)
],
),
),
),
Expanded(
child: reorderable_list.ReorderableList(
onReorder: _reorderCallback,
onReorderDone: _reorderDone,
child: ListView.builder(
itemBuilder: (context, index) => reorderable_list.ReorderableItem(
key: renderItems[index].key,
childBuilder: (context, state) {
if (draggingMode == DraggingMode.android) {
return reorderable_list.DelayedReorderableListener(
child: _Tile(
draggingMode: draggingMode,
isFirst: index == 0,
isLast: index == renderItems.length - 1,
state: state,
tileWidget: tile(renderItems[index].title),
return SafeArea(
top: false,
bottom: true,
child: Builder(
builder: (context) => CustomScrollView(
slivers: [
SliverOverlapInjector(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
),
SliverList.list(
children: [
Card(
margin: const EdgeInsets.all(16),
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
Icon(
Icons.info_rounded,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
);
}
else {
return _Tile(
draggingMode: draggingMode,
isFirst: index == 0,
isLast: index == renderItems.length - 1,
state: state,
tileWidget: tile(renderItems[index].title),
);
}
},
const SizedBox(width: 16),
Flexible(
child: Text(AppLocalizations.of(context)!.topItemsReorderInfo)
)
],
),
),
),
itemCount: renderItems.length,
)
),
),
],
reorderable_list.ReorderableList(
onReorder: _reorderCallback,
onReorderDone: _reorderDone,
child: ListView.builder(
primary: false,
shrinkWrap: true,
padding: const EdgeInsets.only(top: 0),
itemBuilder: (context, index) => reorderable_list.ReorderableItem(
key: renderItems[index].key,
childBuilder: (context, state) {
if (draggingMode == DraggingMode.android) {
return reorderable_list.DelayedReorderableListener(
child: _Tile(
draggingMode: draggingMode,
isFirst: index == 0,
isLast: index == renderItems.length - 1,
state: state,
tileWidget: tile(renderItems[index].title),
),
);
}
else {
return _Tile(
draggingMode: draggingMode,
isFirst: index == 0,
isLast: index == renderItems.length - 1,
state: state,
tileWidget: tile(renderItems[index].title),
);
}
},
),
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 bool? disabled;
final EdgeInsets? padding;
final IconData? leadingIcon;
const CustomSwitchListTile({
Key? key,
super.key,
required this.value,
required this.onChanged,
required this.title,
this.disabled,
this.subtitle,
this.padding
}) : super(key: key);
this.padding,
this.leadingIcon,
});
@override
Widget build(BuildContext context) {
@ -33,6 +35,13 @@ class CustomSwitchListTile extends StatelessWidget {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
if (leadingIcon != null) ...[
Icon(
leadingIcon,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
const SizedBox(width: 16),
],
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,