feat: 源码提交
Build Windows / build (push) Has been cancelled

This commit is contained in:
2025-10-19 23:30:54 -07:00
parent 54e7df78db
commit 75d4c48e41
6076 changed files with 64655 additions and 0 deletions
+32
View File
@@ -0,0 +1,32 @@
import 'package:flutter/material.dart';
class BottomSheetPage extends Page {
const BottomSheetPage({
super.key,
super.name,
required this.builder,
this.fixed = false,
});
final Widget Function(ScrollController? controller) builder;
final bool fixed;
@override
Route<void> createRoute(BuildContext context) {
return ModalBottomSheetRoute(
settings: this,
isScrollControlled: true,
useSafeArea: true,
showDragHandle: true,
builder: (_) {
if (!fixed) {
return DraggableScrollableSheet(
expand: false,
builder: (_, scrollController) => builder(scrollController),
);
}
return builder(null);
},
);
}
}
+25
View File
@@ -0,0 +1,25 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
class CallbackDebouncer {
CallbackDebouncer(this._delay);
final Duration _delay;
Timer? _timer;
/// Calls the given [callback] after the given duration has passed.
void call(VoidCallback callback) {
if (_delay == Duration.zero) {
callback();
} else {
_timer?.cancel();
_timer = Timer(_delay, callback);
}
}
/// Stops any running timers and disposes this instance.
void dispose() {
_timer?.cancel();
}
}
+31
View File
@@ -0,0 +1,31 @@
import 'package:loggy/loggy.dart';
/// application layer logger
///
/// used in notifiers and controllers
mixin AppLogger implements LoggyType {
@override
Loggy<AppLogger> get loggy => Loggy<AppLogger>('$runtimeType');
}
/// presentation layer logger
///
/// used in widgets and ui
mixin PresLogger implements LoggyType {
@override
Loggy<PresLogger> get loggy => Loggy<PresLogger>('$runtimeType');
}
/// data layer logger
///
/// used in Repositories, DAOs, Services
mixin InfraLogger implements LoggyType {
@override
Loggy<InfraLogger> get loggy => Loggy<InfraLogger>('$runtimeType');
}
abstract class LoggerMixin {
LoggerMixin(this.loggy);
final Loggy loggy;
}
+17
View File
@@ -0,0 +1,17 @@
// import 'package:freezed_annotation/freezed_annotation.dart';
// import 'package:kaer_with_panels/core/model/failures.dart';
// part 'mutation_state.freezed.dart';
// // TODO: remove
// @freezed
// class MutationState<F extends Failure> with _$MutationState<F> {
// const MutationState._();
// const factory MutationState.initial() = MutationInitial<F>;
// const factory MutationState.inProgress() = MutationInProgress<F>;
// const factory MutationState.failure(Failure failure) = MutationFailure<F>;
// const factory MutationState.success() = MutationSuccess<F>;
// bool get isInProgress => this is MutationInProgress;
// }
+6
View File
@@ -0,0 +1,6 @@
import 'dart:io';
abstract class PlatformUtils {
static bool get isDesktop =>
Platform.isLinux || Platform.isWindows || Platform.isMacOS;
}
+23
View File
@@ -0,0 +1,23 @@
import 'dart:async';
import 'package:hooks_riverpod/hooks_riverpod.dart';
extension RefLifeCycle<T> on AutoDisposeRef<T> {
void disposeDelay(Duration duration) {
final link = keepAlive();
Timer? timer;
onCancel(() {
timer?.cancel();
timer = Timer(duration, link.close);
});
onDispose(() {
timer?.cancel();
});
onResume(() {
timer?.cancel();
});
}
}
+10
View File
@@ -0,0 +1,10 @@
export 'bottom_sheet_page.dart';
export 'callback_debouncer.dart';
export 'custom_loggers.dart';
export 'mutation_state.dart';
export 'platform_utils.dart';
export 'validators.dart';
+19
View File
@@ -0,0 +1,19 @@
/// https://gist.github.com/dperini/729294
final _urlRegex = RegExp(
// r"^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z0-9\u00a1-\uffff][a-z0-9\u00a1-\uffff_-]{0,62})?[a-z0-9\u00a1-\uffff]\.)+(?:[a-z\u00a1-\uffff]{2,}\.?))(?::\d{2,5})?(?:[/?#]\S*)?$",
r'^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?:[0-9]{1,3}\.){3}[0-9]{1,3}|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?#?.*$',
);
/// https://stackoverflow.com/a/12968117
final _portRegex = RegExp(
r"^([1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$",
);
/// https://stackoverflow.com/questions/3809401/what-is-a-good-regular-expression-to-match-a-url/3809435#3809435
bool isUrl(String input) {
return _urlRegex.hasMatch(input.trim().toLowerCase());
}
bool isPort(String input) {
return _portRegex.hasMatch(input);
}