Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions ui/flutter/lib/app/modules/app/bindings/app_binding.dart

This file was deleted.

2 changes: 2 additions & 0 deletions ui/flutter/lib/app/modules/root/bindings/root_binding.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import 'package:get/get.dart';

import '../../../../util/network_monitor.dart';
import '../controllers/root_controller.dart';

class RootBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut<RootController>(() => RootController(), fenix: true);
Get.put<NetworkMonitor>(NetworkMonitor(), permanent: true);
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import 'package:get/get.dart';

import '../../../../database/database.dart';
import '../../../../util/updater.dart';

class SettingController extends GetxController {
final tapStatues = <String, bool>{}.obs;
final latestVersion = Rxn<VersionInfo>();
final networkAutoControl = false.obs;

@override
void onInit() {
super.onInit();
fetchLatestVersion();
// Initialize network auto control setting
networkAutoControl.value = Database.instance.getNetworkAutoControl();
}

// set all tap status to false
Expand All @@ -27,4 +31,10 @@ class SettingController extends GetxController {
void fetchLatestVersion() async {
latestVersion.value = await checkUpdate();
}

// update network auto control setting
void updateNetworkAutoControl(bool value) {
networkAutoControl.value = value;
Database.instance.saveNetworkAutoControl(value);
}
}
24 changes: 23 additions & 1 deletion ui/flutter/lib/app/modules/setting/views/setting_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import 'package:launch_at_startup/launch_at_startup.dart';
import 'package:url_launcher/url_launcher.dart';

import '../../../../api/model/downloader_config.dart';
import '../../../../database/database.dart';
import '../../../../i18n/message.dart';
import '../../../../util/input_formatter.dart';
import '../../../../util/locale_manager.dart';
Expand Down Expand Up @@ -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
final proxy = downloaderCfg.value.proxy;
final buildProxy = _buildConfigItem(
Expand Down Expand Up @@ -985,7 +1004,10 @@ class SettingView extends GetView<SettingController> {
Text('network'.tr),
Card(
child: Column(
children: _addDivider([buildProxy()]),
children: _addDivider([
buildNetworkAutoControl(),
buildProxy(),
].where((e) => e != null).cast<Widget>().toList()),
)),
const Text('API'),
Card(
Expand Down
9 changes: 9 additions & 0 deletions ui/flutter/lib/database/database.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const String _windowState = 'windowState';
const String _bookmark = 'bookmark';
const String _createHistory = 'createHistory';
const String _webToken = 'webToken';
const String _networkAutoControl = 'networkAutoControl';

class Database {
static final Database _instance = Database._internal();
Expand Down Expand Up @@ -109,4 +110,12 @@ class Database {
void clearCreateHistory() {
clear(_createHistory);
}

void saveNetworkAutoControl(bool enabled) {
save<bool>(_networkAutoControl, enabled);
}

bool getNetworkAutoControl() {
return get<bool>(_networkAutoControl, (json) => json as bool) ?? false;
}
}
2 changes: 2 additions & 0 deletions ui/flutter/lib/i18n/langs/en_us.dart
Original file line number Diff line number Diff line change
Expand Up @@ -125,5 +125,7 @@ const enUS = {
'login_failed': 'Login failed, please check your username and password',
'login_failed_network':
'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 changes: 2 additions & 0 deletions ui/flutter/lib/i18n/langs/es_es.dart
Original file line number Diff line number Diff line change
Expand Up @@ -104,5 +104,7 @@ const esES = {
'taskUrl': 'URL de la Tarea',
'downloadPath': 'Ruta de Descarga',
'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 changes: 2 additions & 0 deletions ui/flutter/lib/i18n/langs/fr_fr.dart
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,7 @@ const frFR = {
'browserExtension': 'Extension du navigateur',
'launchAtStartup': 'Lancer au démarrage',
'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 changes: 2 additions & 0 deletions ui/flutter/lib/i18n/langs/it_it.dart
Original file line number Diff line number Diff line change
Expand Up @@ -97,5 +97,7 @@ const itIT = {
'browserExtension': 'Estensione del browser',
'launchAtStartup': "Lancia all'avvio",
'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 changes: 2 additions & 0 deletions ui/flutter/lib/i18n/langs/ja_jp.dart
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,7 @@ const jaJP = {
'thanksDesc': 'Gopeedコミュニティの建設に協力してくださったすべての貢献者の方々に感謝します!',
'browserExtension': 'ブラウザ拡張機能',
'skipVerifyCert': '証明書の検証をスキップ',
'networkAutoControl': 'ネットワーク自動制御',
'networkAutoControlTip': 'WiFiからモバイルデータに切り替わった時に自動的にダウンロードを一時停止し、WiFiに戻った時に自動的に再開します',
}
};
2 changes: 2 additions & 0 deletions ui/flutter/lib/i18n/langs/ru_ru.dart
Original file line number Diff line number Diff line change
Expand Up @@ -119,5 +119,7 @@ const ruRU = {
'fileSelectedSize': 'Размер: ',
'httpHeaderName': 'Название заголовка HTTP',
'httpHeaderValue': 'Значение заголовка HTTP',
'networkAutoControl': 'Автоматическое управление сетью',
'networkAutoControlTip': 'Автоматически приостанавливать загрузки при переключении с WiFi на мобильные данные и возобновлять при возврате к WiFi',
}
};
2 changes: 2 additions & 0 deletions ui/flutter/lib/i18n/langs/vi_vn.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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!',
'browserExtension': 'Tiện ích mở rộng trình duyệt',
'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 changes: 2 additions & 0 deletions ui/flutter/lib/i18n/langs/zh_cn.dart
Original file line number Diff line number Diff line change
Expand Up @@ -122,5 +122,7 @@ const zhCN = {
'login_success': '登录成功',
'login_failed': '登录失败,请检查用户名和密码',
'login_failed_network': '登录失败,请检查网络连接',
'networkAutoControl': '网络状态自动控制',
'networkAutoControlTip': '当网络从WiFi切换到移动数据时自动暂停下载,切换回WiFi时自动恢复下载',
}
};
2 changes: 2 additions & 0 deletions ui/flutter/lib/i18n/langs/zh_tw.dart
Original file line number Diff line number Diff line change
Expand Up @@ -116,5 +116,7 @@ const zhTW = {
'fileSelectedSize': '大小:',
'httpHeaderName': '標頭名稱',
'httpHeaderValue': '標頭值',
'networkAutoControl': '網路狀態自動控制',
'networkAutoControlTip': '當網路從WiFi切換到流動數據時自動暫停下載,切換回WiFi時自動恢復下載',
}
};
134 changes: 134 additions & 0 deletions ui/flutter/lib/util/network_monitor.dart
Original file line number Diff line number Diff line change
@@ -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 change: 1 addition & 0 deletions ui/flutter/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ dependencies:
toggle_switch: ^2.3.0
permission_handler: ^11.3.1
device_info_plus: ^11.1.0
connectivity_plus: ^6.1.0
checkable_treeview: ^1.3.1
contextmenu_plus: ^1.0.1
contentsize_tabbarview: ^0.0.2
Expand Down