Source Code added
This commit is contained in:
parent
800376eafd
commit
9efa9bc6dd
3912 changed files with 754770 additions and 2 deletions
21
mobile/lib/presentation/pages/dev/main_timeline.page.dart
Normal file
21
mobile/lib/presentation/pages/dev/main_timeline.page.dart
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/memory/memory_lane.widget.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/timeline/timeline.widget.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/memory.provider.dart';
|
||||
|
||||
@RoutePage()
|
||||
class MainTimelinePage extends ConsumerWidget {
|
||||
const MainTimelinePage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final hasMemories = ref.watch(driftMemoryFutureProvider.select((state) => state.value?.isNotEmpty ?? false));
|
||||
return Timeline(
|
||||
topSliverWidget: const SliverToBoxAdapter(child: DriftMemoryLane()),
|
||||
topSliverWidgetHeight: hasMemories ? 200 : 0,
|
||||
showStorageIndicator: true,
|
||||
);
|
||||
}
|
||||
}
|
||||
199
mobile/lib/presentation/pages/dev/media_stat.page.dart
Normal file
199
mobile/lib/presentation/pages/dev/media_stat.page.dart
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/album.provider.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
|
||||
import 'package:immich_mobile/routing/router.dart';
|
||||
|
||||
class _Stat {
|
||||
const _Stat({required this.name, required this.load});
|
||||
|
||||
final String name;
|
||||
final Future<int> Function(Drift _) load;
|
||||
}
|
||||
|
||||
class _Summary extends StatelessWidget {
|
||||
final String name;
|
||||
final Widget? leading;
|
||||
final Future<int> countFuture;
|
||||
final void Function()? onTap;
|
||||
|
||||
const _Summary({required this.name, required this.countFuture, this.leading, this.onTap});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FutureBuilder<int>(
|
||||
future: countFuture,
|
||||
builder: (ctx, snapshot) {
|
||||
final Widget subtitle;
|
||||
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
subtitle = const CircularProgressIndicator();
|
||||
} else if (snapshot.hasError) {
|
||||
subtitle = const Icon(Icons.error_rounded);
|
||||
} else {
|
||||
subtitle = Text('${snapshot.data ?? 0}', style: ctx.textTheme.bodyLarge);
|
||||
}
|
||||
return ListTile(leading: leading, title: Text(name), trailing: subtitle, onTap: onTap);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
final _localStats = [
|
||||
_Stat(name: 'Local Assets', load: (db) => db.managers.localAssetEntity.count()),
|
||||
_Stat(name: 'Local Albums', load: (db) => db.managers.localAlbumEntity.count()),
|
||||
];
|
||||
|
||||
@RoutePage()
|
||||
class LocalMediaSummaryPage extends StatelessWidget {
|
||||
const LocalMediaSummaryPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text('local_media_summary'.tr())),
|
||||
body: Consumer(
|
||||
builder: (ctx, ref, __) {
|
||||
final db = ref.watch(driftProvider);
|
||||
final albumsFuture = ref.watch(localAlbumRepository).getAll();
|
||||
|
||||
return CustomScrollView(
|
||||
slivers: [
|
||||
SliverList.builder(
|
||||
itemBuilder: (_, index) {
|
||||
final stat = _localStats[index];
|
||||
final countFuture = stat.load(db);
|
||||
return _Summary(name: stat.name, countFuture: countFuture);
|
||||
},
|
||||
itemCount: _localStats.length,
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
const Divider(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 15),
|
||||
child: Text("album_summary".tr(), style: ctx.textTheme.titleMedium),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
FutureBuilder(
|
||||
future: albumsFuture,
|
||||
builder: (_, snap) {
|
||||
final albums = snap.data ?? [];
|
||||
if (albums.isEmpty) {
|
||||
return const SliverToBoxAdapter(child: SizedBox.shrink());
|
||||
}
|
||||
|
||||
albums.sortBy((a) => a.name);
|
||||
return SliverList.builder(
|
||||
itemBuilder: (_, index) {
|
||||
final album = albums[index];
|
||||
final countFuture = db.managers.localAlbumAssetEntity
|
||||
.filter((f) => f.albumId.id.equals(album.id))
|
||||
.count();
|
||||
return _Summary(
|
||||
leading: const Icon(Icons.photo_album_rounded),
|
||||
name: album.name,
|
||||
countFuture: countFuture,
|
||||
onTap: () => context.router.push(LocalTimelineRoute(album: album)),
|
||||
);
|
||||
},
|
||||
itemCount: albums.length,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
final _remoteStats = [
|
||||
_Stat(name: 'Remote Assets', load: (db) => db.managers.remoteAssetEntity.count()),
|
||||
_Stat(name: 'Exif Entities', load: (db) => db.managers.remoteExifEntity.count()),
|
||||
_Stat(name: 'Remote Albums', load: (db) => db.managers.remoteAlbumEntity.count()),
|
||||
_Stat(name: 'Memories', load: (db) => db.managers.memoryEntity.count()),
|
||||
_Stat(name: 'Memories Assets', load: (db) => db.managers.memoryAssetEntity.count()),
|
||||
_Stat(name: 'Stacks', load: (db) => db.managers.stackEntity.count()),
|
||||
_Stat(name: 'People', load: (db) => db.managers.personEntity.count()),
|
||||
_Stat(name: 'AssetFaces', load: (db) => db.managers.assetFaceEntity.count()),
|
||||
];
|
||||
|
||||
@RoutePage()
|
||||
class RemoteMediaSummaryPage extends StatelessWidget {
|
||||
const RemoteMediaSummaryPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text('remote_media_summary'.tr())),
|
||||
body: Consumer(
|
||||
builder: (ctx, ref, __) {
|
||||
final db = ref.watch(driftProvider);
|
||||
final albumsFuture = ref.watch(remoteAlbumRepository).getAll();
|
||||
|
||||
return CustomScrollView(
|
||||
slivers: [
|
||||
SliverList.builder(
|
||||
itemBuilder: (_, index) {
|
||||
final stat = _remoteStats[index];
|
||||
final countFuture = stat.load(db);
|
||||
return _Summary(name: stat.name, countFuture: countFuture);
|
||||
},
|
||||
itemCount: _remoteStats.length,
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
const Divider(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 15),
|
||||
child: Text("album_summary".tr(), style: ctx.textTheme.titleMedium),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
FutureBuilder(
|
||||
future: albumsFuture,
|
||||
builder: (_, snap) {
|
||||
final albums = snap.data ?? [];
|
||||
if (albums.isEmpty) {
|
||||
return const SliverToBoxAdapter(child: SizedBox.shrink());
|
||||
}
|
||||
|
||||
albums.sortBy((a) => a.name);
|
||||
return SliverList.builder(
|
||||
itemBuilder: (_, index) {
|
||||
final album = albums[index];
|
||||
final countFuture = db.managers.remoteAlbumAssetEntity
|
||||
.filter((f) => f.albumId.id.equals(album.id))
|
||||
.count();
|
||||
return _Summary(
|
||||
leading: const Icon(Icons.photo_album_rounded),
|
||||
name: album.name,
|
||||
countFuture: countFuture,
|
||||
onTap: () => context.router.push(RemoteAlbumRoute(album: album)),
|
||||
);
|
||||
},
|
||||
itemCount: albums.length,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
100
mobile/lib/presentation/pages/dev/ui_showcase.page.dart
Normal file
100
mobile/lib/presentation/pages/dev/ui_showcase.page.dart
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||
import 'package:immich_ui/immich_ui.dart';
|
||||
|
||||
List<Widget> _showcaseBuilder(Function(ImmichVariant variant, ImmichColor color) builder) {
|
||||
final children = <Widget>[];
|
||||
|
||||
final items = [
|
||||
(variant: ImmichVariant.filled, title: "Filled Variant"),
|
||||
(variant: ImmichVariant.ghost, title: "Ghost Variant"),
|
||||
];
|
||||
|
||||
for (final (:variant, :title) in items) {
|
||||
children.add(Text(title));
|
||||
children.add(Row(spacing: 10, children: [for (var color in ImmichColor.values) builder(variant, color)]));
|
||||
}
|
||||
|
||||
return children;
|
||||
}
|
||||
|
||||
class _ComponentTitle extends StatelessWidget {
|
||||
final String title;
|
||||
|
||||
const _ComponentTitle(this.title);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Text(title, style: context.textTheme.titleLarge);
|
||||
}
|
||||
}
|
||||
|
||||
@RoutePage()
|
||||
class ImmichUIShowcasePage extends StatelessWidget {
|
||||
const ImmichUIShowcasePage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('Immich UI Showcase')),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
spacing: 10,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const _ComponentTitle("IconButton"),
|
||||
..._showcaseBuilder(
|
||||
(variant, color) =>
|
||||
ImmichIconButton(icon: Icons.favorite, color: color, variant: variant, onPressed: () {}),
|
||||
),
|
||||
const _ComponentTitle("CloseButton"),
|
||||
..._showcaseBuilder(
|
||||
(variant, color) => ImmichCloseButton(color: color, variant: variant, onPressed: () {}),
|
||||
),
|
||||
const _ComponentTitle("TextButton"),
|
||||
|
||||
ImmichTextButton(
|
||||
labelText: "Text Button",
|
||||
onPressed: () {},
|
||||
variant: ImmichVariant.filled,
|
||||
color: ImmichColor.primary,
|
||||
),
|
||||
ImmichTextButton(
|
||||
labelText: "Text Button",
|
||||
onPressed: () {},
|
||||
variant: ImmichVariant.filled,
|
||||
color: ImmichColor.primary,
|
||||
loading: true,
|
||||
),
|
||||
ImmichTextButton(
|
||||
labelText: "Text Button",
|
||||
onPressed: () {},
|
||||
variant: ImmichVariant.ghost,
|
||||
color: ImmichColor.primary,
|
||||
),
|
||||
ImmichTextButton(
|
||||
labelText: "Text Button",
|
||||
onPressed: () {},
|
||||
variant: ImmichVariant.ghost,
|
||||
color: ImmichColor.primary,
|
||||
loading: true,
|
||||
),
|
||||
const _ComponentTitle("Form"),
|
||||
ImmichForm(
|
||||
onSubmit: () {},
|
||||
child: const Column(
|
||||
spacing: 10,
|
||||
children: [ImmichTextInput(label: "Title", hintText: "Enter a title")],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue