New tab list filters

This commit is contained in:
Juan Gilsanz Polo 2023-04-06 18:27:57 +02:00
parent 1508c49536
commit b599debb3c
8 changed files with 376 additions and 402 deletions

View file

@ -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({

View file

@ -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();

View file

@ -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,
);
}
}

View file

@ -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();

View file

@ -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,
),
]
)

View file

@ -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,
);
}
}

View file

@ -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();

View file

@ -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: