mirror of
https://github.com/JGeek00/adguard-home-manager.git
synced 2025-05-31 11:52:16 +00:00
New tab list filters
This commit is contained in:
parent
1508c49536
commit
b599debb3c
8 changed files with 376 additions and 402 deletions
|
@ -1,11 +1,13 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:adguard_home_manager/constants/enums.dart';
|
||||
|
||||
FilteringData filteringFromJson(String str) => FilteringData.fromJson(json.decode(str));
|
||||
|
||||
String filteringToJson(FilteringData data) => json.encode(data.toJson());
|
||||
|
||||
class Filtering {
|
||||
int loadStatus = 0;
|
||||
LoadStatus loadStatus = LoadStatus.loading;
|
||||
FilteringData? data;
|
||||
|
||||
Filtering({
|
||||
|
|
|
@ -32,7 +32,7 @@ class ServersProvider with ChangeNotifier {
|
|||
);
|
||||
|
||||
final Filtering _filtering = Filtering(
|
||||
loadStatus: 0, // 0 = loading, 1 = loaded, 2 = error
|
||||
loadStatus: LoadStatus.loading,
|
||||
data: null
|
||||
);
|
||||
|
||||
|
@ -153,7 +153,7 @@ class ServersProvider with ChangeNotifier {
|
|||
notifyListeners();
|
||||
}
|
||||
|
||||
void setFilteringLoadStatus(int loadStatus, bool notify) {
|
||||
void setFilteringLoadStatus(LoadStatus loadStatus, bool notify) {
|
||||
_filtering.loadStatus = loadStatus;
|
||||
if (notify == true) {
|
||||
notifyListeners();
|
||||
|
|
|
@ -7,8 +7,10 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
|||
|
||||
import 'package:adguard_home_manager/screens/filters/fab.dart';
|
||||
import 'package:adguard_home_manager/screens/filters/remove_custom_rule_modal.dart';
|
||||
import 'package:adguard_home_manager/widgets/tab_content_list.dart';
|
||||
|
||||
import 'package:adguard_home_manager/functions/snackbar.dart';
|
||||
import 'package:adguard_home_manager/constants/enums.dart';
|
||||
import 'package:adguard_home_manager/models/filtering.dart';
|
||||
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
||||
import 'package:adguard_home_manager/services/http_requests.dart';
|
||||
|
@ -16,10 +18,10 @@ import 'package:adguard_home_manager/providers/servers_provider.dart';
|
|||
import 'package:adguard_home_manager/classes/process_modal.dart';
|
||||
|
||||
class CustomRulesList extends StatefulWidget {
|
||||
final int loadStatus;
|
||||
final LoadStatus loadStatus;
|
||||
final ScrollController scrollController;
|
||||
final List<String> data;
|
||||
final void Function() fetchData;
|
||||
final Future<void> Function() fetchData;
|
||||
|
||||
const CustomRulesList({
|
||||
Key? key,
|
||||
|
@ -149,120 +151,98 @@ class _CustomRulesListState extends State<CustomRulesList> {
|
|||
}
|
||||
}
|
||||
|
||||
switch (widget.loadStatus) {
|
||||
case 0:
|
||||
return SizedBox(
|
||||
width: double.maxFinite,
|
||||
height: MediaQuery.of(context).size.height-171,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
const CircularProgressIndicator(),
|
||||
const SizedBox(height: 30),
|
||||
Text(
|
||||
AppLocalizations.of(context)!.loadingFilters,
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
case 1:
|
||||
return Stack(
|
||||
return CustomTabContentList(
|
||||
loadingGenerator: () => SizedBox(
|
||||
width: double.maxFinite,
|
||||
height: MediaQuery.of(context).size.height-171,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
if (widget.data.isNotEmpty) ListView.builder(
|
||||
padding: const EdgeInsets.only(top: 0),
|
||||
itemCount: widget.data.length,
|
||||
itemBuilder: (context, index) => ListTile(
|
||||
title: Text(
|
||||
widget.data[index],
|
||||
style: TextStyle(
|
||||
color: checkIfComment(widget.data[index]) == true
|
||||
? Theme.of(context).colorScheme.onSurface.withOpacity(0.6)
|
||||
: Theme.of(context).colorScheme.onSurface,
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
subtitle: generateSubtitle(widget.data[index]),
|
||||
trailing: IconButton(
|
||||
onPressed: () => openRemoveCustomRuleModal(widget.data[index]),
|
||||
icon: const Icon(Icons.delete)
|
||||
),
|
||||
)
|
||||
),
|
||||
if (widget.data.isEmpty) Container(
|
||||
width: double.maxFinite,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Flexible(
|
||||
child: Text(
|
||||
AppLocalizations.of(context)!.noCustomFilters,
|
||||
textAlign: TextAlign.center,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
TextButton.icon(
|
||||
onPressed: widget.fetchData,
|
||||
icon: const Icon(Icons.refresh_rounded),
|
||||
label: Text(AppLocalizations.of(context)!.refresh),
|
||||
)
|
||||
],
|
||||
const CircularProgressIndicator(),
|
||||
const SizedBox(height: 30),
|
||||
Text(
|
||||
AppLocalizations.of(context)!.loadingFilters,
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
AnimatedPositioned(
|
||||
duration: const Duration(milliseconds: 100),
|
||||
curve: Curves.easeInOut,
|
||||
bottom: isVisible ?
|
||||
appConfigProvider.showingSnackbar
|
||||
? 70 : 20
|
||||
: -70,
|
||||
right: 20,
|
||||
child: const FiltersFab(
|
||||
type: 'custom_rule',
|
||||
)
|
||||
)
|
||||
],
|
||||
);
|
||||
|
||||
case 2:
|
||||
return SizedBox(
|
||||
width: double.maxFinite,
|
||||
height: MediaQuery.of(context).size.height-171,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.error,
|
||||
color: Colors.red,
|
||||
size: 50,
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
Text(
|
||||
AppLocalizations.of(context)!.filtersNotLoaded,
|
||||
),
|
||||
),
|
||||
itemsCount: widget.data.length,
|
||||
contentWidget: (index) => ListTile(
|
||||
title: Text(
|
||||
widget.data[index],
|
||||
style: TextStyle(
|
||||
color: checkIfComment(widget.data[index]) == true
|
||||
? Theme.of(context).colorScheme.onSurface.withOpacity(0.6)
|
||||
: Theme.of(context).colorScheme.onSurface,
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
subtitle: generateSubtitle(widget.data[index]),
|
||||
trailing: IconButton(
|
||||
onPressed: () => openRemoveCustomRuleModal(widget.data[index]),
|
||||
icon: const Icon(Icons.delete)
|
||||
),
|
||||
),
|
||||
noData: Container(
|
||||
width: double.maxFinite,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Flexible(
|
||||
child: Text(
|
||||
AppLocalizations.of(context)!.noCustomFilters,
|
||||
textAlign: TextAlign.center,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
fontSize: 24,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
default:
|
||||
return const SizedBox();
|
||||
}
|
||||
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
TextButton.icon(
|
||||
onPressed: widget.fetchData,
|
||||
icon: const Icon(Icons.refresh_rounded),
|
||||
label: Text(AppLocalizations.of(context)!.refresh),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
errorGenerator: () => SizedBox(
|
||||
width: double.maxFinite,
|
||||
height: MediaQuery.of(context).size.height-171,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.error,
|
||||
color: Colors.red,
|
||||
size: 50,
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
Text(
|
||||
AppLocalizations.of(context)!.filtersNotLoaded,
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
loadStatus: widget.loadStatus,
|
||||
onRefresh: widget.fetchData,
|
||||
fab: const FiltersFab(
|
||||
type: 'custom_rule',
|
||||
),
|
||||
fabVisible: isVisible,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:bottom_sheet/bottom_sheet.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
import 'package:adguard_home_manager/screens/filters/add_custom_rule.dart';
|
||||
|
@ -12,6 +11,7 @@ import 'package:adguard_home_manager/functions/snackbar.dart';
|
|||
import 'package:adguard_home_manager/services/http_requests.dart';
|
||||
import 'package:adguard_home_manager/classes/process_modal.dart';
|
||||
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
||||
import 'package:adguard_home_manager/constants/enums.dart';
|
||||
import 'package:adguard_home_manager/models/filtering.dart';
|
||||
import 'package:adguard_home_manager/providers/servers_provider.dart';
|
||||
|
||||
|
@ -91,11 +91,11 @@ class FiltersFab extends StatelessWidget {
|
|||
|
||||
if (result2['result'] == 'success') {
|
||||
serversProvider.setFilteringData(result2['data']);
|
||||
serversProvider.setFilteringLoadStatus(1, true);
|
||||
serversProvider.setFilteringLoadStatus(LoadStatus.loaded, true);
|
||||
}
|
||||
else {
|
||||
appConfigProvider.addLog(result2['log']);
|
||||
serversProvider.setFilteringLoadStatus(2, true);
|
||||
serversProvider.setFilteringLoadStatus(LoadStatus.error, true);
|
||||
}
|
||||
|
||||
processModal.close();
|
||||
|
|
|
@ -13,6 +13,7 @@ import 'package:adguard_home_manager/screens/filters/update_interval_lists_modal
|
|||
import 'package:adguard_home_manager/functions/snackbar.dart';
|
||||
import 'package:adguard_home_manager/classes/process_modal.dart';
|
||||
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
||||
import 'package:adguard_home_manager/constants/enums.dart';
|
||||
import 'package:adguard_home_manager/services/http_requests.dart';
|
||||
import 'package:adguard_home_manager/models/clients.dart';
|
||||
import 'package:adguard_home_manager/providers/servers_provider.dart';
|
||||
|
@ -51,18 +52,18 @@ class _FiltersWidgetState extends State<FiltersWidget> with TickerProviderStateM
|
|||
final ScrollController scrollController = ScrollController();
|
||||
|
||||
Future fetchFilters() async {
|
||||
widget.serversProvider.setFilteringLoadStatus(0, false);
|
||||
widget.serversProvider.setFilteringLoadStatus(LoadStatus.loading, false);
|
||||
|
||||
final result = await getFiltering(server: widget.serversProvider.selectedServer!);
|
||||
|
||||
if (mounted) {
|
||||
if (result['result'] == 'success') {
|
||||
widget.serversProvider.setFilteringData(result['data']);
|
||||
widget.serversProvider.setFilteringLoadStatus(1, false);
|
||||
widget.serversProvider.setFilteringLoadStatus(LoadStatus.loaded, false);
|
||||
}
|
||||
else {
|
||||
widget.appConfigProvider.addLog(result['log']);
|
||||
widget.serversProvider.setFilteringLoadStatus(2, false);
|
||||
widget.serversProvider.setFilteringLoadStatus(LoadStatus.error, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -228,123 +229,120 @@ class _FiltersWidgetState extends State<FiltersWidget> with TickerProviderStateM
|
|||
return [
|
||||
SliverOverlapAbsorber(
|
||||
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
||||
sliver: SliverSafeArea(
|
||||
top: false,
|
||||
sliver: SliverAppBar(
|
||||
title: Text(AppLocalizations.of(context)!.filters),
|
||||
pinned: true,
|
||||
floating: true,
|
||||
forceElevated: innerBoxIsScrolled,
|
||||
centerTitle: false,
|
||||
actions: serversProvider.filtering.loadStatus == 1 ? [
|
||||
IconButton(
|
||||
onPressed: enableDisableFiltering,
|
||||
tooltip: serversProvider.filtering.data!.enabled == true
|
||||
? AppLocalizations.of(context)!.disableFiltering
|
||||
: AppLocalizations.of(context)!.enableFiltering,
|
||||
icon: Stack(
|
||||
children: [
|
||||
const Icon(Icons.power_settings_new_rounded),
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
child: Stack(
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
color: Colors.white
|
||||
),
|
||||
child: Icon(
|
||||
serversProvider.filtering.data!.enabled == true
|
||||
? Icons.check_circle_rounded
|
||||
: Icons.cancel,
|
||||
size: 12,
|
||||
color: serversProvider.filtering.data!.enabled == true
|
||||
? appConfigProvider.useThemeColorForStatus == true
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: Colors.green
|
||||
: appConfigProvider.useThemeColorForStatus == true
|
||||
? Colors.grey
|
||||
: Colors.red
|
||||
),
|
||||
sliver: SliverAppBar(
|
||||
title: Text(AppLocalizations.of(context)!.filters),
|
||||
pinned: true,
|
||||
floating: true,
|
||||
forceElevated: innerBoxIsScrolled,
|
||||
centerTitle: false,
|
||||
actions: serversProvider.filtering.loadStatus == LoadStatus.loaded ? [
|
||||
IconButton(
|
||||
onPressed: enableDisableFiltering,
|
||||
tooltip: serversProvider.filtering.data!.enabled == true
|
||||
? AppLocalizations.of(context)!.disableFiltering
|
||||
: AppLocalizations.of(context)!.enableFiltering,
|
||||
icon: Stack(
|
||||
children: [
|
||||
const Icon(Icons.power_settings_new_rounded),
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
child: Stack(
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
color: Colors.white
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (context) => UpdateIntervalListsModal(
|
||||
interval: serversProvider.filtering.data!.interval,
|
||||
onChange: setUpdateFrequency
|
||||
child: Icon(
|
||||
serversProvider.filtering.data!.enabled == true
|
||||
? Icons.check_circle_rounded
|
||||
: Icons.cancel,
|
||||
size: 12,
|
||||
color: serversProvider.filtering.data!.enabled == true
|
||||
? appConfigProvider.useThemeColorForStatus == true
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: Colors.green
|
||||
: appConfigProvider.useThemeColorForStatus == true
|
||||
? Colors.grey
|
||||
: Colors.red
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
backgroundColor: Colors.transparent,
|
||||
isScrollControlled: true
|
||||
);
|
||||
},
|
||||
icon: const Icon(Icons.update_rounded)
|
||||
),
|
||||
PopupMenuButton(
|
||||
itemBuilder: (context) => [
|
||||
PopupMenuItem(
|
||||
onTap: fetchUpdateLists,
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.sync_rounded),
|
||||
const SizedBox(width: 10),
|
||||
Text(AppLocalizations.of(context)!.updateLists)
|
||||
],
|
||||
)
|
||||
)
|
||||
],
|
||||
)
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (context) => UpdateIntervalListsModal(
|
||||
interval: serversProvider.filtering.data!.interval,
|
||||
onChange: setUpdateFrequency
|
||||
),
|
||||
PopupMenuItem(
|
||||
onTap: openBlockedServicesModal,
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.block),
|
||||
const SizedBox(width: 10),
|
||||
Text(AppLocalizations.of(context)!.blockedServices)
|
||||
],
|
||||
)
|
||||
),
|
||||
PopupMenuItem(
|
||||
onTap: showCheckHostModal,
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.shield_rounded),
|
||||
const SizedBox(width: 10),
|
||||
Text(AppLocalizations.of(context)!.checkHostFiltered)
|
||||
],
|
||||
)
|
||||
),
|
||||
]
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
] : [],
|
||||
bottom: TabBar(
|
||||
controller: tabController,
|
||||
isScrollable: false,
|
||||
unselectedLabelColor: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
tabs: [
|
||||
Tab(
|
||||
icon: const Icon(Icons.verified_user_rounded),
|
||||
text: AppLocalizations.of(context)!.whitelists,
|
||||
backgroundColor: Colors.transparent,
|
||||
isScrollControlled: true
|
||||
);
|
||||
},
|
||||
icon: const Icon(Icons.update_rounded)
|
||||
),
|
||||
PopupMenuButton(
|
||||
itemBuilder: (context) => [
|
||||
PopupMenuItem(
|
||||
onTap: fetchUpdateLists,
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.sync_rounded),
|
||||
const SizedBox(width: 10),
|
||||
Text(AppLocalizations.of(context)!.updateLists)
|
||||
],
|
||||
)
|
||||
),
|
||||
Tab(
|
||||
icon: const Icon(Icons.gpp_bad_rounded),
|
||||
text: AppLocalizations.of(context)!.blacklist,
|
||||
PopupMenuItem(
|
||||
onTap: openBlockedServicesModal,
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.block),
|
||||
const SizedBox(width: 10),
|
||||
Text(AppLocalizations.of(context)!.blockedServices)
|
||||
],
|
||||
)
|
||||
),
|
||||
Tab(
|
||||
icon: const Icon(Icons.shield_rounded),
|
||||
text: AppLocalizations.of(context)!.customRules,
|
||||
PopupMenuItem(
|
||||
onTap: showCheckHostModal,
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.shield_rounded),
|
||||
const SizedBox(width: 10),
|
||||
Text(AppLocalizations.of(context)!.checkHostFiltered)
|
||||
],
|
||||
)
|
||||
),
|
||||
]
|
||||
)
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
] : [],
|
||||
bottom: TabBar(
|
||||
controller: tabController,
|
||||
isScrollable: false,
|
||||
unselectedLabelColor: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
tabs: [
|
||||
Tab(
|
||||
icon: const Icon(Icons.verified_user_rounded),
|
||||
text: AppLocalizations.of(context)!.whitelists,
|
||||
),
|
||||
Tab(
|
||||
icon: const Icon(Icons.gpp_bad_rounded),
|
||||
text: AppLocalizations.of(context)!.blacklist,
|
||||
),
|
||||
Tab(
|
||||
icon: const Icon(Icons.shield_rounded),
|
||||
text: AppLocalizations.of(context)!.customRules,
|
||||
),
|
||||
]
|
||||
)
|
||||
),
|
||||
)
|
||||
];
|
||||
|
@ -352,37 +350,28 @@ class _FiltersWidgetState extends State<FiltersWidget> with TickerProviderStateM
|
|||
body: TabBarView(
|
||||
controller: tabController,
|
||||
children: [
|
||||
RefreshIndicator(
|
||||
onRefresh: fetchFilters,
|
||||
child: FiltersList(
|
||||
loadStatus: serversProvider.filtering.loadStatus,
|
||||
scrollController: scrollController,
|
||||
type: 'whitelist',
|
||||
data: serversProvider.filtering.loadStatus == 1
|
||||
? serversProvider.filtering.data!.whitelistFilters : [],
|
||||
fetchData: fetchFilters,
|
||||
)
|
||||
FiltersList(
|
||||
loadStatus: serversProvider.filtering.loadStatus,
|
||||
scrollController: scrollController,
|
||||
type: 'whitelist',
|
||||
data: serversProvider.filtering.loadStatus == LoadStatus.loaded
|
||||
? serversProvider.filtering.data!.whitelistFilters : [],
|
||||
fetchData: fetchFilters,
|
||||
),
|
||||
RefreshIndicator(
|
||||
onRefresh: fetchFilters,
|
||||
child: FiltersList(
|
||||
loadStatus: serversProvider.filtering.loadStatus,
|
||||
scrollController: scrollController,
|
||||
type: 'blacklist',
|
||||
data: serversProvider.filtering.loadStatus == 1
|
||||
? serversProvider.filtering.data!.filters : [],
|
||||
fetchData: fetchFilters,
|
||||
)
|
||||
FiltersList(
|
||||
loadStatus: serversProvider.filtering.loadStatus,
|
||||
scrollController: scrollController,
|
||||
type: 'blacklist',
|
||||
data: serversProvider.filtering.loadStatus == LoadStatus.loaded
|
||||
? serversProvider.filtering.data!.filters : [],
|
||||
fetchData: fetchFilters,
|
||||
),
|
||||
RefreshIndicator(
|
||||
onRefresh: fetchFilters,
|
||||
child: CustomRulesList(
|
||||
loadStatus: serversProvider.filtering.loadStatus,
|
||||
scrollController: scrollController,
|
||||
data: serversProvider.filtering.loadStatus == 1
|
||||
? serversProvider.filtering.data!.userRules : [],
|
||||
fetchData: fetchFilters,
|
||||
)
|
||||
CustomRulesList(
|
||||
loadStatus: serversProvider.filtering.loadStatus,
|
||||
scrollController: scrollController,
|
||||
data: serversProvider.filtering.loadStatus == LoadStatus.loaded
|
||||
? serversProvider.filtering.data!.userRules : [],
|
||||
fetchData: fetchFilters,
|
||||
),
|
||||
]
|
||||
)
|
||||
|
|
|
@ -10,16 +10,18 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
|||
import 'package:adguard_home_manager/screens/filters/fab.dart';
|
||||
import 'package:adguard_home_manager/screens/filters/list_details_screen.dart';
|
||||
import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
|
||||
import 'package:adguard_home_manager/widgets/tab_content_list.dart';
|
||||
|
||||
import 'package:adguard_home_manager/constants/enums.dart';
|
||||
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
||||
import 'package:adguard_home_manager/functions/number_format.dart';
|
||||
import 'package:adguard_home_manager/models/filtering.dart';
|
||||
|
||||
class FiltersList extends StatefulWidget {
|
||||
final int loadStatus;
|
||||
final LoadStatus loadStatus;
|
||||
final ScrollController scrollController;
|
||||
final List<Filter> data;
|
||||
final void Function() fetchData;
|
||||
final Future<void> Function() fetchData;
|
||||
final String type;
|
||||
|
||||
const FiltersList({
|
||||
|
@ -74,122 +76,100 @@ class _FiltersListState extends State<FiltersList> {
|
|||
);
|
||||
}
|
||||
|
||||
switch (widget.loadStatus) {
|
||||
case 0:
|
||||
return SizedBox(
|
||||
width: double.maxFinite,
|
||||
height: MediaQuery.of(context).size.height-171,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
const CircularProgressIndicator(),
|
||||
const SizedBox(height: 30),
|
||||
Text(
|
||||
AppLocalizations.of(context)!.loadingFilters,
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
case 1:
|
||||
return Stack(
|
||||
return CustomTabContentList(
|
||||
loadingGenerator: () => SizedBox(
|
||||
width: double.maxFinite,
|
||||
height: MediaQuery.of(context).size.height-171,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
if (widget.data.isNotEmpty) ListView.builder(
|
||||
padding: const EdgeInsets.only(top: 0),
|
||||
itemCount: widget.data.length,
|
||||
itemBuilder: (context, index) => CustomListTile(
|
||||
title: widget.data[index].name,
|
||||
subtitle: "${intFormat(widget.data[index].rulesCount, Platform.localeName)} ${AppLocalizations.of(context)!.enabledRules}",
|
||||
trailing: Icon(
|
||||
widget.data[index].enabled == true
|
||||
? Icons.check_circle_rounded
|
||||
: Icons.cancel,
|
||||
color: widget.data[index].enabled == true
|
||||
? appConfigProvider.useThemeColorForStatus == true
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: Colors.green
|
||||
: appConfigProvider.useThemeColorForStatus == true
|
||||
? Colors.grey
|
||||
: Colors.red
|
||||
),
|
||||
onTap: () => openDetailsModal(widget.data[index]),
|
||||
const CircularProgressIndicator(),
|
||||
const SizedBox(height: 30),
|
||||
Text(
|
||||
AppLocalizations.of(context)!.loadingFilters,
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
if (widget.data.isEmpty) if (widget.data.isEmpty) Container(
|
||||
width: double.maxFinite,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Flexible(
|
||||
child: Text(
|
||||
widget.type == 'blacklist'
|
||||
? AppLocalizations.of(context)!.noBlackLists
|
||||
: AppLocalizations.of(context)!.noWhiteLists,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
TextButton.icon(
|
||||
onPressed: widget.fetchData,
|
||||
icon: const Icon(Icons.refresh_rounded),
|
||||
label: Text(AppLocalizations.of(context)!.refresh),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
AnimatedPositioned(
|
||||
duration: const Duration(milliseconds: 100),
|
||||
curve: Curves.easeInOut,
|
||||
bottom: isVisible ?
|
||||
appConfigProvider.showingSnackbar
|
||||
? 70 : 20
|
||||
: -70,
|
||||
right: 20,
|
||||
child: FiltersFab(
|
||||
type: widget.type
|
||||
)
|
||||
)
|
||||
],
|
||||
);
|
||||
|
||||
case 2:
|
||||
return SizedBox(
|
||||
width: double.maxFinite,
|
||||
height: MediaQuery.of(context).size.height-171,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.error,
|
||||
color: Colors.red,
|
||||
size: 50,
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
Text(
|
||||
AppLocalizations.of(context)!.filtersNotLoaded,
|
||||
),
|
||||
),
|
||||
itemsCount: widget.data.length,
|
||||
contentWidget: (index) => CustomListTile(
|
||||
title: widget.data[index].name,
|
||||
subtitle: "${intFormat(widget.data[index].rulesCount, Platform.localeName)} ${AppLocalizations.of(context)!.enabledRules}",
|
||||
trailing: Icon(
|
||||
widget.data[index].enabled == true
|
||||
? Icons.check_circle_rounded
|
||||
: Icons.cancel,
|
||||
color: widget.data[index].enabled == true
|
||||
? appConfigProvider.useThemeColorForStatus == true
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: Colors.green
|
||||
: appConfigProvider.useThemeColorForStatus == true
|
||||
? Colors.grey
|
||||
: Colors.red
|
||||
),
|
||||
onTap: () => openDetailsModal(widget.data[index]),
|
||||
),
|
||||
noData: Container(
|
||||
width: double.maxFinite,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Flexible(
|
||||
child: Text(
|
||||
widget.type == 'blacklist'
|
||||
? AppLocalizations.of(context)!.noBlackLists
|
||||
: AppLocalizations.of(context)!.noWhiteLists,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
fontSize: 24,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
default:
|
||||
return const SizedBox();
|
||||
}
|
||||
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
TextButton.icon(
|
||||
onPressed: widget.fetchData,
|
||||
icon: const Icon(Icons.refresh_rounded),
|
||||
label: Text(AppLocalizations.of(context)!.refresh),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
errorGenerator: () => SizedBox(
|
||||
width: double.maxFinite,
|
||||
height: MediaQuery.of(context).size.height-171,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.error,
|
||||
color: Colors.red,
|
||||
size: 50,
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
Text(
|
||||
AppLocalizations.of(context)!.filtersNotLoaded,
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
loadStatus: widget.loadStatus,
|
||||
onRefresh: widget.fetchData,
|
||||
fab: FiltersFab(
|
||||
type: widget.type,
|
||||
),
|
||||
fabVisible: isVisible,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@ import 'package:adguard_home_manager/screens/filters/delete_list_modal.dart';
|
|||
|
||||
import 'package:adguard_home_manager/functions/format_time.dart';
|
||||
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
||||
import 'package:adguard_home_manager/constants/enums.dart';
|
||||
import 'package:adguard_home_manager/functions/snackbar.dart';
|
||||
import 'package:adguard_home_manager/classes/process_modal.dart';
|
||||
import 'package:adguard_home_manager/providers/servers_provider.dart';
|
||||
|
@ -92,11 +93,11 @@ class _ListDetailsScreenState extends State<ListDetailsScreen> {
|
|||
|
||||
if (result2['result'] == 'success') {
|
||||
serversProvider.setFilteringData(result2['data']);
|
||||
serversProvider.setFilteringLoadStatus(1, true);
|
||||
serversProvider.setFilteringLoadStatus(LoadStatus.loaded, true);
|
||||
}
|
||||
else {
|
||||
appConfigProvider.addLog(result2['log']);
|
||||
serversProvider.setFilteringLoadStatus(2, true);
|
||||
serversProvider.setFilteringLoadStatus(LoadStatus.error, true);
|
||||
}
|
||||
|
||||
setState(() => enabled = newStatus);
|
||||
|
@ -139,11 +140,11 @@ class _ListDetailsScreenState extends State<ListDetailsScreen> {
|
|||
|
||||
if (result2['result'] == 'success') {
|
||||
serversProvider.setFilteringData(result2['data']);
|
||||
serversProvider.setFilteringLoadStatus(1, true);
|
||||
serversProvider.setFilteringLoadStatus(LoadStatus.loaded, true);
|
||||
}
|
||||
else {
|
||||
appConfigProvider.addLog(result2['log']);
|
||||
serversProvider.setFilteringLoadStatus(2, true);
|
||||
serversProvider.setFilteringLoadStatus(LoadStatus.error, true);
|
||||
}
|
||||
|
||||
processModal.close();
|
||||
|
@ -184,11 +185,11 @@ class _ListDetailsScreenState extends State<ListDetailsScreen> {
|
|||
|
||||
if (result2['result'] == 'success') {
|
||||
serversProvider.setFilteringData(result2['data']);
|
||||
serversProvider.setFilteringLoadStatus(1, true);
|
||||
serversProvider.setFilteringLoadStatus(LoadStatus.loaded, true);
|
||||
}
|
||||
else {
|
||||
appConfigProvider.addLog(result2['log']);
|
||||
serversProvider.setFilteringLoadStatus(2, true);
|
||||
serversProvider.setFilteringLoadStatus(LoadStatus.loading, true);
|
||||
}
|
||||
|
||||
processModal.close();
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
||||
import 'package:adguard_home_manager/constants/enums.dart';
|
||||
|
||||
class CustomTabContentList extends StatelessWidget {
|
||||
|
@ -10,6 +12,8 @@ class CustomTabContentList extends StatelessWidget {
|
|||
final Widget Function() errorGenerator;
|
||||
final LoadStatus loadStatus;
|
||||
final Future<void> Function() onRefresh;
|
||||
final Widget? fab;
|
||||
final bool? fabVisible;
|
||||
|
||||
const CustomTabContentList({
|
||||
Key? key,
|
||||
|
@ -20,10 +24,14 @@ class CustomTabContentList extends StatelessWidget {
|
|||
required this.errorGenerator,
|
||||
required this.loadStatus,
|
||||
required this.onRefresh,
|
||||
this.fab,
|
||||
this.fabVisible
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final appConfigProvider = Provider.of<AppConfigProvider>(context);
|
||||
|
||||
switch (loadStatus) {
|
||||
case LoadStatus.loading:
|
||||
return SafeArea(
|
||||
|
@ -48,33 +56,47 @@ class CustomTabContentList extends StatelessWidget {
|
|||
|
||||
|
||||
case LoadStatus.loaded:
|
||||
return SafeArea(
|
||||
top: false,
|
||||
bottom: false,
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
return RefreshIndicator(
|
||||
onRefresh: onRefresh,
|
||||
edgeOffset: 95,
|
||||
child: CustomScrollView(
|
||||
slivers: <Widget>[
|
||||
SliverOverlapInjector(
|
||||
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
||||
return Stack(
|
||||
children: [
|
||||
SafeArea(
|
||||
top: false,
|
||||
bottom: false,
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
return RefreshIndicator(
|
||||
onRefresh: onRefresh,
|
||||
edgeOffset: 95,
|
||||
child: CustomScrollView(
|
||||
slivers: <Widget>[
|
||||
SliverOverlapInjector(
|
||||
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
||||
),
|
||||
if (itemsCount > 0) SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) => contentWidget(index),
|
||||
childCount: itemsCount
|
||||
),
|
||||
),
|
||||
if (itemsCount == 0) SliverFillRemaining(
|
||||
child: noData,
|
||||
)
|
||||
],
|
||||
),
|
||||
if (itemsCount > 0) SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) => contentWidget(index),
|
||||
childCount: itemsCount
|
||||
),
|
||||
),
|
||||
if (itemsCount == 0) SliverFillRemaining(
|
||||
child: noData,
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
if (fab != null) AnimatedPositioned(
|
||||
duration: const Duration(milliseconds: 100),
|
||||
curve: Curves.easeInOut,
|
||||
bottom: fabVisible != null && fabVisible == true ?
|
||||
appConfigProvider.showingSnackbar
|
||||
? 70 : 20
|
||||
: -70,
|
||||
right: 20,
|
||||
child: fab!
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
case LoadStatus.error:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue