Added new safesearch settings

This commit is contained in:
Juan Gilsanz Polo 2023-04-14 01:40:40 +02:00
parent 9e400f7efa
commit 0921576c19
9 changed files with 516 additions and 12 deletions

View file

@ -603,5 +603,8 @@
"minutes": "{time} minutes",
"hour": "{time} hour",
"hours": "{time} hours",
"remainingTime": "Remaining time"
"remainingTime": "Remaining time",
"safeSearchSettings": "Safe search settings",
"loadingSafeSearchSettings": "Loading safe search settings...",
"safeSearchSettingsNotLoaded": "Error when loading safe search settings."
}

View file

@ -603,5 +603,8 @@
"minutes": "{time} minutos",
"hour": "{time} hora",
"hours": "{time} horas",
"remainingTime": "Tiempo restante"
"remainingTime": "Tiempo restante",
"safeSearchSettings": "Configuración de búsqueda segura",
"loadingSafeSearchSettings": "Cargando configuración de búsqueda segura...",
"safeSearchSettingsNotLoaded": "Error al cargar la configuración de búsqueda segura."
}

View file

@ -0,0 +1,51 @@
import 'package:adguard_home_manager/constants/enums.dart';
class SafeSearch {
LoadStatus loadStatus = LoadStatus.loading;
SafeSearchData? data;
SafeSearch({
required this.loadStatus,
this.data
});
}
class SafeSearchData {
final bool enabled;
final bool bing;
final bool duckduckgo;
final bool google;
final bool pixabay;
final bool yandex;
final bool youtube;
SafeSearchData({
required this.enabled,
required this.bing,
required this.duckduckgo,
required this.google,
required this.pixabay,
required this.yandex,
required this.youtube,
});
factory SafeSearchData.fromJson(Map<String, dynamic> json) => SafeSearchData(
enabled: json["enabled"],
bing: json["bing"],
duckduckgo: json["duckduckgo"],
google: json["google"],
pixabay: json["pixabay"],
yandex: json["yandex"],
youtube: json["youtube"],
);
Map<String, dynamic> toJson() => {
"enabled": enabled,
"bing": bing,
"duckduckgo": duckduckgo,
"google": google,
"pixabay": pixabay,
"yandex": yandex,
"youtube": youtube,
};
}

View file

@ -24,6 +24,12 @@ class ServerStatusData {
bool safeBrowsingEnabled;
bool parentalControlEnabled;
final String serverVersion;
bool safeSeachBing;
bool safeSearchGoogle;
bool safeSearchDuckduckgo;
bool safeSearchPixabay;
bool safeSearchYandex;
bool safeSearchYoutube;
ServerStatusData({
required this.stats,
@ -36,7 +42,13 @@ class ServerStatusData {
required this.safeSearchEnabled,
required this.safeBrowsingEnabled,
required this.parentalControlEnabled,
required this.serverVersion
required this.serverVersion,
required this.safeSeachBing,
required this.safeSearchGoogle,
required this.safeSearchDuckduckgo,
required this.safeSearchPixabay,
required this.safeSearchYandex,
required this.safeSearchYoutube
});
factory ServerStatusData.fromJson(Map<String, dynamic> json) => ServerStatusData(
@ -49,9 +61,15 @@ class ServerStatusData {
: null ,
filteringStatus: FilteringStatus.fromJson(json['filtering']),
filteringEnabled: json['filtering']['enabled'],
safeSearchEnabled: json['safeSearchEnabled']['enabled'],
safeSearchEnabled: json['safeSearch']['enabled'],
safeBrowsingEnabled: json['safeBrowsingEnabled']['enabled'],
parentalControlEnabled: json['parentalControlEnabled']['enabled'],
serverVersion: json['status']['version']
serverVersion: json['status']['version'],
safeSeachBing: json['safeSearch']['bing'],
safeSearchDuckduckgo: json['safeSearch']['duckduckgo'],
safeSearchGoogle: json['safeSearch']['google'],
safeSearchPixabay: json['safeSearch']['pixabay'],
safeSearchYandex: json['safeSearch']['yandex'],
safeSearchYoutube: json['safeSearch']['youtube'],
);
}

View file

@ -247,7 +247,7 @@ class ServersProvider with ChangeNotifier {
_updateAvailable.data = data;
notifyListeners();
}
Future<dynamic> createServer(Server server) async {
final saved = await saveServerIntoDb(server);
if (saved == null) {

View file

@ -0,0 +1,326 @@
// ignore_for_file: use_build_context_synchronously
import 'package:flutter/material.dart';
import 'package:provider/provider.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/classes/process_modal.dart';
import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/models/server_status.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
class SafeSearchSettingsScreen extends StatelessWidget {
const SafeSearchSettingsScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
return SafeSearchSettingsScreenWidget(
serversProvider: serversProvider,
appConfigProvider: appConfigProvider,
);
}
}
class SafeSearchSettingsScreenWidget extends StatefulWidget {
final ServersProvider serversProvider;
final AppConfigProvider appConfigProvider;
const SafeSearchSettingsScreenWidget({
Key? key,
required this.serversProvider,
required this.appConfigProvider
}) : super(key: key);
@override
State<SafeSearchSettingsScreenWidget> createState() => _SafeSearchSettingsScreenWidgetState();
}
class _SafeSearchSettingsScreenWidgetState extends State<SafeSearchSettingsScreenWidget> {
bool generalEnabled = false;
bool bingEnabled = false;
bool duckduckgoEnabled = false;
bool googleEnabled = false;
bool pixabayEnabled = false;
bool yandexEnabled = false;
bool youtubeEnabled = false;
Future requestSafeSearchSettings() async {
final result = await getServerStatus(widget.serversProvider.selectedServer!);
if (mounted) {
if (result['result'] == 'success') {
widget.serversProvider.setServerStatusData(result['data']);
widget.serversProvider.setServerStatusLoad(1);
setState(() {
generalEnabled = result['data'].safeSearchEnabled;
bingEnabled = result['data'].safeSeachBing;
duckduckgoEnabled = result['data'].safeSearchDuckduckgo;
googleEnabled = result['data'].safeSearchGoogle;
pixabayEnabled = result['data'].safeSearchPixabay;
yandexEnabled = result['data'].safeSearchYandex;
youtubeEnabled = result['data'].safeSearchYoutube;
});
}
else {
widget.appConfigProvider.addLog(result['log']);
widget.serversProvider.setServerStatusLoad(2);
}
}
}
@override
void initState() {
if (widget.serversProvider.serverStatus.loadStatus == 0) {
requestSafeSearchSettings();
}
else if (widget.serversProvider.serverStatus.loadStatus == 1) {
generalEnabled = widget.serversProvider.serverStatus.data!.safeSearchEnabled;
bingEnabled = widget.serversProvider.serverStatus.data!.safeSeachBing;
duckduckgoEnabled = widget.serversProvider.serverStatus.data!.safeSearchDuckduckgo;
googleEnabled = widget.serversProvider.serverStatus.data!.safeSearchGoogle;
pixabayEnabled = widget.serversProvider.serverStatus.data!.safeSearchPixabay;
yandexEnabled = widget.serversProvider.serverStatus.data!.safeSearchYandex;
youtubeEnabled = widget.serversProvider.serverStatus.data!.safeSearchYoutube;
}
super.initState();
}
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
void saveConfig() async {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.savingSettings);
final result = await updateSafeSearchSettings(
server: serversProvider.selectedServer!,
body: {
"enabled": generalEnabled,
"bing": bingEnabled,
"duckduckgo": duckduckgoEnabled,
"google": googleEnabled,
"pixabay": pixabayEnabled,
"yandex": yandexEnabled,
"youtube": youtubeEnabled
}
);
processModal.close();
if (result['result'] == 'success') {
ServerStatusData data = serversProvider.serverStatus.data!;
data.safeSearchEnabled = generalEnabled;
data.safeSeachBing = bingEnabled;
data.safeSearchDuckduckgo = duckduckgoEnabled;
data.safeSearchGoogle = googleEnabled;
data.safeSearchPixabay = pixabayEnabled;
data.safeSearchYandex = yandexEnabled;
data.safeSearchYoutube = youtubeEnabled;
serversProvider.setServerStatusData(data);
showSnacbkar(
context: context,
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.settingsUpdatedSuccessfully,
color: Colors.green,
labelColor: Colors.white
);
}
else {
appConfigProvider.addLog(result['log']);
showSnacbkar(
context: context,
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.settingsNotSaved,
color: Colors.red,
labelColor: Colors.white
);
}
}
Widget body() {
switch (serversProvider.serverStatus.loadStatus) {
case 0:
return SizedBox(
width: double.maxFinite,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const CircularProgressIndicator(),
const SizedBox(height: 30),
Text(
AppLocalizations.of(context)!.loadingSafeSearchSettings,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 22,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
)
],
),
);
case 1:
return RefreshIndicator(
onRefresh: requestSafeSearchSettings,
child: ListView(
children: [
Padding(
padding: const EdgeInsets.only(
top: 16,
left: 16,
right: 16,
bottom: 8
),
child: Material(
color: Colors.transparent,
borderRadius: BorderRadius.circular(28),
child: InkWell(
borderRadius: BorderRadius.circular(28),
onTap: () => setState(() => generalEnabled = !generalEnabled),
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12
),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primary.withOpacity(0.1),
borderRadius: BorderRadius.circular(28)
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
AppLocalizations.of(context)!.enableSafeSearch,
style: const TextStyle(
fontSize: 18
),
),
Switch(
value: generalEnabled,
onChanged: (value) => setState(() => generalEnabled = value)
)
],
),
),
),
),
),
CustomSwitchListTile(
value: bingEnabled,
onChanged: (value) => setState(() => bingEnabled = value),
title: "Bing",
padding: const EdgeInsets.only(
top: 8, left: 40, right: 40, bottom: 8
),
disabled: !generalEnabled,
),
CustomSwitchListTile(
value: duckduckgoEnabled,
onChanged: (value) => setState(() => duckduckgoEnabled = value),
title: "DuckDuckGo",
padding: const EdgeInsets.only(
top: 8, left: 40, right: 40, bottom: 8
),
disabled: !generalEnabled,
),
CustomSwitchListTile(
value: googleEnabled,
onChanged: (value) => setState(() => googleEnabled = value),
title: "Google",
padding: const EdgeInsets.only(
top: 8, left: 40, right: 40, bottom: 8
),
disabled: !generalEnabled,
),
CustomSwitchListTile(
value: pixabayEnabled,
onChanged: (value) => setState(() => pixabayEnabled = value),
title: "Pixabay",
padding: const EdgeInsets.only(
top: 8, left: 40, right: 40, bottom: 8
),
disabled: !generalEnabled,
),
CustomSwitchListTile(
value: yandexEnabled,
onChanged: (value) => setState(() => yandexEnabled = value),
title: "Yandex",
padding: const EdgeInsets.only(
top: 8, left: 40, right: 40, bottom: 8
),
disabled: !generalEnabled,
),
CustomSwitchListTile(
value: youtubeEnabled,
onChanged: (value) => setState(() => youtubeEnabled = value),
title: "YouTube",
padding: const EdgeInsets.only(
top: 8, left: 40, right: 40, bottom: 8
),
disabled: !generalEnabled,
),
],
),
);
case 2:
return SizedBox(
width: double.maxFinite,
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)!.safeSearchSettingsNotLoaded,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 22,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
)
],
),
);
default:
return const SizedBox();
}
}
return Scaffold(
appBar: AppBar(
title: Text(AppLocalizations.of(context)!.safeSearchSettings),
centerTitle: false,
actions: [
IconButton(
onPressed: serversProvider.serverStatus.loadStatus == 1
? () => saveConfig()
: null,
icon: const Icon(Icons.save_rounded),
tooltip: AppLocalizations.of(context)!.save,
),
const SizedBox(width: 8)
],
),
body: body(),
);
}
}

