Skip to content

Commit d2ba459

Browse files
authored
Merge pull request #447 from HydrogenC/dev
Implement webvpn on Android
2 parents 469b54a + 4226b4a commit d2ba459

23 files changed

+1027
-318
lines changed

lib/l10n/intl_en.arb

+4-2
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@
227227
"koowz_description": "Danta Developer",
228228
"lan_connection_issue_1": "Failed to connect to the Campus Intranet",
229229
"lan_connection_issue_1_action": "Campus VPN",
230-
"lan_connection_issue_1_description": "Unable to connect to the Fudan Campus Intranet, some features will not be available.\n\nYou can use the campus VPN (Easy Connect) to access the Campus Intranet.",
230+
"lan_connection_issue_1_description": "Unable to connect to the Fudan Campus Intranet, some features may not be available. However, if you have `Use WebVPN` enabled, you may still access those feature directly. \n\nIf this doesn't work, you may have to use the campus VPN (Easy Connect) to access the Campus Intranet.",
231231
"lan_connection_issue_1_guide_content": "3 simple steps:\n\n1. [Click here](https://stuvpn.fudan.edu.cn/com/installClient.html#auto-common) to download the app.\n2. Open the installed app and type in the Address stuvpn.fudan.edu.cn\n3. Enter your UIS account & password.\n\nThen all features of Danta will work normally.",
232232
"lan_connection_issue_1_guide_title": "How to use the VPN?",
233233
"last_15_days": "Last 15 days",
@@ -540,5 +540,7 @@
540540
"proxy_setting_unset": "Not Set",
541541
"proxy_setting_input_title": "Input HTTP Proxy",
542542
"proxy_setting_input_hint": "e.g. 127.0.0.1:1234 (Leave blank to disable)",
543-
"proxy_setting_set_successfully": "Proxy settings saved, restart the app to take effect."
543+
"proxy_setting_set_successfully": "Proxy settings saved, restart the app to take effect.",
544+
"use_webvpn_title": "Use WebVPN proxy",
545+
"use_webvpn_description": "When enabled, certain functions could be accessed directly without Fudan LAN (restart required)"
544546
}

lib/l10n/intl_ja.arb

+4-2
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@
223223
"jump_to_hole": "ロケート",
224224
"lan_connection_issue_1": "キャンパスのイントラネットへの接続障害",
225225
"lan_connection_issue_1_action": "キャンパス VPN",
226-
"lan_connection_issue_1_description": "復旦内部ネットに接続できず、一部の機能は利用できない。あなたは校外やモバイルデータリンクを使用しましたか?\n\nキャンパスVPN(Easy Connect)やEduroamホットスポットなどをリンクしてイントラネットリソースにアクセスすることができます。",
226+
"lan_connection_issue_1_description": "復旦内部ネットに接続できず、一部の機能は利用できない。但し、「WebVPN を自動的に使う」が有効にすると、直接に訪問することもまだできます。\n\nそれが機能しない場合は、キャンパス VPN (Easy Connect) や Eduroam ホットスポットなどをリンクしてイントラネットリソースにアクセスすることができます。",
227227
"lan_connection_issue_1_guide_content": "たった3ステップ:\n\n1. [ここをクリックして](https://stuvpn.fudan.edu.cn/com/installClient.html#auto-common)VPNダウンロードページを開き、対応するプラットフォームを選択する。\n2. インストールされたソフトウェアを開く、URL欄にstuvpn.fudan.edu.cnを入力して、OKをクリックする。\n3. ログイン画面がポップアップするので、UISアカウントを入力し、Connectをクリックする。\n\nそうすれば、旦タのすべての機能を普通に使うことができます!",
228228
"lan_connection_issue_1_guide_title": "キャンパスVPNの使用方法",
229229
"last_15_days": "過去15日間",
@@ -524,5 +524,7 @@
524524
"proxy_setting_unset": "未設定",
525525
"proxy_setting_input_title": "HTTPプロキシアドレスを入力",
526526
"proxy_setting_input_hint": "例:127.0.0.1:1234(空白のままにしてプロキシを無効にする)",
527-
"proxy_setting_set_successfully": "プロキシ設定が保存されました。再起動すると有効になります。"
527+
"proxy_setting_set_successfully": "プロキシ設定が保存されました。再起動すると有効になります。",
528+
"use_webvpn_title": "WebVPN を自動的に使う",
529+
"use_webvpn_description": "有効時、一部の機能はFudan LANなしで、直接に連接するのができます (再起動が必要)"
528530
}

lib/l10n/intl_zh_CN.arb

