Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
f0c75d8
GitButler Workspace Commit
gitbutler-client Apr 15, 2025
a4db898
docs(readme): update readme
realth000 Apr 15, 2025
392316e
feat(utils): bottom sheet layout avoid view insets
realth000 Apr 15, 2025
dcb4d27
feat: auto parse for bilibili share links
realth000 Apr 15, 2025
81794ee
docs(readme): fix broken link
realth000 Apr 15, 2025
59f96b1
Merge branch 'realth000:master' into master
Qing-Novel Apr 16, 2025
52e3b4f
Merge branch 'realth000:master' into master
Qing-Novel Apr 17, 2025
3a90455
Merge branch 'realth000:master' into master
Qing-Novel Apr 19, 2025
f3d1269
Merge branch 'realth000:master' into master
Qing-Novel Apr 20, 2025
c7916f2
Merge branch 'realth000:master' into master
Qing-Novel Apr 21, 2025
ee08e1b
Merge branch 'realth000:master' into master
Qing-Novel Apr 22, 2025
014554c
Merge branch 'realth000:master' into master
Qing-Novel Apr 23, 2025
d0c9d20
Merge branch 'realth000:master' into master
Qing-Novel Apr 28, 2025
3b5e77a
Merge branch 'realth000:master' into master
Qing-Novel May 3, 2025
4ffbeb5
Merge branch 'realth000:master' into master
Qing-Novel May 5, 2025
48dbca1
Merge branch 'realth000:master' into master
Qing-Novel May 6, 2025
e6343eb
Merge branch 'realth000:master' into master
Qing-Novel May 10, 2025
61e23a3
Merge branch 'realth000:master' into master
Qing-Novel May 11, 2025
36f2ba0
Merge branch 'realth000:master' into master
Qing-Novel May 11, 2025
dadaab5
Merge branch 'realth000:master' into master
Qing-Novel May 14, 2025
d7551fe
Merge branch 'realth000:master' into master
Qing-Novel May 17, 2025
3008dc0
Merge branch 'realth000:master' into master
Qing-Novel May 21, 2025
29eba03
Merge branch 'realth000:master' into master
Qing-Novel May 24, 2025
ff74800
Merge branch 'realth000:master' into master
Qing-Novel May 28, 2025
92cc281
Merge branch 'realth000:master' into master
Qing-Novel May 29, 2025
fa5c689
Merge branch 'realth000:master' into master
Qing-Novel May 29, 2025
3834116
Merge branch 'realth000:master' into master
Qing-Novel May 31, 2025
2b83442
Merge branch 'realth000:master' into master
Qing-Novel Jun 3, 2025
e5b813a
Merge branch 'realth000:master' into master
Qing-Novel Jun 6, 2025
ef9ba9d
Merge branch 'realth000:master' into master
Qing-Novel Jun 7, 2025
bef9ce5
Merge branch 'realth000:master' into master
Qing-Novel Jun 9, 2025
0c882a7
Merge branch 'realth000:master' into master
Qing-Novel Jun 12, 2025
ed8e146
Merge branch 'realth000:master' into master
Qing-Novel Jun 12, 2025
259d549
Merge branch 'realth000:master' into master
Qing-Novel Jun 14, 2025
08d8a73
Merge branch 'realth000:master' into master
Qing-Novel Jun 17, 2025
418c33f
Merge branch 'realth000:master' into master
Qing-Novel Jun 20, 2025
bcd3aaf
Merge branch 'realth000:master' into master
Qing-Novel Jun 21, 2025
a8ea664
Merge branch 'realth000:master' into master
Qing-Novel Jun 22, 2025
f969626
Merge branch 'realth000:master' into master
Qing-Novel Jun 22, 2025
84b8e2b
Merge branch 'realth000:master' into master
Qing-Novel Jun 23, 2025
59a5a5d
Merge branch 'realth000:master' into master
Qing-Novel Jun 24, 2025
234a74b
Merge branch 'realth000:master' into master
Qing-Novel Jun 27, 2025
8046730
Merge branch 'realth000:master' into master
Qing-Novel Jun 28, 2025
a94a791
Merge branch 'realth000:master' into master
Qing-Novel Jun 29, 2025
1bf7a30
Merge branch 'realth000:master' into master
Qing-Novel Jun 30, 2025
804f956
Merge branch 'realth000:master' into master
Qing-Novel Jul 2, 2025
14316ce
Merge branch 'realth000:master' into master
Qing-Novel Jul 4, 2025
22bb116
Merge branch 'realth000:master' into master
Qing-Novel Jul 5, 2025
af77d3d
Merge branch 'realth000:master' into master
Qing-Novel Jul 6, 2025
734ea93
Merge branch 'realth000:master' into master
Qing-Novel Jul 6, 2025
cc8e301
Merge branch 'realth000:master' into master
Qing-Novel Jul 6, 2025
4e89f4d
Merge branch 'realth000:master' into master
Qing-Novel Jul 9, 2025
d5c50be
Merge branch 'realth000:master' into master
Qing-Novel Jul 10, 2025
d003701
Merge branch 'realth000:master' into master
Qing-Novel Jul 11, 2025
a953e70
Merge branch 'realth000:master' into master
Qing-Novel Jul 12, 2025
dacd630
Merge branch 'realth000:master' into master
Qing-Novel Jul 17, 2025
9be77c1
Merge branch 'realth000:master' into master
Qing-Novel Jul 17, 2025
5ef4503
Merge branch 'realth000:master' into master
Qing-Novel Jul 19, 2025
c09f1c3
Merge branch 'realth000:master' into master
Qing-Novel Jul 22, 2025
4a59e0e
Merge branch 'realth000:master' into master
Qing-Novel Jul 26, 2025
3321e28
Merge branch 'realth000:master' into master
Qing-Novel Jul 27, 2025
492b039
Merge branch 'realth000:master' into master
Qing-Novel Aug 3, 2025
77957a0
Merge branch 'realth000:master' into master
Qing-Novel Aug 16, 2025
c96f20e
Merge branch 'realth000:master' into master
Qing-Novel Aug 19, 2025
12f0604
Merge branch 'realth000:master' into master
Qing-Novel Aug 29, 2025
156191c
Merge branch 'realth000:master' into master
Qing-Novel Oct 18, 2025
b12ebee
Merge branch 'realth000:master' into master
Qing-Novel Oct 28, 2025
106a310
Merge branch 'realth000:master' into master
Qing-Novel Nov 19, 2025
79e989f
Update pubspec.yaml
Qing-Novel Nov 19, 2025
c5e0bda
Create BackgroundService for task management
Qing-Novel Nov 19, 2025
166eba5
Delete lib/lib directory
Qing-Novel Nov 19, 2025
64ea762
Create BackgroundService for task management
Qing-Novel Nov 19, 2025
9f9ecfa
Update settings_page.dart
Qing-Novel Nov 19, 2025
16a41f5
Implement SettingsProvider for background task management
Qing-Novel Nov 19, 2025
36b8f05
Update main.dart
Qing-Novel Nov 19, 2025
51d8bef
Add background_service import to main.dart
Qing-Novel Nov 19, 2025
dcea449
Enhance BackgroundService with error handling and logging
Qing-Novel Nov 19, 2025
c07010f
Update AndroidManifest.xml
Qing-Novel Nov 19, 2025
2d8d6ba
Update Info.plist
Qing-Novel Nov 19, 2025
3b235df
Update background_service.dart
Qing-Novel Nov 19, 2025
db442a7
Update AndroidManifest.xml
Qing-Novel Nov 19, 2025
bc3d011
Update Info.plist
Qing-Novel Nov 19, 2025
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
40 changes: 21 additions & 19 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,38 +1,40 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<!-- android:usesCleartextTraffic: When using native Cronet http client, http urls shall be handled explicitly -->
<application
android:label="天使动漫"
android:name="${applicationName}"
android:usesCleartextTraffic="true"
android:icon="@mipmap/ic_launcher">
android:label="天使动漫"
android:name="${applicationName}"
android:usesCleartextTraffic="true"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/Theme.TsdmClient.Launcher"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/Theme.TsdmClient.Launcher"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2"/>
android:name="flutterEmbedding"
android:value="2" />
</application>
</manifest>
5 changes: 5 additions & 0 deletions ios/Runner/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,10 @@
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>processing</string>
</array>
</dict>
</plist>
30 changes: 30 additions & 0 deletions lib/features/settings/provider/settings_provider.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// lib/features/settings/provider/settings_provider.dart
import 'package:flutter/foundation.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../../services/background_service.dart';