View file

@ -8,6 +8,7 @@ import 'package:adguard_home_manager/screens/settings/encryption/encryption.dart
import 'package:adguard_home_manager/screens/settings/access_settings/access_settings.dart';
import 'package:adguard_home_manager/screens/settings/customization/customization.dart';
import 'package:adguard_home_manager/screens/settings/dhcp/dhcp.dart';
import 'package:adguard_home_manager/screens/settings/safe_search_settings.dart';
import 'package:adguard_home_manager/widgets/section_label.dart';
import 'package:adguard_home_manager/screens/settings/update_server/update.dart';
import 'package:adguard_home_manager/screens/settings/dns/dns.dart';
@ -20,6 +21,7 @@ import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
import 'package:adguard_home_manager/constants/strings.dart';
import 'package:adguard_home_manager/functions/open_url.dart';
import 'package:adguard_home_manager/functions/compare_versions.dart';
import 'package:adguard_home_manager/constants/urls.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart';
@ -49,6 +51,22 @@ class Settings extends StatelessWidget {
children: [
if (serversProvider.selectedServer != null) ...[
SectionLabel(label: AppLocalizations.of(context)!.serverSettings),
if (versionIsGreater(
currentVersion: serversProvider.serverStatus.data!.serverVersion,
referenceVersion: 'v0.107.28',
referenceVersionBeta: 'v0.108.0-b.33'
) == true) CustomListTile(
icon: Icons.search_rounded,
title: AppLocalizations.of(context)!.safeSearch,
subtitle: AppLocalizations.of(context)!.safeSearchSettings,
onTap: () => {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const SafeSearchSettingsScreen()
)
)
},
),
CustomListTile(
icon: Icons.lock_rounded,
title: AppLocalizations.of(context)!.accessSettings,

View file

@ -14,13 +14,13 @@ import 'package:adguard_home_manager/models/logs.dart';
import 'package:adguard_home_manager/models/filtering_status.dart';
import 'package:adguard_home_manager/models/app_log.dart';
import 'package:adguard_home_manager/models/rewrite_rules.dart';
import 'package:adguard_home_manager/models/safe_search.dart';
import 'package:adguard_home_manager/models/server_info.dart';
import 'package:adguard_home_manager/models/server_status.dart';
import 'package:adguard_home_manager/models/clients.dart';
import 'package:adguard_home_manager/models/clients_allowed_blocked.dart';
import 'package:adguard_home_manager/models/server.dart';
import 'package:adguard_home_manager/constants/urls.dart';
import 'package:adguard_home_manager/models/update_available.dart';
Future<Map<String, dynamic>> apiRequest({
@ -61,8 +61,23 @@ Future<Map<String, dynamic>> apiRequest({
};
}
}
else if (method == 'post') {
HttpClientRequest request = await httpClient.postUrl(Uri.parse(connectionString));
else if (method == 'post' || method == 'put') {
HttpClientRequest? request;
if (method == 'post') {
request = await httpClient.postUrl(Uri.parse(connectionString));
}
else if (method == 'put') {
request = await httpClient.putUrl(Uri.parse(connectionString));
}
else {
return {
'hasResponse': false,
'error': true,
'statusCode': null,
'body': 'Invalid method [selected $method]'
};
}
if (server.authToken != null) {
request.headers.set('Authorization', 'Basic ${server.authToken}');
}
@ -282,7 +297,7 @@ Future getServerStatus(Server server) async {
'clients': jsonDecode(result[6]['body'])['clients'],
'status': jsonDecode(result[1]['body']),
'filtering': jsonDecode(result[2]['body']),
'safeSearchEnabled': jsonDecode(result[3]['body']),
'safeSearch': jsonDecode(result[3]['body']),
'safeBrowsingEnabled': jsonDecode(result[4]['body']),
'parentalControlEnabled': jsonDecode(result[5]['body']),
};
@ -2169,4 +2184,73 @@ Future requestUpdateServer({
else {
return result;
}
}
Future getSafeSearchSettings({
required Server server,
}) async {
final result = await apiRequest(
urlPath: '/safesearch/status',
method: 'get',
server: server,
type: 'safesearch_settings'
);
if (result['hasResponse'] == true) {
if (result['statusCode'] == 200) {
return {
'result': 'success',
'data': SafeSearchData.fromJson(jsonDecode(result['body']))
};
}
else {
return {
'result': 'error',
'log': AppLog(
type: 'safesearch_settings',
dateTime: DateTime.now(),
message: 'error_code_not_expected',
statusCode: result['statusCode'].toString(),
resBody: result['body'],
)
};
}
}
else {
return result;
}
}
Future updateSafeSearchSettings({
required Server server,
required Map<String, dynamic> body
}) async {
final result = await apiRequest(
urlPath: '/safesearch/settings',
method: 'put',
server: server,
type: 'safesearch_settings',
body: body
);
if (result['hasResponse'] == true) {
if (result['statusCode'] == 200) {
return { 'result': 'success' };
}
else {
return {
'result': 'error',
'log': AppLog(
type: 'safesearch_settings',
dateTime: DateTime.now(),
message: 'error_code_not_expected',
statusCode: result['statusCode'].toString(),
resBody: result['body'],
)
};
}
}
else {
return result;
}
}

View file

@ -6,6 +6,7 @@ class CustomSwitchListTile extends StatelessWidget {
final String title;
final String? subtitle;
final bool? disabled;
final EdgeInsets? padding;
const CustomSwitchListTile({
Key? key,
@ -14,6 +15,7 @@ class CustomSwitchListTile extends StatelessWidget {
required this.title,
this.disabled,
this.subtitle,
this.padding
}) : super(key: key);
@override
@ -25,7 +27,7 @@ class CustomSwitchListTile extends StatelessWidget {
? null
: () => onChanged(!value),
child: Padding(
padding: const EdgeInsets.only(
padding: padding ?? const EdgeInsets.only(
top: 12, left: 16, right: 18, bottom: 16
),
child: Row(
@ -68,7 +70,6 @@ class CustomSwitchListTile extends StatelessWidget {
onChanged: disabled != null && disabled == true
? null
: onChanged,
activeColor: Theme.of(context).colorScheme.primary,
)
],
),