first commit
This commit is contained in:
50
lib/components/debouncer.dart
Normal file
50
lib/components/debouncer.dart
Normal file
@@ -0,0 +1,50 @@
|
||||
// Dart imports:
|
||||
import 'dart:async';
|
||||
|
||||
// Flutter imports:
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
///
|
||||
/// Компонент для выполнения отложенных операций
|
||||
///
|
||||
class Debouncer {
|
||||
///
|
||||
/// Компонент для выполнения отложенных операций
|
||||
///
|
||||
/// Пример использования
|
||||
///
|
||||
/// ```dart
|
||||
/// final Debouncer _searchDelayer = Debouncer(
|
||||
/// delay: const Duration(milliseconds: 300),
|
||||
/// );
|
||||
///
|
||||
/// Widget _buildButton(BuildContext) {
|
||||
/// return ElevatedButton(
|
||||
/// onPressed: () {
|
||||
/// _debouncer.run(() {
|
||||
/// debugPrint('Type your code here');
|
||||
/// });
|
||||
/// },
|
||||
/// );
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
Debouncer({
|
||||
required this.delay,
|
||||
});
|
||||
|
||||
/// Время через которое необходимо вызывать функцию
|
||||
final Duration delay;
|
||||
|
||||
/// Таймер
|
||||
Timer? _timer;
|
||||
|
||||
///
|
||||
/// Запуск отложенного события
|
||||
///
|
||||
void run(VoidCallback action) {
|
||||
_timer?.cancel();
|
||||
|
||||
_timer = Timer(delay, action);
|
||||
}
|
||||
}
|
||||
30
lib/components/env.dart
Normal file
30
lib/components/env.dart
Normal file
@@ -0,0 +1,30 @@
|
||||
// Package imports:
|
||||
import 'package:get_it/get_it.dart';
|
||||
|
||||
part 'env/dev_env.dart';
|
||||
part 'env/prod_env.dart';
|
||||
|
||||
///
|
||||
/// Базовый класс ENV
|
||||
///
|
||||
abstract class Env {
|
||||
///
|
||||
/// Указание на URL бекенда
|
||||
///
|
||||
Uri get url;
|
||||
|
||||
///
|
||||
/// Режим работы приложения
|
||||
///
|
||||
String get mode;
|
||||
|
||||
///
|
||||
/// Получение ENV более удобным для написания кода способом
|
||||
///
|
||||
static Env get get => Env.of();
|
||||
|
||||
///
|
||||
/// Получение ENV
|
||||
///
|
||||
static Env of() => GetIt.I.get<Env>();
|
||||
}
|
||||
12
lib/components/env/dev_env.dart
vendored
Normal file
12
lib/components/env/dev_env.dart
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
part of '../env.dart';
|
||||
|
||||
///
|
||||
/// DEV сборка
|
||||
///
|
||||
class DevEnv extends Env {
|
||||
@override
|
||||
Uri get url => Uri.parse('https://api.remever.dizoft-studio.ru');
|
||||
|
||||
@override
|
||||
String get mode => 'dev';
|
||||
}
|
||||
12
lib/components/env/prod_env.dart
vendored
Normal file
12
lib/components/env/prod_env.dart
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
part of '../env.dart';
|
||||
|
||||
///
|
||||
/// Продакшн сборка
|
||||
///
|
||||
class ProdEnv extends Env {
|
||||
@override
|
||||
Uri get url => Uri.parse('https://api.remever.dizoft-studio.ru');
|
||||
|
||||
@override
|
||||
String get mode => 'prod';
|
||||
}
|
||||
21
lib/components/extensions/context.dart
Normal file
21
lib/components/extensions/context.dart
Normal file
@@ -0,0 +1,21 @@
|
||||
// Flutter imports:
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
/// Подключение сторонней библиотеки
|
||||
/// Сделано для упрощения чтения импортов
|
||||
export 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
|
||||
///
|
||||
/// Маштабирование в зависимости от контекста
|
||||
///
|
||||
extension ScaleFromContext on BuildContext {
|
||||
///
|
||||
/// Screen Width
|
||||
///
|
||||
double get sw => MediaQuery.of(this).size.width;
|
||||
|
||||
///
|
||||
/// Screen Height
|
||||
///
|
||||
double get sh => MediaQuery.of(this).size.height;
|
||||
}
|
||||
21
lib/components/extensions/duration_extensions.dart
Normal file
21
lib/components/extensions/duration_extensions.dart
Normal file
@@ -0,0 +1,21 @@
|
||||
///
|
||||
/// Расширение для работы с [Duration]
|
||||
///
|
||||
extension AppDuration on Duration {
|
||||
///
|
||||
/// Получение длительности в формате mm:ss
|
||||
///
|
||||
String get mmss => hhmmss.substring('00:'.length);
|
||||
|
||||
///
|
||||
/// Получение длительности в формате HH:mm:ss
|
||||
///
|
||||
String get hhmmss {
|
||||
String twoDigits(int n) => n.toString().padLeft(2, '0');
|
||||
|
||||
String twoDigitMinutes = twoDigits(inMinutes.remainder(60));
|
||||
String twoDigitSeconds = twoDigits(inSeconds.remainder(60));
|
||||
|
||||
return '${twoDigits(inHours)}:$twoDigitMinutes:$twoDigitSeconds';
|
||||
}
|
||||
}
|
||||
26
lib/components/extensions/state.dart
Normal file
26
lib/components/extensions/state.dart
Normal file
@@ -0,0 +1,26 @@
|
||||
// Dart imports:
|
||||
import 'dart:async';
|
||||
|
||||
// Flutter imports:
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
extension StateExtension on State {
|
||||
/// [setState] when it's not building, then wait until next frame built.
|
||||
FutureOr<void> safeSetState(FutureOr<dynamic> Function() fn) async {
|
||||
await fn();
|
||||
if (mounted &&
|
||||
!context.debugDoingBuild &&
|
||||
context.owner?.debugBuilding == false) {
|
||||
// ignore: invalid_use_of_protected_member, no-empty-block
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
final Completer<void> completer = Completer<void>();
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
completer.complete();
|
||||
});
|
||||
|
||||
return completer.future;
|
||||
}
|
||||
}
|
||||
31
lib/components/extensions/string.dart
Normal file
31
lib/components/extensions/string.dart
Normal file
@@ -0,0 +1,31 @@
|
||||
// Flutter imports:
|
||||
import 'package:flutter/material.dart' show Color;
|
||||
|
||||
///
|
||||
/// Расширение для работы со строками
|
||||
///
|
||||
extension MString on String {
|
||||
///
|
||||
/// Слово с заглавной буквы
|
||||
///
|
||||
String capitalyze() {
|
||||
final String str = toLowerCase();
|
||||
final String first = str.substring(0, 1);
|
||||
|
||||
return '${first.toUpperCase()}${str.substring(1)}';
|
||||
}
|
||||
|
||||
///
|
||||
/// Парсинг hex string в color
|
||||
///
|
||||
Color get toColor {
|
||||
String res = replaceFirst('#', '');
|
||||
|
||||
return Color(
|
||||
int.parse(
|
||||
res.length == 8 ? res : (res.length == 6 ? 'FF$res' : res),
|
||||
radix: 16,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
21
lib/components/extensions/theme_mode.dart
Normal file
21
lib/components/extensions/theme_mode.dart
Normal file
@@ -0,0 +1,21 @@
|
||||
// Flutter imports:
|
||||
import 'package:flutter/material.dart' show ThemeMode;
|
||||
|
||||
/// Расширение [ThemeMode]
|
||||
extension ThemModeExtension on ThemeMode {
|
||||
///
|
||||
/// Получение инверсивного [ThemeMode]
|
||||
///
|
||||
ThemeMode get inversed {
|
||||
switch (this) {
|
||||
case ThemeMode.system:
|
||||
return ThemeMode.light;
|
||||
|
||||
case ThemeMode.light:
|
||||
return ThemeMode.dark;
|
||||
|
||||
case ThemeMode.dark:
|
||||
return ThemeMode.light;
|
||||
}
|
||||
}
|
||||
}
|
||||
38
lib/components/listeners/theme_listener.dart
Normal file
38
lib/components/listeners/theme_listener.dart
Normal file
@@ -0,0 +1,38 @@
|
||||
// Flutter imports:
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
// Package imports:
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:hive_ce_flutter/hive_flutter.dart';
|
||||
import 'package:remever/common/storage.dart';
|
||||
import 'package:remever/services/core/theme_service.dart';
|
||||
|
||||
// Project imports:
|
||||
|
||||
/// Описание функции для построения содержимого [ThemeModeListener]
|
||||
typedef ThemeModeBuilder =
|
||||
Widget Function(BuildContext context, ThemeMode themeMode);
|
||||
|
||||
class ThemeModeListener extends StatelessWidget {
|
||||
///
|
||||
/// Слушатель изменений темы
|
||||
///
|
||||
const ThemeModeListener({required this.builder, super.key});
|
||||
|
||||
/// Построитель
|
||||
final ThemeModeBuilder builder;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ThemeService service = GetIt.I.get<ThemeService>();
|
||||
|
||||
return ValueListenableBuilder<Box<ThemeMode>>(
|
||||
valueListenable: hiveTheme.listenable(),
|
||||
builder: (BuildContext context, _, Widget? child) {
|
||||
if (child != null) return child;
|
||||
|
||||
return builder(context, service.themeMode);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
39
lib/components/notifiers/app_settings.dart
Normal file
39
lib/components/notifiers/app_settings.dart
Normal file
@@ -0,0 +1,39 @@
|
||||
// Flutter imports:
|
||||
import 'package:flutter/material.dart' show ChangeNotifier;
|
||||
|
||||
///
|
||||
/// Динамические параметры для конфигурирования приложения
|
||||
///
|
||||
class AppSettingsNotifier extends ChangeNotifier {
|
||||
///
|
||||
/// Динамические параметры для конфигурирования приложения
|
||||
///
|
||||
AppSettingsNotifier({
|
||||
this.debugMode = false,
|
||||
this.showFps = false,
|
||||
});
|
||||
|
||||
/// Включение дебаг мода
|
||||
bool debugMode;
|
||||
|
||||
/// Отображение FPS
|
||||
bool showFps;
|
||||
|
||||
///
|
||||
/// Переключение режима "Дебаг"
|
||||
///
|
||||
void toggleDebugMode() {
|
||||
debugMode = !debugMode;
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
///
|
||||
/// Переключение режима "Дебаг"
|
||||
///
|
||||
void toggleFps() {
|
||||
showFps = !showFps;
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
18
lib/components/notifiers/home_screen_data.dart
Normal file
18
lib/components/notifiers/home_screen_data.dart
Normal file
@@ -0,0 +1,18 @@
|
||||
// Flutter imports:
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
class CollectionData extends ChangeNotifier {
|
||||
CollectionData({this.showFAB = true});
|
||||
|
||||
/// Флаг показа
|
||||
bool showFAB;
|
||||
|
||||
/// Смена состояния показа Fab на экране коллекции
|
||||
void showFab(bool show) {
|
||||
if (showFAB != show) {
|
||||
showFAB = show;
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user