class SettingsProvider with ChangeNotifier {
bool _backgroundKeepAlive = false;

bool get backgroundKeepAlive => _backgroundKeepAlive;

Future<void> setBackgroundKeepAlive(bool value) async {
_backgroundKeepAlive = value;
final prefs = await SharedPreferences.getInstance();
await prefs.setBool('background_keep_alive', value);
notifyListeners();

// 根据开关状态启动或停止后台任务
if (value) {
await BackgroundService.startBackgroundTask();
} else {
await BackgroundService.stopBackgroundTask();
}
}

Future<void> loadBackgroundKeepAlive() async {
final prefs = await SharedPreferences.getInstance();
_backgroundKeepAlive = prefs.getBool('background_keep_alive') ?? false;
notifyListeners();
}
}
47 changes: 47 additions & 0 deletions lib/features/settings/view/settings_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ import 'package:tsdm_client/widgets/section_switch_list_tile.dart';
import 'package:tsdm_client/widgets/section_title_text.dart';
import 'package:tsdm_client/widgets/shutdown.dart';
import 'package:tsdm_client/widgets/tips.dart';
import 'package:provider/provider.dart';
import '../provider/settings_provider.dart';

/// Settings page of the app.
class SettingsPage extends StatefulWidget {
Expand Down Expand Up @@ -865,3 +867,48 @@ class _SettingsPageState extends State<SettingsPage> {
);
}
}

Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text('设置'),
),
child: SafeArea(
child: ListView(
children: [
// ... 其他现有设置项 ...

// === 添加后台常驻开关 ===
CupertinoFormSection.insetGrouped(
header: Text('行为'),
children: [
CupertinoFormRow(
prefix: Container(
width: 24, // 留空图标位置
),
helper: Text('开启后,应用在后台时会尝试保持活动状态以执行任务'),
child: Row(
children: [
Expanded(
child: Text('后台常驻'),
),
Consumer<SettingsProvider>(
builder: (context, settings, child) {
return CupertinoSwitch(
value: settings.backgroundKeepAlive,
onChanged: (bool value) {
settings.setBackgroundKeepAlive(value);
},
);
},
),
],
),
),
],
),
],
),
),
);
}
13 changes: 13 additions & 0 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import 'package:tsdm_client/features/local_notice/callback.dart';
import 'package:tsdm_client/features/settings/repositories/settings_repository.dart';
import 'package:tsdm_client/i18n/strings.g.dart';
import 'package:tsdm_client/instance.dart';
import 'package:tsdm_client/services/background_service.dart';
import 'package:tsdm_client/shared/providers/providers.dart';
import 'package:tsdm_client/shared/providers/proxy_provider/proxy_provider.dart';
import 'package:tsdm_client/utils/platform.dart';
Expand All @@ -31,6 +32,18 @@ Future<void> _boot(List<String> args) async {
talker.debug('------------------- start app -------------------');
await initProviders();

// 初始化后台服务
await BackgroundService.initialize();

// 获取设置仓库并检查后台常驻设置
final settingsRepo = getIt.get<SettingsRepository>();
final backgroundKeepAliveEnabled = settingsRepo.currentSettings.backgroundKeepAlive ?? false;

// 如果设置中启用了后台常驻,则启动后台任务
if (backgroundKeepAliveEnabled) {
await BackgroundService.startBackgroundTask();
}

final settings = getIt.get<SettingsRepository>().currentSettings;

final settingsLocale = settings.locale;
Expand Down
53 changes: 53 additions & 0 deletions lib/services/background_service.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import 'package:workmanager/workmanager.dart';

@pragma('vm:entry-point')
void callbackDispatcher() {
Workmanager().executeTask((task, inputData) {
print("BackgroundTask: TSDM Client is running in background!");
return Future.value(true);
});
}

class BackgroundService {
static Future<void> initialize() async {
try {
await Workmanager().initialize(
callbackDispatcher,
isInDebugMode: false,
);
print("BackgroundService: Initialized successfully");
} catch (e) {
print("BackgroundService: Initialization failed - $e");
rethrow;
}
}

static Future<void> startBackgroundTask() async {
try {
await Workmanager().registerPeriodicTask(
"tsdmBackgroundTask",
"tsdmBackgroundTask",
frequency: Duration(minutes: 15),
initialDelay: Duration(seconds: 10),
constraints: Constraints(
networkType: NetworkType.connected,
),
existingWorkPolicy: ExistingWorkPolicy.replace,
);
print("BackgroundService: Background task started successfully");
} catch (e) {
print("BackgroundService: Failed to start background task - $e");
rethrow;
}
}

static Future<void> stopBackgroundTask() async {
try {
await Workmanager().cancelByUniqueName("tsdmBackgroundTask");
print("BackgroundService: Background task stopped successfully");
} catch (e) {
print("BackgroundService: Failed to stop background task - $e");
rethrow;
}
}
}