diff --git a/mobile/lib/pages/albums/albums.page.dart b/mobile/lib/pages/albums/albums.page.dart index e5758c959c..4cbfc28ba5 100644 --- a/mobile/lib/pages/albums/albums.page.dart +++ b/mobile/lib/pages/albums/albums.page.dart @@ -17,6 +17,7 @@ import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/widgets/album/album_thumbnail_card.dart'; import 'package:immich_mobile/widgets/common/immich_app_bar.dart'; import 'package:immich_mobile/widgets/common/immich_thumbnail.dart'; +import 'package:immich_mobile/widgets/common/search_field.dart'; @RoutePage() class AlbumsPage extends HookConsumerWidget { @@ -115,46 +116,17 @@ class AlbumsPage extends HookConsumerWidget { transform: const GradientRotation(0.5 * pi), ), ), - child: TextField( + child: SearchField( autofocus: false, - decoration: InputDecoration( - contentPadding: const EdgeInsets.all(16), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(25), - borderSide: BorderSide( - color: context.colorScheme.surfaceDim, - ), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(25), - borderSide: BorderSide( - color: context.colorScheme.surfaceContainer, - ), - ), - disabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(25), - borderSide: BorderSide( - color: context.colorScheme.surfaceDim, - ), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(25), - borderSide: BorderSide( - color: context.colorScheme.primary.withAlpha(100), - ), - ), - hintText: 'search_albums'.tr(), - hintStyle: context.textTheme.bodyLarge?.copyWith( - color: context.colorScheme.onSurfaceSecondary, - ), - prefixIcon: const Icon(Icons.search_rounded), - suffixIcon: searchController.text.isNotEmpty - ? IconButton( - icon: const Icon(Icons.clear_rounded), - onPressed: clearSearch, - ) - : const SizedBox.shrink(), - ), + contentPadding: const EdgeInsets.all(16), + hintText: 'search_albums'.tr(), + prefixIcon: const Icon(Icons.search_rounded), + suffixIcon: searchController.text.isNotEmpty + ? IconButton( + icon: const Icon(Icons.clear_rounded), + onPressed: clearSearch, + ) + : null, controller: searchController, onChanged: (_) => onSearch(searchController.text, filterMode.value), diff --git a/mobile/lib/pages/search/search.page.dart b/mobile/lib/pages/search/search.page.dart index 80fedb588e..9ff8caff1d 100644 --- a/mobile/lib/pages/search/search.page.dart +++ b/mobile/lib/pages/search/search.page.dart @@ -8,13 +8,13 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/constants/enums.dart'; import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; -import 'package:immich_mobile/extensions/theme_extensions.dart'; import 'package:immich_mobile/interfaces/person_api.interface.dart'; import 'package:immich_mobile/models/search/search_filter.model.dart'; import 'package:immich_mobile/providers/search/paginated_search.provider.dart'; import 'package:immich_mobile/providers/search/search_input_focus.provider.dart'; import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/widgets/asset_grid/multiselect_grid.dart'; +import 'package:immich_mobile/widgets/common/search_field.dart'; import 'package:immich_mobile/widgets/search/search_filter/camera_picker.dart'; import 'package:immich_mobile/widgets/search/search_filter/display_option_picker.dart'; import 'package:immich_mobile/widgets/search/search_filter/filter_bottom_sheet_scaffold.dart'; @@ -640,51 +640,21 @@ class SearchPage extends HookConsumerWidget { end: Alignment.bottomRight, ), ), - child: TextField( + child: SearchField( + hintText: searchHintText.value, key: const Key('search_text_field'), controller: textSearchController, - decoration: InputDecoration( - contentPadding: prefilter != null - ? const EdgeInsets.only(left: 24) - : const EdgeInsets.all(8), - prefixIcon: prefilter != null - ? null - : Icon( - getSearchPrefixIcon(), - color: context.colorScheme.primary, - ), - hintText: searchHintText.value, - hintStyle: context.textTheme.bodyLarge?.copyWith( - color: context.themeData.colorScheme.onSurfaceSecondary, - ), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(25), - borderSide: BorderSide( - color: context.colorScheme.surfaceDim, - ), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(25), - borderSide: BorderSide( - color: context.colorScheme.surfaceContainer, - ), - ), - disabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(25), - borderSide: BorderSide( - color: context.colorScheme.surfaceDim, - ), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(25), - borderSide: BorderSide( - color: context.colorScheme.primary.withAlpha(100), - ), - ), - ), + contentPadding: prefilter != null + ? const EdgeInsets.only(left: 24) + : const EdgeInsets.all(8), + prefixIcon: prefilter != null + ? null + : Icon( + getSearchPrefixIcon(), + color: context.colorScheme.primary, + ), onSubmitted: handleTextSubmitted, focusNode: ref.watch(searchInputFocusProvider), - onTapOutside: (_) => ref.read(searchInputFocusProvider).unfocus(), ), ), ), diff --git a/mobile/lib/widgets/common/search_field.dart b/mobile/lib/widgets/common/search_field.dart new file mode 100644 index 0000000000..5d71082b24 --- /dev/null +++ b/mobile/lib/widgets/common/search_field.dart @@ -0,0 +1,79 @@ +import 'package:flutter/material.dart'; +import 'package:immich_mobile/extensions/build_context_extensions.dart'; +import 'package:immich_mobile/extensions/theme_extensions.dart'; + +class SearchField extends StatelessWidget { + const SearchField({ + super.key, + required this.hintText, + this.autofocus = false, + this.controller, + this.focusNode, + this.onChanged, + this.onSubmitted, + this.onTapOutside, + this.contentPadding = const EdgeInsets.only(left: 24), + this.prefixIcon, + this.suffixIcon, + this.filled = false, + }); + + final FocusNode? focusNode; + final void Function(String)? onChanged; + final void Function(String)? onSubmitted; + final void Function(PointerDownEvent)? onTapOutside; + final TextEditingController? controller; + final String hintText; + final EdgeInsetsGeometry contentPadding; + final Widget? prefixIcon; + final Widget? suffixIcon; + final bool autofocus; + final bool filled; + + @override + Widget build(BuildContext context) { + return TextField( + controller: controller, + autofocus: autofocus, + focusNode: focusNode, + onChanged: onChanged, + onTapOutside: onTapOutside ?? (_) => focusNode?.unfocus(), + onSubmitted: onSubmitted, + decoration: InputDecoration( + contentPadding: contentPadding, + filled: filled, + fillColor: context.primaryColor.withValues(alpha: 0.1), + hintStyle: context.textTheme.bodyLarge?.copyWith( + color: context.themeData.colorScheme.onSurfaceSecondary, + ), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(25), + borderSide: BorderSide( + color: context.colorScheme.surfaceDim, + ), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(25), + borderSide: BorderSide( + color: context.colorScheme.surfaceContainer, + ), + ), + disabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(25), + borderSide: BorderSide( + color: context.colorScheme.surfaceDim, + ), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(25), + borderSide: BorderSide( + color: context.colorScheme.primary.withAlpha(100), + ), + ), + prefixIcon: prefixIcon, + suffixIcon: suffixIcon, + hintText: hintText, + ), + ); + } +} diff --git a/mobile/lib/widgets/search/search_filter/people_picker.dart b/mobile/lib/widgets/search/search_filter/people_picker.dart index 2c45e2097c..54fa54b1ff 100644 --- a/mobile/lib/widgets/search/search_filter/people_picker.dart +++ b/mobile/lib/widgets/search/search_filter/people_picker.dart @@ -4,12 +4,12 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/extensions/asyncvalue_extensions.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; -import 'package:immich_mobile/extensions/theme_extensions.dart'; import 'package:immich_mobile/interfaces/person_api.interface.dart'; import 'package:immich_mobile/pages/common/large_leading_tile.dart'; import 'package:immich_mobile/providers/search/people.provider.dart'; import 'package:immich_mobile/services/api.service.dart'; import 'package:immich_mobile/utils/image_url_builder.dart'; +import 'package:immich_mobile/widgets/common/search_field.dart'; class PeoplePicker extends HookConsumerWidget { const PeoplePicker({super.key, required this.onSelect, this.filter}); @@ -30,47 +30,12 @@ class PeoplePicker extends HookConsumerWidget { children: [ Padding( padding: const EdgeInsets.all(8), - child: TextField( + child: SearchField( focusNode: formFocus, onChanged: (value) => searchQuery.value = value, onTapOutside: (_) => formFocus.unfocus(), - decoration: InputDecoration( - contentPadding: const EdgeInsets.only(left: 24), - filled: true, - fillColor: context.primaryColor.withValues(alpha: 0.1), - hintStyle: context.textTheme.bodyLarge?.copyWith( - color: context.themeData.colorScheme.onSurfaceSecondary, - ), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(25), - borderSide: BorderSide( - color: context.colorScheme.surfaceContainerHighest, - ), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(25), - borderSide: BorderSide( - color: context.colorScheme.surfaceContainerHighest, - ), - ), - disabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(25), - borderSide: BorderSide( - color: context.colorScheme.surfaceContainerHighest, - ), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(25), - borderSide: BorderSide( - color: context.colorScheme.primary.withAlpha(150), - ), - ), - prefixIcon: Icon( - Icons.search_rounded, - color: context.colorScheme.primary, - ), - hintText: 'search_filter_people_hint'.tr(), - ), + filled: true, + hintText: 'search_filter_people_hint'.tr(), ), ), Padding(