Compare commits

...
16 changed files with 197 additions and 13 deletions

No files matched your search

@@ -1,12 +0,0 @@
import 'package:get/get.dart';
import '../controllers/app_controller.dart';
class AppBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut<AppController>(
() => AppController(),
);
}
}
@@ -1,10 +1,12 @@
import 'package:get/get.dart'; import 'package:get/get.dart';
import '../../../../util/network_monitor.dart';
import '../controllers/root_controller.dart'; import '../controllers/root_controller.dart';
class RootBinding extends Bindings { class RootBinding extends Bindings {
@override @override
void dependencies() { void dependencies() {
Get.lazyPut<RootController>(() => RootController(), fenix: true); Get.lazyPut<RootController>(() => RootController(), fenix: true);
Get.put<NetworkMonitor>(NetworkMonitor(), permanent: true);
} }
} }
@@ -1,15 +1,19 @@
import 'package:get/get.dart'; import 'package:get/get.dart';
import '../../../../database/database.dart';
import '../../../../util/updater.dart'; import '../../../../util/updater.dart';
class SettingController extends GetxController { class SettingController extends GetxController {
final tapStatues = <String, bool>{}.obs; final tapStatues = <String, bool>{}.obs;
final latestVersion = Rxn<VersionInfo>(); final latestVersion = Rxn<VersionInfo>();
final networkAutoControl = false.obs;
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
fetchLatestVersion(); fetchLatestVersion();
// Initialize network auto control setting
networkAutoControl.value = Database.instance.getNetworkAutoControl();
} }
// set all tap status to false // set all tap status to false
@@ -27,4 +31,10 @@ class SettingController extends GetxController {
void fetchLatestVersion() async { void fetchLatestVersion() async {
latestVersion.value = await checkUpdate(); latestVersion.value = await checkUpdate();
} }
// update network auto control setting
void updateNetworkAutoControl(bool value) {
networkAutoControl.value = value;
Database.instance.saveNetworkAutoControl(value);
}
} }
@@ -11,6 +11,7 @@ import 'package:launch_at_startup/launch_at_startup.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import '../../../../api/model/downloader_config.dart'; import '../../../../api/model/downloader_config.dart';
import '../../../../database/database.dart';
import '../../../../i18n/message.dart'; import '../../../../i18n/message.dart';
import '../../../../util/input_formatter.dart'; import '../../../../util/input_formatter.dart';
import '../../../../util/locale_manager.dart'; import '../../../../util/locale_manager.dart';
@@ -543,6 +544,24 @@ class SettingView extends GetView<SettingController> {
); );
} }
// Network auto control setting (mobile only)
buildNetworkAutoControl() {
if (!Platform.isAndroid && !Platform.isIOS) {
return null;
}
return Obx(() => ListTile(
title: Text('networkAutoControl'.tr),
subtitle: Text('networkAutoControlTip'.tr),
trailing: Switch(
value: controller.networkAutoControl.value,
onChanged: (bool value) {
controller.updateNetworkAutoControl(value);
},
),
));
}
// advanced config proxy items start // advanced config proxy items start
final proxy = downloaderCfg.value.proxy; final proxy = downloaderCfg.value.proxy;
final buildProxy = _buildConfigItem( final buildProxy = _buildConfigItem(
@@ -985,7 +1004,10 @@ class SettingView extends GetView<SettingController> {
Text('network'.tr), Text('network'.tr),
Card( Card(
child: Column( child: Column(
children: _addDivider([buildProxy()]), children: _addDivider([
buildNetworkAutoControl(),
buildProxy(),
].where((e) => e != null).cast<Widget>().toList()),
)), )),
const Text('API'), const Text('API'),
Card( Card(
+9
View File
@@ -10,6 +10,7 @@ const String _windowState = 'windowState';
const String _bookmark = 'bookmark'; const String _bookmark = 'bookmark';
const String _createHistory = 'createHistory'; const String _createHistory = 'createHistory';
const String _webToken = 'webToken'; const String _webToken = 'webToken';
const String _networkAutoControl = 'networkAutoControl';
class Database { class Database {
static final Database _instance = Database._internal(); static final Database _instance = Database._internal();
@@ -109,4 +110,12 @@ class Database {
void clearCreateHistory() { void clearCreateHistory() {
clear(_createHistory); clear(_createHistory);
} }
void saveNetworkAutoControl(bool enabled) {
save<bool>(_networkAutoControl, enabled);
}
bool getNetworkAutoControl() {
return get<bool>(_networkAutoControl, (json) => json as bool) ?? false;
}
} }
+2
View File
@@ -125,5 +125,7 @@ const enUS = {
'login_failed': 'Login failed, please check your username and password', 'login_failed': 'Login failed, please check your username and password',
'login_failed_network': 'login_failed_network':
'Login failed, please check your network connection', 'Login failed, please check your network connection',
'networkAutoControl': 'Network Auto Control',
'networkAutoControlTip': 'Automatically pause downloads when switching from WiFi to mobile data, and resume when switching back to WiFi',
}, },
}; };
+2
View File
@@ -104,5 +104,7 @@ const esES = {
'taskUrl': 'URL de la Tarea', 'taskUrl': 'URL de la Tarea',
'downloadPath': 'Ruta de Descarga', 'downloadPath': 'Ruta de Descarga',
'skipVerifyCert': 'Omitir Verificación de Certificado', 'skipVerifyCert': 'Omitir Verificación de Certificado',
'networkAutoControl': 'Control Automático de Red',
'networkAutoControlTip': 'Pausar automáticamente las descargas al cambiar de WiFi a datos móviles y reanudar al volver a WiFi',
}, },
}; };
+2
View File
@@ -93,5 +93,7 @@ const frFR = {
'browserExtension': 'Extension du navigateur', 'browserExtension': 'Extension du navigateur',
'launchAtStartup': 'Lancer au démarrage', 'launchAtStartup': 'Lancer au démarrage',
'skipVerifyCert': 'Bypass Verifikasi Sertifikat', 'skipVerifyCert': 'Bypass Verifikasi Sertifikat',
'networkAutoControl': 'Contrôle automatique du réseau',
'networkAutoControlTip': 'Mettre automatiquement en pause les téléchargements lors du passage du WiFi aux données mobiles et reprendre lors du retour au WiFi',
}, },
}; };
+2
View File
@@ -97,5 +97,7 @@ const itIT = {
'browserExtension': 'Estensione del browser', 'browserExtension': 'Estensione del browser',
'launchAtStartup': "Lancia all'avvio", 'launchAtStartup': "Lancia all'avvio",
'skipVerifyCert': 'Salta la verifica del certificato', 'skipVerifyCert': 'Salta la verifica del certificato',
'networkAutoControl': 'Controllo automatico della rete',
'networkAutoControlTip': 'Mette automaticamente in pausa i download quando si passa dal WiFi ai dati mobili e riprende quando si torna al WiFi',
}, },
}; };
+2
View File
@@ -63,5 +63,7 @@ const jaJP = {
'thanksDesc': 'Gopeedコミュニティの建設に協力してくださったすべての貢献者の方々に感謝します!', 'thanksDesc': 'Gopeedコミュニティの建設に協力してくださったすべての貢献者の方々に感謝します!',
'browserExtension': 'ブラウザ拡張機能', 'browserExtension': 'ブラウザ拡張機能',
'skipVerifyCert': '証明書の検証をスキップ', 'skipVerifyCert': '証明書の検証をスキップ',
'networkAutoControl': 'ネットワーク自動制御',
'networkAutoControlTip': 'WiFiからモバイルデータに切り替わった時に自動的にダウンロードを一時停止し、WiFiに戻った時に自動的に再開します',
} }
}; };
+2
View File
@@ -119,5 +119,7 @@ const ruRU = {
'fileSelectedSize': 'Размер: ', 'fileSelectedSize': 'Размер: ',
'httpHeaderName': 'Название заголовка HTTP', 'httpHeaderName': 'Название заголовка HTTP',
'httpHeaderValue': 'Значение заголовка HTTP', 'httpHeaderValue': 'Значение заголовка HTTP',
'networkAutoControl': 'Автоматическое управление сетью',
'networkAutoControlTip': 'Автоматически приостанавливать загрузки при переключении с WiFi на мобильные данные и возобновлять при возврате к WiFi',
} }
}; };
+2
View File
@@ -90,5 +90,7 @@ const viVN = {
'Cảm ơn tất cả những người đóng góp đã giúp xây dựng và phát triển cộng đồng Gopeed!', 'Cảm ơn tất cả những người đóng góp đã giúp xây dựng và phát triển cộng đồng Gopeed!',
'browserExtension': 'Tiện ích mở rộng trình duyệt', 'browserExtension': 'Tiện ích mở rộng trình duyệt',
'skipVerifyCert': 'Bỏ qua xác thực chứng chỉ', 'skipVerifyCert': 'Bỏ qua xác thực chứng chỉ',
'networkAutoControl': 'Điều khiển mạng tự động',
'networkAutoControlTip': 'Tự động tạm dừng tải xuống khi chuyển từ WiFi sang dữ liệu di động và tiếp tục khi quay lại WiFi',
}, },
}; };
+2
View File
@@ -122,5 +122,7 @@ const zhCN = {
'login_success': '登录成功', 'login_success': '登录成功',
'login_failed': '登录失败,请检查用户名和密码', 'login_failed': '登录失败,请检查用户名和密码',
'login_failed_network': '登录失败,请检查网络连接', 'login_failed_network': '登录失败,请检查网络连接',
'networkAutoControl': '网络状态自动控制',
'networkAutoControlTip': '当网络从WiFi切换到移动数据时自动暂停下载,切换回WiFi时自动恢复下载',
} }
}; };
+2
View File
@@ -116,5 +116,7 @@ const zhTW = {
'fileSelectedSize': '大小:', 'fileSelectedSize': '大小:',
'httpHeaderName': '標頭名稱', 'httpHeaderName': '標頭名稱',
'httpHeaderValue': '標頭值', 'httpHeaderValue': '標頭值',
'networkAutoControl': '網路狀態自動控制',
'networkAutoControlTip': '當網路從WiFi切換到流動數據時自動暫停下載,切換回WiFi時自動恢復下載',
} }
}; };
+134
View File
@@ -0,0 +1,134 @@
import 'dart:async';
import 'dart:io';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:get/get.dart';
import '../api/api.dart';
import '../database/database.dart';
import '../util/log_util.dart';
enum NetworkType { wifi, mobile, other, none }
class NetworkMonitor extends GetxService {
static NetworkMonitor get to => Get.find();
late final Connectivity _connectivity;
late StreamSubscription<List<ConnectivityResult>> _connectivitySubscription;
final _isWiFiConnected = false.obs;
bool get isWiFiConnected => _isWiFiConnected.value;
NetworkType _previousNetworkType = NetworkType.none;
bool _isInitialized = false;
@override
Future<void> onInit() async {
super.onInit();
logInfo('NetworkMonitor.onInit() called');
// Only monitor network on mobile platforms
if (!Platform.isAndroid && !Platform.isIOS) {
logInfo('NetworkMonitor: Not on mobile platform, skipping initialization');
return;
}
_connectivity = Connectivity();
// Check initial connectivity state
final initialResult = await _connectivity.checkConnectivity();
logInfo('NetworkMonitor: Initial connectivity result: $initialResult');
_updateNetworkStatus(initialResult);
_previousNetworkType = _getNetworkType(initialResult);
logInfo('NetworkMonitor: Initial network type: $_previousNetworkType');
_isInitialized = true;
// Listen to connectivity changes
_connectivitySubscription = _connectivity.onConnectivityChanged.listen(
_onConnectivityChanged,
onError: (error) {
logError('Network monitoring error: $error');
},
);
logInfo('Network monitor initialized successfully');
}
@override
void onClose() {
_connectivitySubscription.cancel();
super.onClose();
}
NetworkType _getNetworkType(List<ConnectivityResult> result) {
if (result.contains(ConnectivityResult.wifi)) {
return NetworkType.wifi;
} else if (result.contains(ConnectivityResult.mobile)) {
return NetworkType.mobile;
} else if (result.contains(ConnectivityResult.none)) {
return NetworkType.none;
} else {
// Ethernet, Bluetooth, VPN, or other connection types
return NetworkType.other;
}
}
void _updateNetworkStatus(List<ConnectivityResult> result) {
final hasWiFi = result.contains(ConnectivityResult.wifi);
_isWiFiConnected.value = hasWiFi;
}
void _onConnectivityChanged(List<ConnectivityResult> result) {
logInfo('NetworkMonitor: Connectivity changed event received: $result');
if (!_isInitialized) {
logInfo('NetworkMonitor: Not initialized yet, ignoring connectivity change');
return;
}
// Check if network auto control is enabled
final isNetworkAutoControlEnabled = Database.instance.getNetworkAutoControl();
logInfo('NetworkMonitor: Network auto control enabled: $isNetworkAutoControlEnabled');
if (!isNetworkAutoControlEnabled) {
logInfo('NetworkMonitor: Network auto control disabled, ignoring connectivity change');
return;
}
_updateNetworkStatus(result);
final currentNetworkType = _getNetworkType(result);
logInfo('Network changed: previous=$_previousNetworkType, current=$currentNetworkType');
// Only handle WiFi ↔ Mobile transitions, ignore other connection types
if (_previousNetworkType == NetworkType.wifi && currentNetworkType == NetworkType.mobile) {
_pauseAllDownloads();
logInfo('Switched from WiFi to mobile data - pausing all downloads');
} else if (_previousNetworkType == NetworkType.mobile && currentNetworkType == NetworkType.wifi) {
_resumeAllDownloads();
logInfo('Switched from mobile data to WiFi - resuming all downloads');
} else {
logInfo('Network change ignored: not a WiFi ↔ Mobile transition');
}
_previousNetworkType = currentNetworkType;
}
Future<void> _pauseAllDownloads() async {
try {
await pauseAllTasks(null);
logInfo('Successfully paused all downloads due to network change');
} catch (e) {
logError('Failed to pause all downloads: $e');
}
}
Future<void> _resumeAllDownloads() async {
try {
await continueAllTasks(null);
logInfo('Successfully resumed all downloads due to network change');
} catch (e) {
logError('Failed to resume all downloads: $e');
}
}
}
+1
View File
@@ -66,6 +66,7 @@ dependencies:
toggle_switch: ^2.3.0 toggle_switch: ^2.3.0
permission_handler: ^11.3.1 permission_handler: ^11.3.1
device_info_plus: ^11.1.0 device_info_plus: ^11.1.0
connectivity_plus: ^6.1.0
checkable_treeview: ^1.3.1 checkable_treeview: ^1.3.1
contextmenu_plus: ^1.0.1 contextmenu_plus: ^1.0.1
contentsize_tabbarview: ^0.0.2 contentsize_tabbarview: ^0.0.2