immich/mobile/lib/presentation/pages/dev/drift_search.page.dart
2025-07-08 13:00:46 +08:00

314 lines
8.4 KiB
Dart

import 'package:auto_route/auto_route.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/extensions/translate_extensions.dart';
import 'package:immich_mobile/providers/user.provider.dart';
import 'package:immich_mobile/routing/router.dart';
import 'package:immich_mobile/widgets/common/immich_sliver_app_bar.dart';
@RoutePage()
class DriftSearchPage extends ConsumerStatefulWidget {
const DriftSearchPage({super.key});
@override
ConsumerState<DriftSearchPage> createState() => _DriftSearchPageState();
}
class _DriftSearchPageState extends ConsumerState<DriftSearchPage> {
final searchController = TextEditingController();
final searchFocusNode = FocusNode();
@override
void initState() {
super.initState();
}
void onSearch(String searchTerm) {
final userId = ref.watch(currentUserProvider)?.id;
}
void clearSearch() {
}
@override
void dispose() {
searchController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final userId = ref.watch(currentUserProvider)?.id;
return Scaffold(
body: CustomScrollView(
slivers: [
const ImmichSliverAppBar(),
_SearchBar(
searchController: searchController,
searchFocusNode: searchFocusNode,
onClearSearch: clearSearch,
),
const _SearchFilterChipRow(),
const _QuickLinkList(),
],
),
);
}
}
class _SearchBar extends StatelessWidget {
const _SearchBar({
required this.searchController,
required this.searchFocusNode,
required this.onClearSearch,
});
final TextEditingController searchController;
final FocusNode searchFocusNode;
final VoidCallback onClearSearch;
@override
Widget build(BuildContext context) {
return const SliverPadding(
padding: EdgeInsets.symmetric(horizontal: 16),
sliver: SliverToBoxAdapter(
child: SizedBox.shrink(),
),
);
}
}
class _SearchFilterChipRow extends StatelessWidget {
const _SearchFilterChipRow();
void showPeoplePicker() {
}
void showLocationPicker() {
}
void showCameraPicker() {
}
void showDatePicker() {
}
void showMediaTypePicker() {
}
void showDisplayOptionPicker() {
}
@override
Widget build(BuildContext context) {
return SliverPadding(
padding: const EdgeInsets.only(left: 16, top: 12, right: 16),
sliver: SliverToBoxAdapter(
child: SizedBox(
height: 50,
child: ListView(
key: const Key('search_filter_chip_list'),
shrinkWrap: true,
scrollDirection: Axis.horizontal,
children: [
_SearchFilterChip(
icon: Icons.people_alt_outlined,
onTap: showPeoplePicker,
label: 'people'.t(context: context),
// currentFilter: peopleCurrentFilterWidget.value,
),
_SearchFilterChip(
icon: Icons.location_on_outlined,
onTap: showLocationPicker,
label: 'search_filter_location'.t(context: context),
// currentFilter: locationCurrentFilterWidget.value,
),
_SearchFilterChip(
icon: Icons.camera_alt_outlined,
onTap: showCameraPicker,
label: 'camera'.t(context: context),
// currentFilter: cameraCurrentFilterWidget.value,
),
_SearchFilterChip(
icon: Icons.date_range_outlined,
onTap: showDatePicker,
label: 'search_filter_date'.t(context: context),
// currentFilter: dateRangeCurrentFilterWidget.value,
),
_SearchFilterChip(
icon: Icons.video_collection_outlined,
onTap: showMediaTypePicker,
label: 'search_filter_media_type'.t(context: context),
// currentFilter: mediaTypeCurrentFilterWidget.value,
),
_SearchFilterChip(
icon: Icons.display_settings_outlined,
onTap: showDisplayOptionPicker,
label: 'search_filter_display_options'.t(context: context),
// currentFilter: displayOptionCurrentFilterWidget.value,
),
],
),
),
),
);
}
}
class _SearchFilterChip extends StatelessWidget {
const _SearchFilterChip({
required this.label,
required this.icon,
required this.onTap,
this.currentFilter,
});
final String label;
final IconData icon;
final VoidCallback onTap;
final Widget? currentFilter;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Card(
elevation: 0,
color: currentFilter == null
? context.colorScheme.surfaceContainerLow
: context.primaryColor.withValues(alpha: .5),
shape: StadiumBorder(
side: BorderSide(
color: currentFilter == null
? context.colorScheme.outline.withAlpha(15)
: context.colorScheme.secondaryContainer,
),
),
child: Padding(
padding:
const EdgeInsets.symmetric(vertical: 2.0, horizontal: 14.0),
child: Row(
children: [
Icon(
icon,
size: 18,
),
const SizedBox(width: 4.0),
currentFilter ?? Text(label),
],
),
),
),
);
}
}
class _QuickLinkList extends StatelessWidget {
const _QuickLinkList();
@override
Widget build(BuildContext context) {
return SliverPadding(
padding: const EdgeInsets.symmetric(horizontal: 16),
sliver: SliverToBoxAdapter(
child: Container(
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(
Radius.circular(20),
),
border: Border.all(
color: context.colorScheme.outline.withAlpha(10),
width: 1,
),
gradient: LinearGradient(
colors: [
context.colorScheme.primary.withAlpha(10),
context.colorScheme.primary.withAlpha(15),
context.colorScheme.primary.withAlpha(20),
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
child: ListView(
shrinkWrap: true,
padding: const EdgeInsets.all(0),
physics: const NeverScrollableScrollPhysics(),
children: [
_QuickLink(
label: 'recently_taken'.t(context: context),
icon: Icons.schedule_outlined,
onTap: () => context.pushRoute(const RecentlyTakenRoute()),
isTop: true,
),
_QuickLink(
label: 'videos'.t(context: context),
icon: Icons.play_circle_outline_rounded,
onTap: () => context.pushRoute(const DriftVideoRoute()),
),
_QuickLink(
label: 'favorites'.t(context: context),
icon: Icons.favorite_border_rounded,
onTap: () => context.pushRoute(const DriftFavoriteRoute()),
isBottom: true,
),
],
),
),
),
);
}
}
class _QuickLink extends StatelessWidget {
const _QuickLink({
required this.label,
required this.icon,
required this.onTap,
this.isTop = false,
this.isBottom = false,
});
final String label;
final IconData icon;
final VoidCallback onTap;
final bool isTop;
final bool isBottom;
@override
Widget build(BuildContext context) {
final borderRadius = BorderRadius.only(
topLeft: Radius.circular(isTop ? 20 : 0),
topRight: Radius.circular(isTop ? 20 : 0),
bottomLeft: Radius.circular(isBottom ? 20 : 0),
bottomRight: Radius.circular(isBottom ? 20 : 0),
);
return ListTile(
shape: RoundedRectangleBorder(
borderRadius: borderRadius,
),
leading: Icon(
icon,
size: 26,
),
title: Text(
label,
style: context.textTheme.titleSmall?.copyWith(
fontWeight: FontWeight.w500,
),
),
onTap: onTap,
);
}
}