diff --git a/lib/functions/compare_versions.dart b/lib/functions/compare_versions.dart index 58c9542..5e3a81b 100644 --- a/lib/functions/compare_versions.dart +++ b/lib/functions/compare_versions.dart @@ -44,4 +44,66 @@ bool compareBetaVersions({ else { return false; } +} + +bool versionIsGreater({ + required String currentVersion, + required String referenceVersion, + String? referenceVersionBeta +}) { + final current = currentVersion.replaceAll('v', ''); + final reference = referenceVersion.replaceAll('v', ''); + final referenceBeta = referenceVersionBeta?.replaceAll('v', ''); + + if (current.contains('beta')) { + if (referenceBeta != null) { + final currentSplit = current.split('-')[0].split('.').map((e) => int.parse(e)).toList(); + final newSplit = referenceBeta.split('-')[0].split('.').map((e) => int.parse(e)).toList(); + + final currentBeta = int.parse(current.split('-')[1].replaceAll('b.', '')); + final newBeta = int.parse(referenceBeta.split('-')[1].replaceAll('b.', '')); + + if (newSplit[0] == currentSplit[0] && newSplit[1] == currentSplit[1] && newSplit[2] == currentSplit[2] && newBeta == currentBeta) { + return true; + } + else if (newSplit[0] > currentSplit[0]) { + return true; + } + else if (newSplit[1] > currentSplit[1]) { + return true; + } + else if (newSplit[2] > currentSplit[2]) { + return true; + } + else if (newBeta > currentBeta) { + return true; + } + else { + return false; + } + } + else { + return false; + } + } + else { + final currentSplit = current.split('.').map((e) => int.parse(e)).toList(); + final newSplit = reference.split('.').map((e) => int.parse(e)).toList(); + + if (newSplit[0] == currentSplit[0] && newSplit[1] == currentSplit[1] && newSplit[2] == currentSplit[2]) { + return true; + } + else if (newSplit[0] > currentSplit[0]) { + return true; + } + else if (newSplit[1] > currentSplit[1]) { + return true; + } + else if (newSplit[2] > currentSplit[2]) { + return true; + } + else { + return false; + } + } } \ No newline at end of file diff --git a/lib/models/server_status.dart b/lib/models/server_status.dart index 8d76613..2e364fb 100644 --- a/lib/models/server_status.dart +++ b/lib/models/server_status.dart @@ -23,6 +23,7 @@ class ServerStatusData { bool safeSearchEnabled; bool safeBrowsingEnabled; bool parentalControlEnabled; + final String serverVersion; ServerStatusData({ required this.stats, @@ -34,21 +35,23 @@ class ServerStatusData { required this.filteringEnabled, required this.safeSearchEnabled, required this.safeBrowsingEnabled, - required this.parentalControlEnabled + required this.parentalControlEnabled, + required this.serverVersion }); factory ServerStatusData.fromJson(Map json) => ServerStatusData( stats: DnsStatistics.fromJson(json['stats']), clients: json["clients"] != null ? List.from(json["clients"].map((x) => Client.fromJson(x))) : [], - generalEnabled: json['generalEnabled']['protection_enabled'], - timeGeneralDisabled: json['generalEnabled']['protection_disabled_duration'] ?? 0, - disabledUntil: json['generalEnabled']['protection_disabled_duration'] > 0 - ? generateTimeDeadline(json['generalEnabled']['protection_disabled_duration']) + generalEnabled: json['status']['protection_enabled'], + timeGeneralDisabled: json['status']['protection_disabled_duration'] ?? 0, + disabledUntil: json['status']['protection_disabled_duration'] > 0 + ? generateTimeDeadline(json['status']['protection_disabled_duration']) : null , filteringStatus: FilteringStatus.fromJson(json['filtering']), filteringEnabled: json['filtering']['enabled'], safeSearchEnabled: json['safeSearchEnabled']['enabled'], safeBrowsingEnabled: json['safeBrowsingEnabled']['enabled'], - parentalControlEnabled: json['parentalControlEnabled']['enabled'] + parentalControlEnabled: json['parentalControlEnabled']['enabled'], + serverVersion: json['status']['version'] ); } \ No newline at end of file diff --git a/lib/providers/servers_provider.dart b/lib/providers/servers_provider.dart index 471bcaf..fcb0131 100644 --- a/lib/providers/servers_provider.dart +++ b/lib/providers/servers_provider.dart @@ -366,6 +366,25 @@ class ServersProvider with ChangeNotifier { return result['log']; } + case 'general_legacy': + _protectionsManagementProcess.add('general'); + notifyListeners(); + + final result = await updateGeneralProtectionLegacy(server, newStatus); + + _protectionsManagementProcess = _protectionsManagementProcess.where((e) => e != 'general').toList(); + + if (result['result'] == 'success') { + _serverStatus.data!.generalEnabled = newStatus; + notifyListeners(); + return null; + } + else { + notifyListeners(); + return result['log']; + } + + case 'filtering': _protectionsManagementProcess.add('filtering'); notifyListeners(); diff --git a/lib/screens/home/management_modal.dart b/lib/screens/home/management_modal.dart index aaef255..f562b57 100644 --- a/lib/screens/home/management_modal.dart +++ b/lib/screens/home/management_modal.dart @@ -3,12 +3,13 @@ import 'dart:async'; import 'dart:io'; -import 'package:adguard_home_manager/functions/time_server_disabled.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:expandable/expandable.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:adguard_home_manager/functions/compare_versions.dart'; +import 'package:adguard_home_manager/functions/time_server_disabled.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/services/http_requests.dart'; import 'package:adguard_home_manager/providers/servers_provider.dart'; @@ -146,23 +147,25 @@ class _ManagementModalState extends State with SingleTickerProv } Widget mainSwitch() { - Widget topRow() { + Widget topRow(bool legacyMode) { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ - RotationTransition( - turns: animation, - child: Icon( - Icons.keyboard_arrow_down_rounded, - size: 26, - color: serversProvider.serverStatus.data!.generalEnabled == true - ? Theme.of(context).colorScheme.onSurfaceVariant - : Colors.grey, + if (legacyMode == true) ...[ + RotationTransition( + turns: animation, + child: Icon( + Icons.keyboard_arrow_down_rounded, + size: 26, + color: serversProvider.serverStatus.data!.generalEnabled == true + ? Theme.of(context).colorScheme.onSurfaceVariant + : Colors.grey, + ), ), - ), - const SizedBox(width: 8), + const SizedBox(width: 8), + ], Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -185,8 +188,15 @@ class _ManagementModalState extends State with SingleTickerProv Switch( value: serversProvider.serverStatus.data!.generalEnabled, onChanged: serversProvider.protectionsManagementProcess.contains('general') == false - ? (value) => updateBlocking(value: value, filter: 'general') - : null, + ? (value) { + if (value == false) { + expandableController.toggle(); + } + updateBlocking( + value: value, + filter: legacyMode == true ? 'general_legacy' : 'general' + ); + } : null, activeColor: Theme.of(context).colorScheme.primary, ) ] @@ -241,43 +251,71 @@ class _ManagementModalState extends State with SingleTickerProv return Padding( padding: const EdgeInsets.symmetric(horizontal: 24), - child: ExpandableNotifier( - controller: expandableController, - child: Material( - color: Colors.transparent, - borderRadius: BorderRadius.circular(28), - child: InkWell( - onTap: serversProvider.serverStatus.data!.generalEnabled == true - ? () => expandableController.toggle() - : null, - borderRadius: BorderRadius.circular(28), - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: 20, - vertical: 12 - ), - decoration: BoxDecoration( + child: versionIsGreater( + currentVersion: serversProvider.serverStatus.data!.serverVersion, + referenceVersion: 'v0.107.28', + referenceVersionBeta: 'v0.108.0-b.33' + ) == true + ? ExpandableNotifier( + controller: expandableController, + child: Material( + color: Colors.transparent, + borderRadius: BorderRadius.circular(28), + child: InkWell( + onTap: serversProvider.serverStatus.data!.generalEnabled == true + ? () => expandableController.toggle() + : null, borderRadius: BorderRadius.circular(28), - color: Theme.of(context).primaryColor.withOpacity(0.1) - ), - child: Expandable( - theme: const ExpandableThemeData( - animationDuration: Duration(milliseconds: 200), - fadeCurve: Curves.ease + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 20, + vertical: 12 + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(28), + color: Theme.of(context).primaryColor.withOpacity(0.1) + ), + child: Expandable( + theme: const ExpandableThemeData( + animationDuration: Duration(milliseconds: 200), + fadeCurve: Curves.ease + ), + collapsed: topRow(true), + expanded: Column( + children: [ + topRow(true), + bottomRow(), + const SizedBox(height: 8) + ], + ) + ), ), - collapsed: topRow(), - expanded: Column( - children: [ - topRow(), - bottomRow(), - const SizedBox(height: 8) - ], - ) + ), + ) + ) + : Material( + color: Colors.transparent, + borderRadius: BorderRadius.circular(28), + child: InkWell( + onTap: serversProvider.protectionsManagementProcess.contains('general') == false + ? () => updateBlocking( + value: !serversProvider.serverStatus.data!.generalEnabled, + filter: 'general_legacy' + ) : null, + borderRadius: BorderRadius.circular(28), + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 20, + vertical: 12 + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(28), + color: Theme.of(context).primaryColor.withOpacity(0.1) + ), + child: topRow(false) ), ), - ), - ) - ), + ) ); } diff --git a/lib/services/http_requests.dart b/lib/services/http_requests.dart index b1b3d25..a9ddfa7 100644 --- a/lib/services/http_requests.dart +++ b/lib/services/http_requests.dart @@ -280,7 +280,7 @@ Future getServerStatus(Server server) async { final Map mappedData = { 'stats': jsonDecode(result[0]['body']), 'clients': jsonDecode(result[6]['body'])['clients'], - 'generalEnabled': jsonDecode(result[1]['body']), + 'status': jsonDecode(result[1]['body']), 'filtering': jsonDecode(result[2]['body']), 'safeSearchEnabled': jsonDecode(result[3]['body']), 'safeBrowsingEnabled': jsonDecode(result[4]['body']), @@ -503,6 +503,39 @@ Future updateGeneralProtection({ } } +Future updateGeneralProtectionLegacy(Server server, bool enable) async { + final result = await apiRequest( + urlPath: '/dns_config', + method: 'post', + server: server, + body: { + 'protection_enabled': enable + }, + type: 'general_protection' + ); + + if (result['hasResponse'] == true) { + if (result['statusCode'] == 200) { + return {'result': 'success'}; + } + else { + return { + 'result': 'error', + 'log': AppLog( + type: 'general_protection', + dateTime: DateTime.now(), + message: 'error_code_not_expected', + statusCode: result['statusCode'].toString(), + resBody: result['body'] + ) + }; + } + } + else { + return result; + } +} + Future getClients(Server server) async { final result = await Future.wait([ apiRequest(server: server, method: 'get', urlPath: '/clients', type: 'get_clients'),