Skip to content
Merged
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
57 changes: 34 additions & 23 deletions lib/app.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import 'dart:async';

import 'package:fl_lib/fl_lib.dart' as fl;
import 'package:fl_lib/fl_lib.dart' show ChineseThemeData;
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:window_manager/window_manager.dart';

import 'constants/app_branding.dart';
import 'generated/l10n/l10n.dart';
import 'kit/kit.dart' as kit;
import 'kit/kit.dart' show ChineseThemeData;
import 'models/aria2_instance.dart';
import 'models/settings.dart';
import 'pages/download_page/download_page.dart';
Expand Down Expand Up @@ -53,14 +54,30 @@ class _ThemeProviderState extends State<_ThemeProvider> {

@override
Widget build(BuildContext context) {
final display = context.select<Settings, ({Locale? locale, bool hideTitleBar, Color primaryColor, ThemeMode themeMode})>((s) => (locale: s.locale, hideTitleBar: s.hideTitleBar, primaryColor: s.primaryColor, themeMode: s.themeMode));
final display = context
.select<
Settings,
({
Locale? locale,
bool hideTitleBar,
Color primaryColor,
ThemeMode themeMode,
})
>(
(s) => (
locale: s.locale,
hideTitleBar: s.hideTitleBar,
primaryColor: s.primaryColor,
themeMode: s.themeMode,
),
);

return MaterialApp(
title: kAppName,
locale: display.locale,
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
builder: (context, child) => fl.VirtualWindowFrame(
builder: (context, child) => kit.VirtualWindowFrame(
title: kAppName,
showCaption: display.hideTitleBar,
child: ClipRect(child: child ?? const SizedBox.shrink()),
Expand Down Expand Up @@ -203,7 +220,7 @@ class _HomeWrapperState extends State<_HomeWrapper> with Loggable {
@override
Widget build(BuildContext context) {
if (!_isInitialized) {
return Scaffold(body: Center(child: fl.SizedLoading.medium));
return Scaffold(body: Center(child: kit.SizedLoading.medium));
}
return const MainWindow();
}
Expand Down Expand Up @@ -552,8 +569,7 @@ class _MainWindowState extends State<MainWindow> with WindowListener, Loggable {
connectedCount == 0
? l10n.notConnected
: '${l10n.connected}: $connectedCount',
if (settings.showTraySpeed)
l10n.totalSpeed(formatSpeed(summary.speed)),
if (settings.showTraySpeed) l10n.totalSpeed(formatSpeed(summary.speed)),
l10n.activeTasks(summary.active.toString()),
l10n.waitingTasks(summary.waiting.toString()),
];
Expand Down Expand Up @@ -902,7 +918,7 @@ class _MainWindowState extends State<MainWindow> with WindowListener, Loggable {
}

({int active, int waiting, int resumable, int pausable, int speed})
_computeTaskSummary(List<DownloadTask> tasks) {
_computeTaskSummary(List<DownloadTask> tasks) {
var active = 0;
var waiting = 0;
var resumable = 0;
Expand Down Expand Up @@ -940,9 +956,13 @@ class _StatusBar extends StatelessWidget {
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
final colorScheme = Theme.of(context).colorScheme;
final summary = context.select<DownloadDataService, ({int active, int waiting, int resumable, int pausable, int speed})>((service) {
return _computeTaskSummary(service.tasks);
});
final summary = context
.select<
DownloadDataService,
({int active, int waiting, int resumable, int pausable, int speed})
>((service) {
return _computeTaskSummary(service.tasks);
});

return Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
Expand All @@ -967,28 +987,19 @@ class _StatusBar extends StatelessWidget {
label: Text(l10n.totalSpeed(formatSpeed(summary.speed))),
avatar: const Icon(Icons.speed, size: 16),
backgroundColor: colorScheme.surfaceContainerHighest,
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 6,
),
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6),
),
Chip(
label: Text(l10n.activeTasks(summary.active.toString())),
avatar: const Icon(Icons.task_alt, size: 16),
backgroundColor: colorScheme.surfaceContainerHighest,
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 6,
),
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6),
),
Chip(
label: Text(l10n.waitingTasks(summary.waiting.toString())),
avatar: const Icon(Icons.pending, size: 16),
backgroundColor: colorScheme.surfaceContainerHighest,
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 6,
),
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6),
),
],
),
Expand Down
21 changes: 21 additions & 0 deletions lib/kit/core/build.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
enum BuildMode {
release,
debug,
profile;

static final isDebug = _buildMode == BuildMode.debug;
static final isProfile = _buildMode == BuildMode.profile;
static final isRelease = _buildMode == BuildMode.release;
}

final _buildMode = () {
if (const bool.fromEnvironment('dart.vm.product')) {
return BuildMode.release;
}
var result = BuildMode.profile;
assert(() {
result = BuildMode.debug;
return true;
}());
return result;
}();
7 changes: 7 additions & 0 deletions lib/kit/core/ext/datetime.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
extension DateTimeX on DateTime {
String get hourMinute {
return '${hour.toString().padLeft(2, '0')}:${minute.toString().padLeft(2, '0')}';
}

static int get timestamp => DateTime.now().millisecondsSinceEpoch;
}
13 changes: 13 additions & 0 deletions lib/kit/core/ext/obj.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import '../rnode.dart';

extension ObjectX<T extends Object> on T {
VNode<T> get vn => VNode<T>(this);
}

extension ObjectXNullable<T extends Object> on T? {
A? nullOr<A>(A Function(T) f) => this != null ? f(this!) : null;

VNode<T?> get vn => VNode<T?>(this);
}

VNode<T?> nvn<T>() => VNode<T?>(null);
7 changes: 7 additions & 0 deletions lib/kit/core/ext/string.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import 'package:url_launcher/url_launcher_string.dart';

extension StringX on String {
Future<bool> launchUrl() async {
return await launchUrlString(this);
}
}
21 changes: 21 additions & 0 deletions lib/kit/core/ext/widget.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import 'package:flutter/material.dart';

extension WidgetX on Widget {
Widget paddingAll(double value) =>
Padding(padding: EdgeInsets.all(value), child: this);

Widget paddingOnly({
double left = 0,
double top = 0,
double right = 0,
double bottom = 0,
}) => Padding(
padding: EdgeInsets.only(
left: left,
top: top,
right: right,
bottom: bottom,
),
child: this,
);
}
23 changes: 23 additions & 0 deletions lib/kit/core/func.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import 'dart:async';

abstract final class Fns {
static const _defaultDurationTime = 377;
static const _defaultThrottleId = 'default';
static final startTimeMap = <String, int>{_defaultThrottleId: 0};

static FutureOr<T?> throttle<T>(
FutureOr<T> Function() func, {
String id = _defaultThrottleId,
int duration = _defaultDurationTime,
void Function()? continueClick,
}) async {
final currentTime = DateTime.now().millisecondsSinceEpoch;
if (currentTime - (startTimeMap[id] ?? 0) > duration) {
startTimeMap[id] = DateTime.now().millisecondsSinceEpoch;
return await func();
} else {
continueClick?.call();
return null;
}
}
}
65 changes: 65 additions & 0 deletions lib/kit/core/logger.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import 'dart:io';

import 'package:logging/logging.dart';

import 'build.dart';

abstract final class Loggers {
static final root = Logger('Root');
static final store = Logger('Store');
static final route = Logger('Route');
static final app = Logger('App');

static final sourceReg = RegExp(r'\((.+):(\d+):(\d+)\)');

static void log(Object message, {int skipFrames = 1}) {
final traceLines = StackTrace.current.toString().split('\n');

if (traceLines.length > skipFrames) {
final caller = traceLines[skipFrames];
final match = sourceReg.firstMatch(caller);
if (match != null) {
String? file = match.group(1)?.replaceFirst('file://', '');
final line = match.group(2);
if (file != null) {
final pwd = Directory.current.path;
if (file.startsWith(pwd)) {
file = file.substring(pwd.length + 1);
file = './$file';
}
}
print('[$file:$line] $message');
return;
}
}
print(message);
}
}

void dprint(Object? msg, [Object? msg2, Object? msg3, Object? msg4]) {
if (!BuildMode.isDebug) return;
lprint(msg, msg2, msg3, msg4, 3);
}

void lprint(
Object? msg, [
Object? msg2,
Object? msg3,
Object? msg4,
int skipFrames = 2,
]) {
final sb = StringBuffer();
sb.write(msg.toString());

if (msg2 != null) {
sb.write('\n$msg2');
if (msg3 != null) {
sb.write('\n$msg3');
if (msg4 != null) {
sb.write('\n$msg4');
}
}
}
final str = sb.toString();
Loggers.log(str, skipFrames: skipFrames);
}
49 changes: 49 additions & 0 deletions lib/kit/core/platform.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import 'dart:io';

import 'package:flutter/foundation.dart';

enum Pfs {
android,
ios,
linux,
macos,
windows,
web,
fuchsia,
unknown;

static final type = () {
if (kIsWeb) return web;
return switch (Platform.operatingSystem) {
'android' => android,
'ios' => ios,
'linux' => linux,
'macos' => macos,
'windows' => windows,
'fuchsia' => fuchsia,
_ => unknown,
};
}();

static final String separator = isWindows ? '\\' : '/';

static final String? homeDir = () {
final envVars = Platform.environment;
if (isMacOS || isLinux) {
return envVars['HOME'];
} else if (isWindows) {
return envVars['UserProfile'];
}
return null;
}();
}

final isAndroid = Pfs.type == Pfs.android;
final isIOS = Pfs.type == Pfs.ios;
final isLinux = Pfs.type == Pfs.linux;
final isMacOS = Pfs.type == Pfs.macos;
final isWindows = Pfs.type == Pfs.windows;
final isWeb = Pfs.type == Pfs.web;
final isMobile = Pfs.type == Pfs.ios || Pfs.type == Pfs.android;
final isDesktop =
Pfs.type == Pfs.linux || Pfs.type == Pfs.macos || Pfs.type == Pfs.windows;
Loading