mirror of
https://github.com/JGeek00/adguard-home-manager.git
synced 2025-04-19 21:39:16 +00:00
Created home top items reorder screen
This commit is contained in:
parent
d967399b64
commit
520a14fcda
8 changed files with 313 additions and 4 deletions
|
@ -655,5 +655,10 @@
|
||||||
"quickFilters": "Quick filters",
|
"quickFilters": "Quick filters",
|
||||||
"searchDomainInternet": "Search domain on the Internet",
|
"searchDomainInternet": "Search domain on the Internet",
|
||||||
"hideServerAddress": "Hide server address",
|
"hideServerAddress": "Hide server address",
|
||||||
"hideServerAddressDescription": "Hides the server address on the home screen"
|
"hideServerAddressDescription": "Hides the server address on the home screen",
|
||||||
|
"topItemsOrder": "Top items order",
|
||||||
|
"topItemsOrderDescription": "Order the home screen top items lists",
|
||||||
|
"topItemsReorderInfo": "Hold and swipe an item to reorder it.",
|
||||||
|
"discardChanges": "Discard changes",
|
||||||
|
"discardChangesDescription": "Are you sure you want to discard the changes?"
|
||||||
}
|
}
|
|
@ -655,5 +655,10 @@
|
||||||
"quickFilters": "Filtros rápidos",
|
"quickFilters": "Filtros rápidos",
|
||||||
"searchDomainInternet": "Buscar dominio en internet",
|
"searchDomainInternet": "Buscar dominio en internet",
|
||||||
"hideServerAddress": "Ocultar dirección del servidor",
|
"hideServerAddress": "Ocultar dirección del servidor",
|
||||||
"hideServerAddressDescription": "Oculta la dirección del servidor en la pantalla de inicio"
|
"hideServerAddressDescription": "Oculta la dirección del servidor en la pantalla de inicio",
|
||||||
|
"topItemsOrder": "Orden de los top",
|
||||||
|
"topItemsOrderDescription": "Ordena las listas de top de elementos en la pantalla de inicio",
|
||||||
|
"topItemsReorderInfo": "Mantén presionado y desliza un elemento para reordenarlo.",
|
||||||
|
"discardChanges": "Descartar cambios",
|
||||||
|
"discardChangesDescription": "¿Estás seguro de que deseas descartar los cambios realizados?"
|
||||||
}
|
}
|
|
@ -374,7 +374,7 @@ class AppConfigProvider with ChangeNotifier {
|
||||||
final updated = await updateConfigQuery(
|
final updated = await updateConfigQuery(
|
||||||
db: _dbInstance!,
|
db: _dbInstance!,
|
||||||
column: 'homeTopItemsOrder',
|
column: 'homeTopItemsOrder',
|
||||||
value: jsonEncode(order)
|
value: jsonEncode(List<String>.from(order.map((e) => e.name)))
|
||||||
);
|
);
|
||||||
if (updated == true) {
|
if (updated == true) {
|
||||||
_homeTopItemsOrder = order;
|
_homeTopItemsOrder = order;
|
||||||
|
|
|
@ -7,6 +7,8 @@ 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/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';
|
||||||
|
|
||||||
|
@ -181,6 +183,14 @@ class _GeneralSettingsState extends State<GeneralSettings> {
|
||||||
right: 10
|
right: 10
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
CustomListTile(
|
||||||
|
icon: Icons.reorder_rounded,
|
||||||
|
title: AppLocalizations.of(context)!.topItemsOrder,
|
||||||
|
subtitle: AppLocalizations.of(context)!.topItemsOrderDescription,
|
||||||
|
onTap: () => Navigator.push(context, MaterialPageRoute(
|
||||||
|
builder: (context) => const ReorderableTopItemsHome()
|
||||||
|
)),
|
||||||
|
),
|
||||||
SectionLabel(label: AppLocalizations.of(context)!.logs),
|
SectionLabel(label: AppLocalizations.of(context)!.logs),
|
||||||
CustomListTile(
|
CustomListTile(
|
||||||
icon: Icons.timer_rounded,
|
icon: Icons.timer_rounded,
|
|
@ -0,0 +1,280 @@
|
||||||
|
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_library;
|
||||||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
|
||||||
|
|
||||||
|
import 'package:adguard_home_manager/constants/enums.dart';
|
||||||
|
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
||||||
|
|
||||||
|
class ItemData {
|
||||||
|
final HomeTopItems title;
|
||||||
|
final Key key;
|
||||||
|
|
||||||
|
const ItemData({
|
||||||
|
required this.title,
|
||||||
|
required this.key
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
enum DraggingMode {
|
||||||
|
iOS,
|
||||||
|
android,
|
||||||
|
}
|
||||||
|
|
||||||
|
class ReorderableTopItemsHome extends StatefulWidget {
|
||||||
|
const ReorderableTopItemsHome({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ReorderableTopItemsHome> createState() => _ReorderableTopItemsHomeState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ReorderableTopItemsHomeState extends State<ReorderableTopItemsHome> {
|
||||||
|
List<HomeTopItems> homeTopItemsList = [];
|
||||||
|
List<HomeTopItems> persistHomeTopItemsList = [];
|
||||||
|
List<ItemData> renderItems = [];
|
||||||
|
|
||||||
|
int _indexOfKey(Key key) {
|
||||||
|
return renderItems.indexWhere((ItemData d) => d.key == key);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _reorderCallback(Key item, Key newPosition) {
|
||||||
|
int draggingIndex = _indexOfKey(item);
|
||||||
|
int newPositionIndex = _indexOfKey(newPosition);
|
||||||
|
|
||||||
|
final draggedItem = renderItems[draggingIndex];
|
||||||
|
|
||||||
|
final List<HomeTopItems> reorderedItems = reorderEnumItems(draggingIndex, newPositionIndex);
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
renderItems.removeAt(draggingIndex);
|
||||||
|
renderItems.insert(newPositionIndex, draggedItem);
|
||||||
|
homeTopItemsList = reorderedItems;
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _reorderDone(Key item) {
|
||||||
|
renderItems[_indexOfKey(item)];
|
||||||
|
setState(() => persistHomeTopItemsList = homeTopItemsList);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<HomeTopItems> reorderEnumItems(int oldIndex, int newIndex) {
|
||||||
|
final List<HomeTopItems> list = [...homeTopItemsList];
|
||||||
|
final HomeTopItems item = list.removeAt(oldIndex);
|
||||||
|
list.insert(newIndex, item);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
final appConfigProvider = Provider.of<AppConfigProvider>(context, listen: false);
|
||||||
|
homeTopItemsList = appConfigProvider.homeTopItemsOrder;
|
||||||
|
persistHomeTopItemsList = appConfigProvider.homeTopItemsOrder;
|
||||||
|
renderItems = appConfigProvider.homeTopItemsOrder.asMap().entries.map(
|
||||||
|
(e) => ItemData(
|
||||||
|
key: ValueKey(e.key),
|
||||||
|
title: e.value,
|
||||||
|
)
|
||||||
|
).toList();
|
||||||
|
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final appConfigProvider = Provider.of<AppConfigProvider>(context);
|
||||||
|
|
||||||
|
Widget tile(HomeTopItems title) {
|
||||||
|
switch (title) {
|
||||||
|
case HomeTopItems.queriedDomains:
|
||||||
|
return CustomListTile(
|
||||||
|
title: AppLocalizations.of(context)!.topQueriedDomains,
|
||||||
|
icon: Icons.install_desktop_outlined,
|
||||||
|
padding: const EdgeInsets.all(16)
|
||||||
|
);
|
||||||
|
|
||||||
|
case HomeTopItems.blockedDomains:
|
||||||
|
return CustomListTile(
|
||||||
|
title: AppLocalizations.of(context)!.topBlockedDomains,
|
||||||
|
icon: Icons.block_rounded,
|
||||||
|
padding: const EdgeInsets.all(16)
|
||||||
|
);
|
||||||
|
|
||||||
|
case HomeTopItems.recurrentClients:
|
||||||
|
return CustomListTile(
|
||||||
|
title: AppLocalizations.of(context)!.topClients,
|
||||||
|
icon: Icons.smartphone_rounded,
|
||||||
|
padding: const EdgeInsets.all(16)
|
||||||
|
);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return const SizedBox();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> onWillPopScope() async {
|
||||||
|
if (!listEquals(appConfigProvider.homeTopItemsOrder, persistHomeTopItemsList)) {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (dialogContext) => AlertDialog(
|
||||||
|
title: Text(AppLocalizations.of(context)!.discardChanges),
|
||||||
|
content: Text(AppLocalizations.of(context)!.discardChangesDescription),
|
||||||
|
actions: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pop(dialogContext);
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
child: Text(AppLocalizations.of(context)!.confirm)
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.pop(dialogContext),
|
||||||
|
child: Text(AppLocalizations.of(context)!.cancel)
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return WillPopScope(
|
||||||
|
onWillPop: onWillPopScope,
|
||||||
|
child: Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(AppLocalizations.of(context)!.topItemsOrder),
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
onPressed: !listEquals(appConfigProvider.homeTopItemsOrder, persistHomeTopItemsList)
|
||||||
|
? () => appConfigProvider.setHomeTopItemsOrder(homeTopItemsList)
|
||||||
|
: 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_library.ReorderableList(
|
||||||
|
onReorder: _reorderCallback,
|
||||||
|
onReorderDone: _reorderDone,
|
||||||
|
child: ListView.builder(
|
||||||
|
itemBuilder: (context, index) => reorderable_list_library.ReorderableItem(
|
||||||
|
key: renderItems[index].key,
|
||||||
|
childBuilder: (context, state) => Item(
|
||||||
|
tileWidget: tile(renderItems[index].title),
|
||||||
|
isFirst: index == 0,
|
||||||
|
isLast: index == renderItems.length - 1,
|
||||||
|
state: state
|
||||||
|
),
|
||||||
|
),
|
||||||
|
itemCount: renderItems.length,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Item extends StatelessWidget {
|
||||||
|
final Widget tileWidget;
|
||||||
|
final bool isFirst;
|
||||||
|
final bool isLast;
|
||||||
|
final reorderable_list_library.ReorderableItemState state;
|
||||||
|
|
||||||
|
const Item({
|
||||||
|
Key? key,
|
||||||
|
required this.tileWidget,
|
||||||
|
required this.isFirst,
|
||||||
|
required this.isLast,
|
||||||
|
required this.state,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
BoxDecoration decoration;
|
||||||
|
|
||||||
|
if (
|
||||||
|
state == reorderable_list_library.ReorderableItemState.dragProxy ||
|
||||||
|
state == reorderable_list_library.ReorderableItemState.dragProxyFinished
|
||||||
|
) {
|
||||||
|
decoration = BoxDecoration(
|
||||||
|
color: Theme.of(context).colorScheme.surface.withOpacity(0.7)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bool placeholder = state == reorderable_list_library.ReorderableItemState.placeholder;
|
||||||
|
decoration = BoxDecoration(
|
||||||
|
border: Border(
|
||||||
|
top: isFirst && !placeholder ? BorderSide(
|
||||||
|
width: 1,
|
||||||
|
color: Theme.of(context).colorScheme.primary.withOpacity(0.1)
|
||||||
|
) : BorderSide.none,
|
||||||
|
bottom: isLast && placeholder ? BorderSide.none : BorderSide(
|
||||||
|
width: 1,
|
||||||
|
color: Theme.of(context).colorScheme.primary.withOpacity(0.1)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return reorderable_list_library.DelayedReorderableListener(
|
||||||
|
child: Container(
|
||||||
|
decoration: decoration,
|
||||||
|
child: SafeArea(
|
||||||
|
top: false,
|
||||||
|
bottom: false,
|
||||||
|
child: Opacity(
|
||||||
|
opacity: state == reorderable_list_library.ReorderableItemState.placeholder ? 0.0 : 1.0,
|
||||||
|
child: IntrinsicHeight(
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: <Widget>[
|
||||||
|
Expanded(
|
||||||
|
child: tileWidget
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,7 +17,7 @@ import 'package:adguard_home_manager/screens/settings/dns/dns.dart';
|
||||||
import 'package:adguard_home_manager/screens/settings/dns_rewrites/dns_rewrites.dart';
|
import 'package:adguard_home_manager/screens/settings/dns_rewrites/dns_rewrites.dart';
|
||||||
import 'package:adguard_home_manager/screens/servers/servers.dart';
|
import 'package:adguard_home_manager/screens/servers/servers.dart';
|
||||||
import 'package:adguard_home_manager/screens/settings/advanced_setings.dart';
|
import 'package:adguard_home_manager/screens/settings/advanced_setings.dart';
|
||||||
import 'package:adguard_home_manager/screens/settings/general_settings.dart';
|
import 'package:adguard_home_manager/screens/settings/general_settings/general_settings.dart';
|
||||||
|
|
||||||
import 'package:adguard_home_manager/widgets/custom_settings_tile.dart';
|
import 'package:adguard_home_manager/widgets/custom_settings_tile.dart';
|
||||||
import 'package:adguard_home_manager/widgets/section_label.dart';
|
import 'package:adguard_home_manager/widgets/section_label.dart';
|
||||||
|
|
|
@ -267,6 +267,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.2"
|
version: "2.3.2"
|
||||||
|
flutter_reorderable_list:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_reorderable_list
|
||||||
|
sha256: "0400ef34fa00b7cac69f71efc92d7e49727f425bc1080180ebe70bf47618afe0"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.1"
|
||||||
flutter_split_view:
|
flutter_split_view:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -72,6 +72,7 @@ dependencies:
|
||||||
async: ^2.10.0
|
async: ^2.10.0
|
||||||
sentry_flutter: ^7.9.0
|
sentry_flutter: ^7.9.0
|
||||||
flutter_dotenv: ^5.0.2
|
flutter_dotenv: ^5.0.2
|
||||||
|
flutter_reorderable_list: ^1.3.1
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
Loading…
Add table
Reference in a new issue