+4-2
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@
224224
"koowz_description": "旦挞开发者",
225225
"lan_connection_issue_1": "未能连接到校园内网",
226226
"lan_connection_issue_1_action": "校园 VPN",
227-
"lan_connection_issue_1_description": "无法连接到复旦内部网络,部分功能不可用。您是否在校外或使用了移动数据链接?\n\n您可以使用校园 VPN(Easy Connect) 或链接 Eduroam 热点以访问内网资源。",
227+
"lan_connection_issue_1_description": "无法连接到复旦内部网络,部分功能可能不可用。然而,如果你开启了“自动使用 WebVPN 代理”,并且登录了 UIS 账号,你仍然可以直接使用这些功能。\n\n如果不起作用,请尝试使用校园 VPN (EasyConnect) 或链接 Eduroam 热点以访问内网资源。",
228228
"lan_connection_issue_1_guide_content": "三步走即可:\n\n1. [点击这里](https://stuvpn.fudan.edu.cn/com/installClient.html#auto-common)去 VPN 下载界面,选择对应平台安装。\n2. 打开安装的软件,在地址栏输入 stuvpn.fudan.edu.cn ,点击确定。\n3. 弹出登录界面,输入自己的 UIS 账号,点击连接。\n\n然后就可以正常使用旦挞各项功能了!",
229229
"lan_connection_issue_1_guide_title": "如何使用校园 VPN?",
230230
"last_15_days": "过去 15 天",
@@ -534,5 +534,7 @@
534534
"proxy_setting_unset": "未设置",
535535
"proxy_setting_input_title": "输入 HTTP 代理地址",
536536
"proxy_setting_input_hint": "如 127.0.0.1:1234(留空以关闭代理)",
537-
"proxy_setting_set_successfully": "代理设置已保存,重启应用后生效"
537+
"proxy_setting_set_successfully": "代理设置已保存,重启应用后生效",
538+
"use_webvpn_title": "自动使用 WebVPN 代理",
539+
"use_webvpn_description": "启动该项后,允许在非校园网环境下直接访问茶楼、评教等功能(需要重启应用)"
538540
}

lib/page/dashboard/announcement_notices.dart

