mirror of
https://github.com/immich-app/immich.git
synced 2025-07-08 18:54:18 -04:00
replace bloc with watch_it
This commit is contained in:
parent
aa5673bae3
commit
fb6253d2d1
@ -15,4 +15,9 @@ dart_code_metrics:
|
|||||||
- recommended
|
- recommended
|
||||||
rules:
|
rules:
|
||||||
- prefer-match-file-name: false
|
- prefer-match-file-name: false
|
||||||
- avoid-passing-self-as-argument: false
|
- avoid-passing-self-as-argument:
|
||||||
|
exclude:
|
||||||
|
- lib/domain/repositories/**
|
||||||
|
- prefer-single-widget-per-file:
|
||||||
|
ignore-private-widgets: true
|
||||||
|
- prefer-correct-callback-field-name: false
|
||||||
|
8
mobile-v2/assets/i18n/strings.i18n.json
Normal file
8
mobile-v2/assets/i18n/strings.i18n.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"tab_controller": {
|
||||||
|
"photos": "Photos",
|
||||||
|
"search": "Search",
|
||||||
|
"sharing": "Sharing",
|
||||||
|
"library": "Library"
|
||||||
|
}
|
||||||
|
}
|
@ -27,4 +27,11 @@ targets:
|
|||||||
#autoroute @AutoRouterConfig()
|
#autoroute @AutoRouterConfig()
|
||||||
auto_route_generator:auto_router_generator:
|
auto_route_generator:auto_router_generator:
|
||||||
generate_for:
|
generate_for:
|
||||||
- lib/presentation/router.dart
|
- lib/presentation/router/router.dart
|
||||||
|
#localization
|
||||||
|
slang_build_runner:
|
||||||
|
options:
|
||||||
|
fallback_strategy: base_locale_empty_string
|
||||||
|
input_directory: assets/i18n
|
||||||
|
output_directory: lib/i18n
|
||||||
|
timestamp: false
|
||||||
|
@ -45,5 +45,11 @@
|
|||||||
<true/>
|
<true/>
|
||||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<!-- Localization -->
|
||||||
|
<key>CFBundleLocalizations</key>
|
||||||
|
<array>
|
||||||
|
<string>en</string>
|
||||||
|
</array>
|
||||||
|
<!-- /Localization -->
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
@ -5,7 +5,7 @@ import 'package:immich_mobile/domain/models/store.model.dart';
|
|||||||
abstract class IStoreRepository {
|
abstract class IStoreRepository {
|
||||||
FutureOr<T?> getValue<T>(StoreKey key);
|
FutureOr<T?> getValue<T>(StoreKey key);
|
||||||
|
|
||||||
FutureOr<void> setValue<T>(StoreKey<T> key, T value);
|
FutureOr<void> setValue<T>(StoreKey key, T value);
|
||||||
|
|
||||||
FutureOr<void> deleteValue(StoreKey key);
|
FutureOr<void> deleteValue(StoreKey key);
|
||||||
|
|
||||||
|
10
mobile-v2/lib/domain/models/app_setting.model.dart
Normal file
10
mobile-v2/lib/domain/models/app_setting.model.dart
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||||
|
|
||||||
|
enum AppSettings<T> {
|
||||||
|
appTheme<int>(StoreKey.appTheme, 10);
|
||||||
|
|
||||||
|
const AppSettings(this.storeKey, this.defaultValue);
|
||||||
|
|
||||||
|
final StoreKey storeKey;
|
||||||
|
final T defaultValue;
|
||||||
|
}
|
@ -1,10 +1,7 @@
|
|||||||
/// Key for each possible value in the `Store`.
|
/// Key for each possible value in the `Store`.
|
||||||
/// Defines the data type for each value
|
/// Defines the data type for each value
|
||||||
enum StoreKey<T> {
|
enum StoreKey {
|
||||||
// Server endpoint related stores
|
appTheme(1000, type: int);
|
||||||
accessToken<String>(0, type: String),
|
|
||||||
serverEndpoint<String>(1, type: String),
|
|
||||||
;
|
|
||||||
|
|
||||||
const StoreKey(this.id, {required this.type});
|
const StoreKey(this.id, {required this.type});
|
||||||
final int id;
|
final int id;
|
||||||
@ -45,7 +42,7 @@ class StoreValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static StoreValue of<T>(StoreKey<T> key, T? value) {
|
static StoreValue of<T>(StoreKey key, T? value) {
|
||||||
int? i;
|
int? i;
|
||||||
String? s;
|
String? s;
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ class StoreDriftRepository implements IStoreRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
FutureOr<void> setValue<T>(StoreKey<T> key, T value) {
|
FutureOr<void> setValue<T>(StoreKey key, T value) {
|
||||||
return db.transaction(() async {
|
return db.transaction(() async {
|
||||||
final storeValue = StoreValue.of(key, value);
|
final storeValue = StoreValue.of(key, value);
|
||||||
await db.into(db.store).insertOnConflictUpdate(StoreCompanion.insert(
|
await db.into(db.store).insertOnConflictUpdate(StoreCompanion.insert(
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
import 'package:get_it/get_it.dart';
|
|
||||||
import 'package:immich_mobile/domain/interfaces/log.interface.dart';
|
|
||||||
import 'package:immich_mobile/domain/interfaces/store.interface.dart';
|
|
||||||
import 'package:immich_mobile/domain/repositories/database.repository.dart';
|
|
||||||
import 'package:immich_mobile/domain/repositories/log.repository.dart';
|
|
||||||
import 'package:immich_mobile/domain/repositories/store.repository.dart';
|
|
||||||
import 'package:immich_mobile/domain/store_manager.dart';
|
|
||||||
|
|
||||||
/// Ambient instance
|
|
||||||
final getIt = GetIt.instance;
|
|
||||||
|
|
||||||
class ServiceLocator {
|
|
||||||
const ServiceLocator._internal();
|
|
||||||
|
|
||||||
static void configureServices() {
|
|
||||||
// Register DB
|
|
||||||
getIt.registerSingleton<DriftDatabaseRepository>(DriftDatabaseRepository());
|
|
||||||
_registerCoreServices();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _registerCoreServices() {
|
|
||||||
// Init store
|
|
||||||
getIt
|
|
||||||
.registerFactory<IStoreRepository>(() => StoreDriftRepository(getIt()));
|
|
||||||
getIt.registerSingleton<StoreManager>(StoreManager(getIt()));
|
|
||||||
// Logs
|
|
||||||
getIt.registerFactory<ILogRepository>(() => LogDriftRepository(getIt()));
|
|
||||||
}
|
|
||||||
}
|
|
22
mobile-v2/lib/domain/services/app_setting.service.dart
Normal file
22
mobile-v2/lib/domain/services/app_setting.service.dart
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import 'package:immich_mobile/domain/models/app_setting.model.dart';
|
||||||
|
import 'package:immich_mobile/domain/store_manager.dart';
|
||||||
|
|
||||||
|
class AppSettingsService {
|
||||||
|
final StoreManager store;
|
||||||
|
|
||||||
|
const AppSettingsService(this.store);
|
||||||
|
|
||||||
|
T getSetting<T>(AppSettings<T> setting) {
|
||||||
|
return store.get(setting.storeKey, setting.defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSetting<T>(AppSettings<T> setting, T value) {
|
||||||
|
store.put(setting.storeKey, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<T> watchSetting<T>(AppSettings<T> setting) {
|
||||||
|
return store
|
||||||
|
.watch<T>(setting.storeKey)
|
||||||
|
.map((value) => value ?? setting.defaultValue);
|
||||||
|
}
|
||||||
|
}
|
@ -55,11 +55,11 @@ class StoreManager with LogContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the stored value for the given key (possibly null)
|
/// Returns the stored value for the given key (possibly null)
|
||||||
T? tryGet<T>(StoreKey<T> key) => _cache[key.id] as T?;
|
T? tryGet<T>(StoreKey key) => _cache[key.id] as T?;
|
||||||
|
|
||||||
/// Returns the stored value for the given key or if null the [defaultValue]
|
/// Returns the stored value for the given key or if null the [defaultValue]
|
||||||
/// Throws a [StoreKeyNotFoundException] if both are null
|
/// Throws a [StoreKeyNotFoundException] if both are null
|
||||||
T get<T>(StoreKey<T> key, [T? defaultValue]) {
|
T get<T>(StoreKey key, [T? defaultValue]) {
|
||||||
final value = _cache[key.id] ?? defaultValue;
|
final value = _cache[key.id] ?? defaultValue;
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
throw StoreKeyNotFoundException(key);
|
throw StoreKeyNotFoundException(key);
|
||||||
@ -68,17 +68,17 @@ class StoreManager with LogContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Watches a specific key for changes
|
/// Watches a specific key for changes
|
||||||
Stream<T?> watch<T>(StoreKey<T> key) => _db.watchValue(key);
|
Stream<T?> watch<T>(StoreKey key) => _db.watchValue(key);
|
||||||
|
|
||||||
/// Stores the value synchronously in the cache and asynchronously in the DB
|
/// Stores the value synchronously in the cache and asynchronously in the DB
|
||||||
FutureOr<void> put<T>(StoreKey<T> key, T value) async {
|
FutureOr<void> put<T>(StoreKey key, T value) async {
|
||||||
if (_cache[key.id] == value) return Future.value();
|
if (_cache[key.id] == value) return Future.value();
|
||||||
_cache[key.id] = value;
|
_cache[key.id] = value;
|
||||||
return await _db.setValue(key, value);
|
return await _db.setValue(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes the value synchronously from the cache and asynchronously from the DB
|
/// Removes the value synchronously from the cache and asynchronously from the DB
|
||||||
Future<void> delete<T>(StoreKey<T> key) async {
|
Future<void> delete(StoreKey key) async {
|
||||||
if (_cache[key.id] == null) return Future.value();
|
if (_cache[key.id] == null) return Future.value();
|
||||||
_cache.remove(key.id);
|
_cache.remove(key.id);
|
||||||
return await _db.deleteValue(key);
|
return await _db.deleteValue(key);
|
||||||
|
35
mobile-v2/lib/immich_app.dart
Normal file
35
mobile-v2/lib/immich_app.dart
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||||
|
import 'package:immich_mobile/i18n/strings.g.dart';
|
||||||
|
import 'package:immich_mobile/presentation/router/router.dart';
|
||||||
|
import 'package:watch_it/watch_it.dart';
|
||||||
|
|
||||||
|
class ImmichApp extends StatefulWidget {
|
||||||
|
final ThemeData lightTheme;
|
||||||
|
final ThemeData darkTheme;
|
||||||
|
|
||||||
|
const ImmichApp({
|
||||||
|
required this.lightTheme,
|
||||||
|
required this.darkTheme,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State createState() => _ImmichAppState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ImmichAppState extends State<ImmichApp> with WidgetsBindingObserver {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final router = di<AppRouter>();
|
||||||
|
|
||||||
|
return MaterialApp.router(
|
||||||
|
locale: TranslationProvider.of(context).flutterLocale,
|
||||||
|
supportedLocales: AppLocaleUtils.supportedLocales,
|
||||||
|
localizationsDelegates: GlobalMaterialLocalizations.delegates,
|
||||||
|
theme: widget.lightTheme,
|
||||||
|
darkTheme: widget.darkTheme,
|
||||||
|
routerConfig: router.config(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,63 +1,33 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:immich_mobile/i18n/strings.g.dart';
|
||||||
import 'package:immich_mobile/domain/service_locator.dart';
|
import 'package:immich_mobile/immich_app.dart';
|
||||||
import 'package:immich_mobile/presentation/home_page/cubit/home_cubit.dart';
|
import 'package:immich_mobile/presentation/theme/states/app_theme.state.dart';
|
||||||
|
import 'package:immich_mobile/presentation/theme/widgets/app_theme_builder.dart';
|
||||||
|
import 'package:immich_mobile/service_locator.dart';
|
||||||
|
import 'package:watch_it/watch_it.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
// Ensure the bindings are initialized
|
// Ensure the bindings are initialized
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
// DI Injection
|
// DI Injection
|
||||||
ServiceLocator.configureServices();
|
ServiceLocator.configureServices();
|
||||||
|
// Init localization
|
||||||
|
LocaleSettings.useDeviceLocale();
|
||||||
runApp(const MainWidget());
|
runApp(const MainWidget());
|
||||||
}
|
}
|
||||||
|
|
||||||
class MainWidget extends StatelessWidget {
|
class MainWidget extends StatelessWidget with WatchItMixin {
|
||||||
const MainWidget({super.key});
|
const MainWidget({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
final appTheme = watchIt<AppThemeState>().value;
|
||||||
title: 'Flutter Demo',
|
|
||||||
theme: ThemeData(
|
return TranslationProvider(
|
||||||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
|
child: AppThemeBuilder(
|
||||||
useMaterial3: true,
|
theme: appTheme,
|
||||||
),
|
builder: (lightTheme, darkTheme) =>
|
||||||
home: MultiBlocProvider(
|
ImmichApp(lightTheme: lightTheme, darkTheme: darkTheme),
|
||||||
providers: [BlocProvider(create: (context) => HomeCubit())],
|
|
||||||
child: Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: const Text("Immich v2"),
|
|
||||||
),
|
|
||||||
body: BlocConsumer<HomeCubit, HomeState>(
|
|
||||||
listener: (context, state) {
|
|
||||||
print(state);
|
|
||||||
},
|
|
||||||
builder: (context, state) {
|
|
||||||
return Center(
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Text("Album count: ${state.albumCount}"),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
context.read<HomeCubit>().increaseAlbumCount();
|
|
||||||
},
|
|
||||||
child: const Text("Increase"),
|
|
||||||
),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
context.read<HomeCubit>().decreaseAlbumCount();
|
|
||||||
},
|
|
||||||
child: const Text("Decrease"),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
import 'package:bloc/bloc.dart';
|
|
||||||
|
|
||||||
part 'home_state.dart';
|
|
||||||
|
|
||||||
class HomeCubit extends Cubit<HomeState> {
|
|
||||||
HomeCubit() : super(HomeState(albumCount: 0));
|
|
||||||
|
|
||||||
void increaseAlbumCount() {
|
|
||||||
emit(state.copyWith(albumCount: state.albumCount + 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
void decreaseAlbumCount() {
|
|
||||||
emit(state.copyWith(albumCount: state.albumCount - 1));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
part of 'home_cubit.dart';
|
|
||||||
|
|
||||||
class HomeState {
|
|
||||||
final int albumCount;
|
|
||||||
HomeState({
|
|
||||||
required this.albumCount,
|
|
||||||
});
|
|
||||||
|
|
||||||
HomeState copyWith({
|
|
||||||
int? albumCount,
|
|
||||||
}) {
|
|
||||||
return HomeState(
|
|
||||||
albumCount: albumCount ?? this.albumCount,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, dynamic> toMap() {
|
|
||||||
return {
|
|
||||||
'albumCount': albumCount,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
factory HomeState.fromMap(Map<String, dynamic> map) {
|
|
||||||
return HomeState(
|
|
||||||
albumCount: map['albumCount']?.toInt() ?? 0,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() => 'HomeState(albumCount: $albumCount)';
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
if (identical(this, other)) return true;
|
|
||||||
|
|
||||||
return other is HomeState && other.albumCount == albumCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode => albumCount.hashCode;
|
|
||||||
}
|
|
12
mobile-v2/lib/presentation/modules/home/pages/home.page.dart
Normal file
12
mobile-v2/lib/presentation/modules/home/pages/home.page.dart
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import 'package:auto_route/auto_route.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
@RoutePage()
|
||||||
|
class HomePage extends StatelessWidget {
|
||||||
|
const HomePage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
import 'package:auto_route/auto_route.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
@RoutePage()
|
||||||
|
class LibraryPage extends StatelessWidget {
|
||||||
|
const LibraryPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
import 'package:auto_route/auto_route.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
@RoutePage()
|
||||||
|
class SearchPage extends StatelessWidget {
|
||||||
|
const SearchPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
import 'package:auto_route/auto_route.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
@RoutePage()
|
||||||
|
class SettingsPage extends StatelessWidget {
|
||||||
|
const SettingsPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
import 'package:auto_route/auto_route.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
@RoutePage()
|
||||||
|
class SharingPage extends StatelessWidget {
|
||||||
|
const SharingPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +0,0 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
|
|
||||||
part 'router.gr.dart';
|
|
||||||
|
|
||||||
@AutoRouterConfig(replaceInRouteName: 'Page,Route')
|
|
||||||
class AppRouter extends _$AppRouter {
|
|
||||||
@override
|
|
||||||
List<AutoRoute> get routes => [];
|
|
||||||
}
|
|
132
mobile-v2/lib/presentation/router/pages/tab_controller.page.dart
Normal file
132
mobile-v2/lib/presentation/router/pages/tab_controller.page.dart
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
import 'package:auto_route/auto_route.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_adaptive_scaffold/flutter_adaptive_scaffold.dart';
|
||||||
|
import 'package:immich_mobile/i18n/strings.g.dart';
|
||||||
|
import 'package:immich_mobile/presentation/router/router.dart';
|
||||||
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
|
|
||||||
|
@RoutePage()
|
||||||
|
class TabControllerPage extends StatelessWidget {
|
||||||
|
const TabControllerPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AutoTabsRouter(
|
||||||
|
routes: const [
|
||||||
|
HomeRoute(),
|
||||||
|
SearchRoute(),
|
||||||
|
SharingRoute(),
|
||||||
|
LibraryRoute(),
|
||||||
|
],
|
||||||
|
builder: (ctx, child) {
|
||||||
|
final tabsRouter = AutoTabsRouter.of(ctx);
|
||||||
|
// Pop-back to photos tab or if already in photos tab, close the app
|
||||||
|
return PopScope(
|
||||||
|
canPop: tabsRouter.activeIndex == 0,
|
||||||
|
onPopInvoked: (didPop) =>
|
||||||
|
!didPop ? tabsRouter.setActiveIndex(0) : null,
|
||||||
|
child: _TabControllerAdaptiveScaffold(
|
||||||
|
body: (ctxx) => child,
|
||||||
|
selectedIndex: tabsRouter.activeIndex,
|
||||||
|
onSelectedIndexChange: (index) => tabsRouter.setActiveIndex(index),
|
||||||
|
destinations: [
|
||||||
|
NavigationDestination(
|
||||||
|
icon: const Icon(Symbols.photo_rounded),
|
||||||
|
selectedIcon: const Icon(Symbols.photo_rounded, fill: 1.0),
|
||||||
|
label: context.t.tab_controller.photos,
|
||||||
|
),
|
||||||
|
NavigationDestination(
|
||||||
|
icon: const Icon(Symbols.search_rounded),
|
||||||
|
selectedIcon: const Icon(Symbols.search_rounded, fill: 1.0),
|
||||||
|
label: context.t.tab_controller.search,
|
||||||
|
),
|
||||||
|
NavigationDestination(
|
||||||
|
icon: const Icon(Symbols.group_rounded),
|
||||||
|
selectedIcon: const Icon(Symbols.group_rounded, fill: 1.0),
|
||||||
|
label: context.t.tab_controller.sharing,
|
||||||
|
),
|
||||||
|
NavigationDestination(
|
||||||
|
icon: const Icon(Symbols.newsstand_rounded),
|
||||||
|
selectedIcon: const Icon(Symbols.newsstand_rounded, fill: 1.0),
|
||||||
|
label: context.t.tab_controller.library,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adaptive scaffold to layout bottom navigation bar and navigation rail for the main
|
||||||
|
/// tab controller layout. This is not used elsewhere so is private to this widget
|
||||||
|
class _TabControllerAdaptiveScaffold extends StatelessWidget {
|
||||||
|
const _TabControllerAdaptiveScaffold({
|
||||||
|
required this.body,
|
||||||
|
required this.selectedIndex,
|
||||||
|
required this.onSelectedIndexChange,
|
||||||
|
required this.destinations,
|
||||||
|
});
|
||||||
|
|
||||||
|
final WidgetBuilder body;
|
||||||
|
final List<NavigationDestination> destinations;
|
||||||
|
final int selectedIndex;
|
||||||
|
final void Function(int) onSelectedIndexChange;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final NavigationRailThemeData navRailTheme =
|
||||||
|
Theme.of(context).navigationRailTheme;
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
body: AdaptiveLayout(
|
||||||
|
// No animation on layout change
|
||||||
|
transitionDuration: Duration.zero,
|
||||||
|
primaryNavigation: SlotLayout(
|
||||||
|
config: <Breakpoint, SlotLayoutConfig>{
|
||||||
|
Breakpoints.mediumAndUp: SlotLayout.from(
|
||||||
|
key: const Key(
|
||||||
|
'_TabControllerAdaptiveScaffold Primary Navigation Medium',
|
||||||
|
),
|
||||||
|
builder: (_) => AdaptiveScaffold.standardNavigationRail(
|
||||||
|
selectedIndex: selectedIndex,
|
||||||
|
destinations: destinations
|
||||||
|
.map((NavigationDestination destination) =>
|
||||||
|
AdaptiveScaffold.toRailDestination(destination))
|
||||||
|
.toList(),
|
||||||
|
onDestinationSelected: onSelectedIndexChange,
|
||||||
|
backgroundColor: navRailTheme.backgroundColor,
|
||||||
|
selectedIconTheme: navRailTheme.selectedIconTheme,
|
||||||
|
unselectedIconTheme: navRailTheme.unselectedIconTheme,
|
||||||
|
selectedLabelTextStyle: navRailTheme.selectedLabelTextStyle,
|
||||||
|
unSelectedLabelTextStyle: navRailTheme.unselectedLabelTextStyle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
body: SlotLayout(
|
||||||
|
config: {
|
||||||
|
Breakpoints.standard: SlotLayout.from(
|
||||||
|
key: const Key('_TabControllerAdaptiveScaffold Body'),
|
||||||
|
builder: body,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
bottomNavigationBar: SlotLayout(
|
||||||
|
config: <Breakpoint, SlotLayoutConfig>{
|
||||||
|
Breakpoints.small: SlotLayout.from(
|
||||||
|
key: const Key(
|
||||||
|
'_TabControllerAdaptiveScaffold Bottom Navigation Small',
|
||||||
|
),
|
||||||
|
builder: (_) => AdaptiveScaffold.standardBottomNavigationBar(
|
||||||
|
currentIndex: selectedIndex,
|
||||||
|
destinations: destinations,
|
||||||
|
onDestinationSelected: onSelectedIndexChange,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
25
mobile-v2/lib/presentation/router/router.dart
Normal file
25
mobile-v2/lib/presentation/router/router.dart
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import 'package:auto_route/auto_route.dart';
|
||||||
|
import 'package:immich_mobile/presentation/modules/home/pages/home.page.dart';
|
||||||
|
import 'package:immich_mobile/presentation/modules/library/pages/library.page.dart';
|
||||||
|
import 'package:immich_mobile/presentation/modules/search/pages/search.page.dart';
|
||||||
|
import 'package:immich_mobile/presentation/modules/settings/pages/settings.page.dart';
|
||||||
|
import 'package:immich_mobile/presentation/modules/sharing/pages/sharing.page.dart';
|
||||||
|
import 'package:immich_mobile/presentation/router/pages/tab_controller.page.dart';
|
||||||
|
|
||||||
|
part 'router.gr.dart';
|
||||||
|
|
||||||
|
@AutoRouterConfig(replaceInRouteName: 'Page,Route')
|
||||||
|
class AppRouter extends _$AppRouter {
|
||||||
|
AppRouter();
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<AutoRoute> get routes => [
|
||||||
|
AutoRoute(page: TabControllerRoute.page, initial: true, children: [
|
||||||
|
AutoRoute(page: HomeRoute.page),
|
||||||
|
AutoRoute(page: SearchRoute.page),
|
||||||
|
AutoRoute(page: SharingRoute.page),
|
||||||
|
AutoRoute(page: LibraryRoute.page),
|
||||||
|
]),
|
||||||
|
AutoRoute(page: SettingsRoute.page),
|
||||||
|
];
|
||||||
|
}
|
30
mobile-v2/lib/presentation/theme/states/app_theme.state.dart
Normal file
30
mobile-v2/lib/presentation/theme/states/app_theme.state.dart
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/app_setting.model.dart';
|
||||||
|
import 'package:immich_mobile/domain/services/app_setting.service.dart';
|
||||||
|
import 'package:immich_mobile/presentation/theme/utils/colors.dart';
|
||||||
|
|
||||||
|
class AppThemeState extends ValueNotifier<AppTheme> {
|
||||||
|
final AppSettingsService _appSettings;
|
||||||
|
StreamSubscription? _appSettingSubscription;
|
||||||
|
|
||||||
|
AppThemeState({required AppSettingsService appSettings})
|
||||||
|
: _appSettings = appSettings,
|
||||||
|
super(AppTheme.blue);
|
||||||
|
|
||||||
|
void init() {
|
||||||
|
_appSettingSubscription =
|
||||||
|
_appSettings.watchSetting(AppSettings.appTheme).listen((themeIndex) {
|
||||||
|
final theme =
|
||||||
|
AppTheme.values.elementAtOrNull(themeIndex) ?? AppTheme.blue;
|
||||||
|
value = theme;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_appSettingSubscription?.cancel();
|
||||||
|
return super.dispose();
|
||||||
|
}
|
||||||
|
}
|
92
mobile-v2/lib/presentation/theme/utils/colors.dart
Normal file
92
mobile-v2/lib/presentation/theme/utils/colors.dart
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
enum AppTheme {
|
||||||
|
blue(AppColors._blueLight, AppColors._blueDark),
|
||||||
|
// Fallback color for dynamic theme for non-supported platforms
|
||||||
|
dynamic(AppColors._blueLight, AppColors._blueDark);
|
||||||
|
|
||||||
|
final ColorScheme lightSchema;
|
||||||
|
final ColorScheme darkSchema;
|
||||||
|
|
||||||
|
const AppTheme(this.lightSchema, this.darkSchema);
|
||||||
|
}
|
||||||
|
|
||||||
|
class AppColors {
|
||||||
|
const AppColors();
|
||||||
|
|
||||||
|
/// Blue color
|
||||||
|
static const ColorScheme _blueLight = ColorScheme(
|
||||||
|
brightness: Brightness.light,
|
||||||
|
primary: Color(0xff1565c0),
|
||||||
|
onPrimary: Color(0xffffffff),
|
||||||
|
primaryContainer: Color(0xffd6e3ff),
|
||||||
|
onPrimaryContainer: Color(0xff001b3d),
|
||||||
|
secondary: Color(0xff3277d2),
|
||||||
|
onSecondary: Color(0xfffdfbff),
|
||||||
|
secondaryContainer: Color(0xffecf0ff),
|
||||||
|
onSecondaryContainer: Color(0xff001b3d),
|
||||||
|
tertiary: Color(0xff7b4d88),
|
||||||
|
onTertiary: Color(0xfffffbff),
|
||||||
|
tertiaryContainer: Color(0xfffad7ff),
|
||||||
|
onTertiaryContainer: Color(0xff310540),
|
||||||
|
error: Color(0xffba1a1a),
|
||||||
|
onError: Color(0xfffffbff),
|
||||||
|
errorContainer: Color(0xffffdad6),
|
||||||
|
onErrorContainer: Color(0xff410002),
|
||||||
|
background: Color(0xfffcfafe),
|
||||||
|
onBackground: Color(0xff191c20),
|
||||||
|
surface: Color(0xfffdfbff),
|
||||||
|
onSurface: Color(0xff191c20),
|
||||||
|
surfaceVariant: Color(0xffdfe2ef),
|
||||||
|
onSurfaceVariant: Color(0xff424751),
|
||||||
|
outline: Color(0xff737782),
|
||||||
|
outlineVariant: Color(0xffc2c6d2),
|
||||||
|
shadow: Color(0xff000000),
|
||||||
|
scrim: Color(0xff000000),
|
||||||
|
inverseSurface: Color(0xff2e3036),
|
||||||
|
onInverseSurface: Color(0xfff0f0f7),
|
||||||
|
inversePrimary: Color(0xffa9c7ff),
|
||||||
|
surfaceTint: Color(0xff00468c),
|
||||||
|
);
|
||||||
|
|
||||||
|
static const ColorScheme _blueDark = ColorScheme(
|
||||||
|
brightness: Brightness.dark,
|
||||||
|
primary: Color(0xffa9c7ff),
|
||||||
|
onPrimary: Color(0xff001b3d),
|
||||||
|
primaryContainer: Color(0xff00468c),
|
||||||
|
onPrimaryContainer: Color(0xffd6e3ff),
|
||||||
|
secondary: Color(0xffd6e3ff),
|
||||||
|
onSecondary: Color(0xff001b3d),
|
||||||
|
secondaryContainer: Color(0xff003063),
|
||||||
|
onSecondaryContainer: Color(0xffd6e3ff),
|
||||||
|
tertiary: Color(0xffeab4f6),
|
||||||
|
onTertiary: Color(0xff310540),
|
||||||
|
tertiaryContainer: Color(0xff61356e),
|
||||||
|
onTertiaryContainer: Color(0xfffad7ff),
|
||||||
|
error: Color(0xffffb4ab),
|
||||||
|
onError: Color(0xff410002),
|
||||||
|
errorContainer: Color(0xff93000a),
|
||||||
|
onErrorContainer: Color(0xffffb4ab),
|
||||||
|
background: Color(0xff1a1d21),
|
||||||
|
onBackground: Color(0xffe2e2e9),
|
||||||
|
surface: Color(0xff1a1e22),
|
||||||
|
onSurface: Color(0xffe2e2e9),
|
||||||
|
surfaceVariant: Color(0xff424852),
|
||||||
|
onSurfaceVariant: Color(0xffc2c6d2),
|
||||||
|
outline: Color(0xff8c919c),
|
||||||
|
outlineVariant: Color(0xff424751),
|
||||||
|
shadow: Color(0xff000000),
|
||||||
|
scrim: Color(0xff000000),
|
||||||
|
inverseSurface: Color(0xffe1e1e9),
|
||||||
|
onInverseSurface: Color(0xff2e3036),
|
||||||
|
inversePrimary: Color(0xff005db7),
|
||||||
|
surfaceTint: Color(0xffa9c7ff),
|
||||||
|
);
|
||||||
|
|
||||||
|
static ThemeData getThemeForColorScheme(ColorScheme color) {
|
||||||
|
return ThemeData(
|
||||||
|
primaryColor: color.primary,
|
||||||
|
iconTheme: const IconThemeData(weight: 400),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
import 'package:dynamic_color/dynamic_color.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:immich_mobile/presentation/theme/utils/colors.dart';
|
||||||
|
|
||||||
|
class AppThemeBuilder extends StatelessWidget {
|
||||||
|
const AppThemeBuilder({
|
||||||
|
super.key,
|
||||||
|
required this.theme,
|
||||||
|
required this.builder,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// Current app theme to switch the theme data used
|
||||||
|
final AppTheme theme;
|
||||||
|
|
||||||
|
/// Builds the child widget of this widget, providing a light and dark [ThemeData] based on the
|
||||||
|
/// [theme] passed.
|
||||||
|
final Widget Function(ThemeData lightTheme, ThemeData darkTheme) builder;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
// Static colors
|
||||||
|
if (theme != AppTheme.dynamic) {
|
||||||
|
final lightTheme = AppColors.getThemeForColorScheme(theme.lightSchema);
|
||||||
|
final darkTheme = AppColors.getThemeForColorScheme(theme.darkSchema);
|
||||||
|
|
||||||
|
return builder(lightTheme, darkTheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dynamic color builder
|
||||||
|
return DynamicColorBuilder(builder: (lightDynamic, darkDynamic) {
|
||||||
|
final lightTheme =
|
||||||
|
AppColors.getThemeForColorScheme(lightDynamic ?? theme.lightSchema);
|
||||||
|
final darkTheme =
|
||||||
|
AppColors.getThemeForColorScheme(darkDynamic ?? theme.darkSchema);
|
||||||
|
|
||||||
|
return builder(lightTheme, darkTheme);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
40
mobile-v2/lib/service_locator.dart
Normal file
40
mobile-v2/lib/service_locator.dart
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import 'package:immich_mobile/domain/interfaces/log.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/store.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/repositories/database.repository.dart';
|
||||||
|
import 'package:immich_mobile/domain/repositories/log.repository.dart';
|
||||||
|
import 'package:immich_mobile/domain/repositories/store.repository.dart';
|
||||||
|
import 'package:immich_mobile/domain/services/app_setting.service.dart';
|
||||||
|
import 'package:immich_mobile/domain/store_manager.dart';
|
||||||
|
import 'package:immich_mobile/presentation/router/router.dart';
|
||||||
|
import 'package:immich_mobile/presentation/theme/states/app_theme.state.dart';
|
||||||
|
import 'package:watch_it/watch_it.dart';
|
||||||
|
|
||||||
|
class ServiceLocator {
|
||||||
|
const ServiceLocator._internal();
|
||||||
|
|
||||||
|
static void configureServices() {
|
||||||
|
// Register DB
|
||||||
|
di.registerSingleton<DriftDatabaseRepository>(DriftDatabaseRepository());
|
||||||
|
_registerDomainServices();
|
||||||
|
_registerPresentationService();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _registerDomainServices() {
|
||||||
|
// Init store
|
||||||
|
di.registerFactory<IStoreRepository>(() => StoreDriftRepository(di()));
|
||||||
|
di.registerSingleton<StoreManager>(StoreManager(di()));
|
||||||
|
// Logs
|
||||||
|
di.registerFactory<ILogRepository>(() => LogDriftRepository(di()));
|
||||||
|
// App Settings
|
||||||
|
di.registerFactory<AppSettingsService>(() => AppSettingsService(di()));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _registerPresentationService() {
|
||||||
|
// App router
|
||||||
|
di.registerSingleton<AppRouter>(AppRouter());
|
||||||
|
// Global states
|
||||||
|
di.registerLazySingleton<AppThemeState>(
|
||||||
|
() => AppThemeState(appSettings: di())..init(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -57,14 +57,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.0.0"
|
version: "8.0.0"
|
||||||
bloc:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: bloc
|
|
||||||
sha256: "106842ad6569f0b60297619e9e0b1885c2fb9bf84812935490e6c5275777804e"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "8.1.4"
|
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -209,6 +201,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.3"
|
version: "3.0.3"
|
||||||
|
csv:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: csv
|
||||||
|
sha256: c6aa2679b2a18cb57652920f674488d89712efaf4d3fdf2e537215b35fc19d6c
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.0.0"
|
||||||
dart_style:
|
dart_style:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -220,21 +220,27 @@ packages:
|
|||||||
drift:
|
drift:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
path: drift
|
name: drift
|
||||||
ref: develop
|
sha256: "6acedc562ffeed308049f78fb1906abad3d65714580b6745441ee6d50ec564cd"
|
||||||
resolved-ref: a1af6f6114960caaee6a9d7699e27f92cc8c93dc
|
url: "https://pub.dev"
|
||||||
url: "https://github.com/simolus3/drift.git"
|
source: hosted
|
||||||
source: git
|
version: "2.18.0"
|
||||||
version: "2.18.0-dev"
|
|
||||||
drift_dev:
|
drift_dev:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
path: drift_dev
|
name: drift_dev
|
||||||
ref: develop
|
sha256: d9b020736ea85fff1568699ce18b89fabb3f0f042e8a7a05e84a3ec20d39acde
|
||||||
resolved-ref: a1af6f6114960caaee6a9d7699e27f92cc8c93dc
|
url: "https://pub.dev"
|
||||||
url: "https://github.com/simolus3/drift.git"
|
source: hosted
|
||||||
source: git
|
version: "2.18.0"
|
||||||
version: "2.18.0-dev"
|
dynamic_color:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: dynamic_color
|
||||||
|
sha256: eae98052fa6e2826bdac3dd2e921c6ce2903be15c6b7f8b6d8a5d49b5086298d
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.7.0"
|
||||||
fake_async:
|
fake_async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -272,22 +278,14 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
flutter_bloc:
|
flutter_adaptive_scaffold:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_bloc
|
name: flutter_adaptive_scaffold
|
||||||
sha256: f0ecf6e6eb955193ca60af2d5ca39565a86b8a142452c5b24d96fb477428f4d2
|
sha256: "9a1d5e9f728815e27b7b612883db19107ba8a35a46a97c757ea00896cb027451"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.1.5"
|
version: "0.1.10+2"
|
||||||
flutter_hooks:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: flutter_hooks
|
|
||||||
sha256: cde36b12f7188c85286fba9b38cc5a902e7279f36dd676967106c041dc9dde70
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.20.5"
|
|
||||||
flutter_lints:
|
flutter_lints:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
@ -296,6 +294,11 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.2"
|
version: "3.0.2"
|
||||||
|
flutter_localizations:
|
||||||
|
dependency: "direct main"
|
||||||
|
description: flutter
|
||||||
|
source: sdk
|
||||||
|
version: "0.0.0"
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
@ -309,8 +312,16 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.0"
|
version: "4.0.0"
|
||||||
|
functional_listener:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: functional_listener
|
||||||
|
sha256: "026d1bd4f66367f11d9ec9f1f1ddb42b89e4484b356972c76d983266cf82f33f"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.1"
|
||||||
get_it:
|
get_it:
|
||||||
dependency: "direct main"
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: get_it
|
name: get_it
|
||||||
sha256: d85128a5dae4ea777324730dc65edd9c9f43155c109d5cc0a69cab74139fbac1
|
sha256: d85128a5dae4ea777324730dc65edd9c9f43155c109d5cc0a69cab74139fbac1
|
||||||
@ -349,6 +360,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.2"
|
version: "4.0.2"
|
||||||
|
intl:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: intl
|
||||||
|
sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.18.1"
|
||||||
io:
|
io:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -365,6 +384,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.1"
|
version: "0.7.1"
|
||||||
|
json2yaml:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: json2yaml
|
||||||
|
sha256: da94630fbc56079426fdd167ae58373286f603371075b69bf46d848d63ba3e51
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.1"
|
||||||
json_annotation:
|
json_annotation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -429,6 +456,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.8.0"
|
version: "0.8.0"
|
||||||
|
material_symbols_icons:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: material_symbols_icons
|
||||||
|
sha256: "4410e4bb5c6e16d811340f94532c0b3161d2a0ba60b41d0fa8a603186857cabe"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.2719.3"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -445,14 +480,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.5"
|
version: "1.0.5"
|
||||||
nested:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: nested
|
|
||||||
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.0"
|
|
||||||
package_config:
|
package_config:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -565,14 +592,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.5.1"
|
version: "1.5.1"
|
||||||
provider:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: provider
|
|
||||||
sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "6.1.2"
|
|
||||||
pub_semver:
|
pub_semver:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -618,8 +637,32 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.99"
|
version: "0.0.99"
|
||||||
source_gen:
|
slang:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: slang
|
||||||
|
sha256: ad2a3974fa705017d40e59f9fce5ba738ce78a40c13247bf655d1760d3af018f
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.30.2"
|
||||||
|
slang_build_runner:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: slang_build_runner
|
||||||
|
sha256: "2daff2deb2ab8d557a2e7de5405c0ee1376afba5d0231570c2d2c3c56da8a692"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.30.0"
|
||||||
|
slang_flutter:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: slang_flutter
|
||||||
|
sha256: "9ee040b0d364d3a4d692e4af536acff6ef513870689403494ebc6d59b0dccea6"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.30.0"
|
||||||
|
source_gen:
|
||||||
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: source_gen
|
name: source_gen
|
||||||
sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832"
|
sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832"
|
||||||
@ -651,14 +694,13 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.21"
|
version: "0.5.21"
|
||||||
sqlparser:
|
sqlparser:
|
||||||
dependency: "direct overridden"
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
path: sqlparser
|
name: sqlparser
|
||||||
ref: develop
|
sha256: ade9a67fd70d0369329ed3373208de7ebd8662470e8c396fc8d0d60f9acdfc9f
|
||||||
resolved-ref: a1af6f6114960caaee6a9d7699e27f92cc8c93dc
|
url: "https://pub.dev"
|
||||||
url: "https://github.com/simolus3/drift.git"
|
source: hosted
|
||||||
source: git
|
version: "0.36.0"
|
||||||
version: "0.36.0-dev"
|
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -739,6 +781,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "13.0.0"
|
version: "13.0.0"
|
||||||
|
watch_it:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: watch_it
|
||||||
|
sha256: "9dc3f552d31f6ae121b0de794ab3cdea5d93627fe69337876ebe4b41bfc3729d"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.4.1"
|
||||||
watcher:
|
watcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -10,47 +10,36 @@ environment:
|
|||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
flutter_localizations:
|
||||||
|
sdk: flutter
|
||||||
|
|
||||||
# OS specific path
|
# OS specific path
|
||||||
path_provider: ^2.0.0
|
path_provider: ^2.0.0
|
||||||
path: ^1.9.0
|
path: ^1.9.0
|
||||||
# Database
|
# Database
|
||||||
drift: ^2.17.0
|
drift: ^2.18.0
|
||||||
sqlite3: ^2.4.2
|
sqlite3: ^2.4.2
|
||||||
sqlite3_flutter_libs: ^0.5.0
|
sqlite3_flutter_libs: ^0.5.0
|
||||||
# Route handling
|
# Route handling
|
||||||
auto_route: ^8.1.0
|
auto_route: ^8.1.0
|
||||||
# Logging
|
# Logging
|
||||||
logging: ^1.2.0
|
logging: ^1.2.0
|
||||||
# Hooks
|
|
||||||
flutter_hooks: ^0.20.5
|
|
||||||
# Collection Utils
|
# Collection Utils
|
||||||
collection: ^1.18.0
|
collection: ^1.18.0
|
||||||
# BLOC
|
# get_it / watch_it
|
||||||
flutter_bloc: ^8.1.5
|
watch_it: ^1.4.1
|
||||||
# get_it
|
|
||||||
get_it: ^7.7.0
|
|
||||||
# Photo Manager
|
# Photo Manager
|
||||||
photo_manager: ^3.0.0
|
photo_manager: ^3.0.0
|
||||||
photo_manager_image_provider: ^2.1.0
|
photo_manager_image_provider: ^2.1.0
|
||||||
|
# Dynamic colors - Android
|
||||||
dependency_overrides:
|
dynamic_color: ^1.7.0
|
||||||
# TODO: Remove the drift related overrides once the manager PR change version is released to pub
|
# Material symbols
|
||||||
drift:
|
material_symbols_icons: ^4.2719.3
|
||||||
git:
|
# Localization
|
||||||
url: https://github.com/simolus3/drift.git
|
slang: ^3.30.2
|
||||||
ref: develop
|
slang_flutter: ^3.30.0
|
||||||
path: drift
|
# Adaptive scaffold
|
||||||
drift_dev:
|
flutter_adaptive_scaffold: ^0.1.10+2
|
||||||
git:
|
|
||||||
url: https://github.com/simolus3/drift.git
|
|
||||||
ref: develop
|
|
||||||
path: drift_dev
|
|
||||||
sqlparser:
|
|
||||||
git:
|
|
||||||
url: https://github.com/simolus3/drift.git
|
|
||||||
ref: develop
|
|
||||||
path: sqlparser
|
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
@ -60,11 +49,12 @@ dev_dependencies:
|
|||||||
flutter_lints: ^3.0.0
|
flutter_lints: ^3.0.0
|
||||||
# Code generator
|
# Code generator
|
||||||
build_runner: ^2.4.9
|
build_runner: ^2.4.9
|
||||||
source_gen: ^1.5.0
|
|
||||||
# Database helper
|
# Database helper
|
||||||
drift_dev: ^2.17.0
|
drift_dev: ^2.18.0
|
||||||
# Route helper
|
# Route helper
|
||||||
auto_route_generator: ^8.0.0
|
auto_route_generator: ^8.0.0
|
||||||
|
# Localization generator
|
||||||
|
slang_build_runner: ^3.30.0
|
||||||
|
|
||||||
flutter:
|
flutter:
|
||||||
uses-material-design: true
|
uses-material-design: true
|
||||||
|
Loading…
x
Reference in New Issue
Block a user