+2-2
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ class AnnouncementListState extends State<AnnouncementList> {
8080
future: _future,
8181
successBuilder: (_, snapShot) {
8282
_data = _showingLatest
83-
? AnnouncementRepository.getInstance().getAnnouncements()
84-
: AnnouncementRepository.getInstance().getAllAnnouncements();
83+
? AnnouncementRepository.getInstance().getAnnouncements() ?? []
84+
: AnnouncementRepository.getInstance().getAllAnnouncements() ?? [];
8585
return Column(
8686
children: [
8787
Expanded(

lib/page/forum/image_viewer.dart

+4-4
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import 'dart:io';
1919

2020
import 'package:cached_network_image/cached_network_image.dart';
2121
import 'package:dan_xi/generated/l10n.dart';
22-
import 'package:dan_xi/util/io/cache_manager_with_proxy.dart';
22+
import 'package:dan_xi/util/io/cache_manager_with_webvpn.dart';
2323
import 'package:dan_xi/util/io/dio_utils.dart';
2424
import 'package:dan_xi/util/noticing.dart';
2525
import 'package:dan_xi/util/platform_universal.dart';
@@ -133,7 +133,7 @@ class ImageViewerPageState extends State<ImageViewerPage> {
133133
}
134134

135135
Future<void> shareImage(BuildContext context) async {
136-
File image = await DefaultCacheManagerWithProxy()
136+
File image = await DefaultCacheManagerWithWebvpn()
137137
.getSingleFile(_imageList[showIndex].hdUrl);
138138
if (!mounted) return;
139139

@@ -160,7 +160,7 @@ class ImageViewerPageState extends State<ImageViewerPage> {
160160
}
161161

162162
Future<void> saveImage(BuildContext context) async {
163-
File image = await DefaultCacheManagerWithProxy()
163+
File image = await DefaultCacheManagerWithWebvpn()
164164
.getSingleFile(_imageList[showIndex].hdUrl);
165165
if (PlatformX.isAndroid) {
166166
bool hasPermission = await PlatformX.galleryStorageGranted;
@@ -310,7 +310,7 @@ class ImageViewerBodyViewState extends State<ImageViewerBodyView> {
310310
Future<void> cacheOriginalImage() async {
311311
if (widget.imageInfo.thumbUrl == null) return;
312312
try {
313-
await DefaultCacheManagerWithProxy()
313+
await DefaultCacheManagerWithWebvpn()
314314
.getSingleFile(widget.imageInfo.hdUrl);
315315
setState(() => originalLoading = false);
316316
} catch (e, st) {

lib/page/home_page.dart

+23-18
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import 'package:dan_xi/util/noticing.dart';
4545
import 'package:dan_xi/util/platform_universal.dart';
4646
import 'package:dan_xi/util/public_extension_methods.dart';
4747
import 'package:dan_xi/util/stream_listener.dart';
48+
import 'package:dan_xi/util/webvpn_proxy.dart';
4849
import 'package:dan_xi/widget/dialogs/login_dialog.dart';
4950
import 'package:dan_xi/widget/dialogs/qr_code_dialog.dart';
5051
import 'package:dan_xi/widget/forum/post_render.dart';
@@ -382,16 +383,16 @@ class HomePageState extends State<HomePage> with WidgetsBindingObserver {
382383
}
383384
try {
384385
if (element == 'hole') {
385-
final OTHole hole = (await ForumRepository.getInstance()
386-
.loadSpecificHole(postId))!;
386+
final OTHole hole =
387+
(await ForumRepository.getInstance().loadSpecificHole(postId))!;
387388
if (mounted) {
388389
smartNavigatorPush(context, "/bbs/postDetail", arguments: {
389390
"post": hole,
390391
});
391392
}
392393
} else if (element == 'floor') {
393-
final floor = (await ForumRepository.getInstance()
394-
.loadSpecificFloor(postId))!;
394+
final floor =
395+
(await ForumRepository.getInstance().loadSpecificFloor(postId))!;
395396
final OTHole hole = (await ForumRepository.getInstance()
396397
.loadSpecificHole(floor.hole_id!))!;
397398
if (mounted) {
@@ -482,8 +483,7 @@ class HomePageState extends State<HomePage> with WidgetsBindingObserver {
482483
});
483484
}
484485
// Configure watch listeners on iOS.
485-
if (_needSendToWatch &&
486-
SettingsProvider.getInstance().forumToken != null) {
486+
if (_needSendToWatch && SettingsProvider.getInstance().forumToken != null) {
487487
sendFduholeTokenToWatch(
488488
SettingsProvider.getInstance().forumToken!.access!);
489489
// Only send once.
@@ -514,11 +514,10 @@ class HomePageState extends State<HomePage> with WidgetsBindingObserver {
514514
break;
515515
case "upload_apns_token":
516516
try {
517-
await ForumRepository.getInstance()
518-
.updatePushNotificationToken(
519-
call.arguments["token"],
520-
await PlatformX.getUniqueDeviceId(),
521-
PushNotificationServiceType.APNS);
517+
await ForumRepository.getInstance().updatePushNotificationToken(
518+
call.arguments["token"],
519+
await PlatformX.getUniqueDeviceId(),
520+
PushNotificationServiceType.APNS);
522521
} catch (e, st) {
523522
if (mounted) {
524523
Noticing.showNotice(
@@ -561,11 +560,10 @@ class HomePageState extends State<HomePage> with WidgetsBindingObserver {
561560
(params.commandArguments?.isNotEmpty ?? false)) {
562561
String regId = params.commandArguments![0];
563562
try {
564-
await ForumRepository.getInstance()
565-
.updatePushNotificationToken(
566-
regId,
567-
await PlatformX.getUniqueDeviceId(),
568-
PushNotificationServiceType.MIPUSH);
563+
await ForumRepository.getInstance().updatePushNotificationToken(
564+
regId,
565+
await PlatformX.getUniqueDeviceId(),
566+
PushNotificationServiceType.MIPUSH);
569567
} catch (e, st) {
570568
Noticing.showNotice(
571569
context,
@@ -622,6 +620,9 @@ class HomePageState extends State<HomePage> with WidgetsBindingObserver {
622620
///
623621
/// If user hasn't logged in before, request him to do so.
624622
void _loadPersonInfoOrLogin() {
623+
/// Register person info at [WebvpnProxy] to enable webvpn services to use it
624+
WebvpnProxy.bindPersonInfo(StateProvider.personInfo);
625+
625626
var preferences = SettingsProvider.getInstance().preferences;
626627

627628
if (PersonInfo.verifySharedPreferences(preferences!)) {
@@ -748,8 +749,12 @@ class HomePageState extends State<HomePage> with WidgetsBindingObserver {
748749
Future<void> _loadUpdate() async {
749750
//We don't need to check for update on iOS platform.
750751
if (PlatformX.isIOS) return;
751-
final UpdateInfo updateInfo =
752+
final UpdateInfo? updateInfo =
752753
AnnouncementRepository.getInstance().checkVersion();
754+
if (updateInfo == null) {
755+
return;
756+
}
757+
753758
if (updateInfo.isAfter(Version.parse(Pubspec.version.canonical))) {
754759
await showPlatformDialog(
755760
context: context,
@@ -836,6 +841,6 @@ class HomePageState extends State<HomePage> with WidgetsBindingObserver {
836841

837842
Future<void> _loadCelebration() async {
838843
SettingsProvider.getInstance().celebrationWords =
839-
AnnouncementRepository.getInstance().getCelebrations();
844+
AnnouncementRepository.getInstance().getCelebrations() ?? [];
840845
}
841846
}

lib/page/settings/diagnostic_console.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ class DiagnosticConsoleState extends State<DiagnosticConsole> {
106106
_console.writeln(
107107
"Base Auth URL: ${SettingsProvider.getInstance().authBaseUrl}");
108108
_console
109-
.writeln("Hole Base URL: ${SettingsProvider.getInstance().forumBaseUrl}");
109+
.writeln("Forum Base URL: ${SettingsProvider.getInstance().forumBaseUrl}");
110110
_console.writeln(
111111
"Image Base URL: ${SettingsProvider.getInstance().imageBaseUrl}");
112112
_console.writeln(

lib/page/subpage_settings.dart

+17-6
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import 'package:dan_xi/repository/forum/forum_repository.dart';
3232
import 'package:dan_xi/util/browser_util.dart';
3333
import 'package:dan_xi/util/flutter_app.dart';
3434
import 'package:dan_xi/util/forum/clean_mode_filter.dart';
35-
import 'package:dan_xi/util/io/cache_manager_with_proxy.dart';
35+
import 'package:dan_xi/util/io/cache_manager_with_webvpn.dart';
3636
import 'package:dan_xi/util/master_detail_view.dart';
3737
import 'package:dan_xi/util/noticing.dart';
3838
import 'package:dan_xi/util/platform_universal.dart';
@@ -500,18 +500,18 @@ class SettingsSubpageState extends PlatformSubpageState<SettingsSubpage> {
500500
S.of(context).proxy_setting_unset),
501501
leading: const Icon(Icons.network_ping),
502502
onTap: () async {
503-
String? email = await Noticing.showInputDialog(
503+
String? addr = await Noticing.showInputDialog(
504504
context,
505505
S.of(context).proxy_setting_input_title,
506506
initialText:
507507
context.read<SettingsProvider>().proxy,
508508
hintText:
509509
S.of(context).proxy_setting_input_hint);
510-
if (!context.mounted || email == null) {
510+
if (!context.mounted || addr == null) {
511511
return; // return if cancelled
512512
}
513-
if (email.isEmpty) email = null;
514-
context.read<SettingsProvider>().proxy = email;
513+
if (addr.isEmpty) addr = null;
514+
context.read<SettingsProvider>().proxy = addr;
515515
await Noticing.showNotice(context,
516516
S.of(context).proxy_setting_set_successfully);
517517
},
@@ -530,6 +530,17 @@ class SettingsSubpageState extends PlatformSubpageState<SettingsSubpage> {
530530
.read<SettingsProvider>()
531531
.hiddenNotifications = [],
532532
),
533+
SwitchListTile.adaptive(
534+
title: Text(S.of(context).use_webvpn_title),
535+
secondary: const Icon(Icons.network_cell),
536+
subtitle: Text(
537+
S.of(context).use_webvpn_description),
538+
value: context.select<SettingsProvider, bool>(
539+
(s) => s.useWebvpn),
540+
onChanged: (bool value) async {
541+
context.read<SettingsProvider>().useWebvpn =
542+
value;
543+
})
533544
],
534545
),
535546
),
@@ -801,7 +812,7 @@ class SettingsSubpageState extends PlatformSubpageState<SettingsSubpage> {
801812
subtitle: Text(_clearCacheSubtitle ??
802813
S.of(context).clear_cache_description),
803814
onTap: () async {
804-
await DefaultCacheManagerWithProxy().emptyCache();
815+
await DefaultCacheManagerWithWebvpn().emptyCache();
805816
setState(() {
806817
_clearCacheSubtitle = S.of(context).cache_cleared;
807818
});

lib/provider/settings_provider.dart

+13
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ class SettingsProvider with ChangeNotifier {
8484
static const String KEY_IMAGE_BASE_URL = "image_base_url";
8585
static const String KEY_DANKE_BASE_URL = "danke_base_url";
8686
static const String KEY_PROXY = "proxy";
87+
static const String KEY_USE_WEBVPN = "use_webvpn";
8788

8889
SettingsProvider._();
8990

@@ -739,6 +740,18 @@ class SettingsProvider with ChangeNotifier {
739740
preferences!.setBool(KEY_MARKDOWN_ENABLED, value);
740741
notifyListeners();
741742
}
743+
744+
bool get useWebvpn{
745+
if (preferences!.containsKey(KEY_USE_WEBVPN)) {
746+
return preferences!.getBool(KEY_USE_WEBVPN)!;
747+
}
748+
return true;
749+
}
750+
751+
set useWebvpn(bool value){
752+
preferences!.setBool(KEY_USE_WEBVPN, value);
753+
notifyListeners();
754+
}
742755
}
743756

744757
enum SortOrder { LAST_REPLIED, LAST_CREATED }

0 commit comments

Comments
 (0)