import 'dart:io'; import 'package:auto_route/auto_route.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:remever/common/resources.dart'; import 'package:remever/common/utils.dart'; import 'package:remever/common/widgets/loose_focus.dart'; import 'package:remever/common/widgets/typography.dart'; import 'package:remever/common/widgets/w_if.dart'; import 'package:remever/common/widgets/wspace.dart'; import 'package:remever/components/extensions/context.dart'; import 'package:remever/components/extensions/state.dart'; import 'package:remever/database/database.dart'; import 'package:remever/gen/assets.gen.dart'; import 'package:remever/inject.dart'; import 'package:remever/router.gr.dart'; import 'package:remever/screens/collections/collections_screen.dart'; import 'package:remever/screens/collections/widgets/collection_progress_bar.dart'; import 'package:remever/services/collection/collections_interface.dart'; @RoutePage() class CollectionSearchScreen extends StatefulWidget { const CollectionSearchScreen({super.key, required this.onCollectionSelect}); final void Function(Collection) onCollectionSelect; @override State createState() => _CollectionSearchScreenState(); } class _CollectionSearchScreenState extends State { final TextEditingController _searchController = TextEditingController(); String? _search; @override void initState() { _searchController.addListener(() { safeSetState(() { _search = _searchController.text; }); }); super.initState(); } @override void dispose() { _searchController.dispose(); super.dispose(); } void _onCreateTap() { context.pushRoute(CrudCollectionRoute()); } @override Widget build(BuildContext context) { return LooseFocus( child: Scaffold( backgroundColor: AppColors.bg, appBar: _buildAppBar(context), body: _buildBody(context), ), ); } AppBar _buildAppBar(BuildContext context) { return AppBar( toolbarHeight: 66.h, backgroundColor: AppColors.white, shadowColor: Colors.transparent, title: SizedBox( height: 48.h, child: DecoratedBox( decoration: BoxDecoration( color: AppColors.white, borderRadius: BorderRadius.circular(12).r, border: Border.all(color: AppColors.bg), ), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 12).r, child: Center( child: TextField( autofocus: true, controller: _searchController, textCapitalization: TextCapitalization.sentences, maxLines: 1, cursorColor: AppColors.danger, decoration: const InputDecoration.collapsed( hintText: 'Поиск', hintStyle: TextStyle(color: AppColors.gray), ), ), ), ), ), ), centerTitle: true, leading: IconButton( onPressed: () async { context.back(); }, icon: const Icon(CupertinoIcons.left_chevron, color: Colors.black), ), ); } Widget _buildBody(BuildContext context) { return Column( children: [ _buildCreateButton(), Expanded( child: StreamBuilder>( stream: getIt().watchCollectionsList( search: _search, ), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const LoadingList(); } if (snapshot.hasError) { return const ErrorList(); } final collections = snapshot.data; if (collections == null || collections.isEmpty) { return const EmptyList(); } return ListView.builder( itemCount: collections.length, physics: BouncingScrollPhysics(), padding: const EdgeInsets.symmetric(horizontal: 16).r, itemBuilder: (context, index) => Padding( padding: const EdgeInsets.only(bottom: 8).r, child: GestureDetector( onTap: () { widget.onCollectionSelect(collections[index]); context.back(); }, child: _Collection(collection: collections[index]), ), ), ); }, ), ), ], ); } Padding _buildCreateButton() { return Padding( padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 28).r, child: GestureDetector( onTap: () => _onCreateTap(), child: Row( children: [ SizedBox.square( dimension: 20.r, child: DecoratedBox( decoration: BoxDecoration( color: AppColors.white, shape: BoxShape.circle, ), child: Center( child: Icon(Icons.add, color: AppColors.disabled, size: 15.r), ), ), ), WSpace(4), AppTypography('Создать новую коллекцию', type: Regular16px()), ], ), ), ); } } class _Collection extends StatelessWidget { const _Collection({required this.collection}); final Collection collection; @override Widget build(BuildContext context) { return Container( constraints: BoxConstraints(minHeight: 66.h, maxHeight: 84.h), decoration: BoxDecoration( borderRadius: BorderRadius.circular(12).r, color: AppColors.white, ), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8).r, child: Row( children: [_buildAvatar(), const WSpace(5), _buildInfo()], ), ); } /// /// Построение основной информации /// Widget _buildInfo() { return SizedBox( width: 230.w, child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ _buildTitle(), const HSpace(4), Row( children: [ Assets.icons.typeCards.image( height: 18.h, width: 18.w, color: AppColors.disabled, ), const WSpace(2), AppTypography( '${collection.likesCount.toString()} ${Utils.declOfNum(collection.likesCount, ['карточек', 'карточки', 'карточек'])}', type: Regular14px(), color: AppColors.disabled, ), ], ), const HSpace(6), const CollectionProgressBar(), ], ), ); } /// /// Название коллекции /// Widget _buildTitle() { return AppTypography( collection.title, type: Medium16px(), maxLines: 2, softWrap: true, ); } /// /// Обложка коллекции /// Widget _buildAvatar() { return SizedBox.square( dimension: 50.r, child: DecoratedBox( decoration: BoxDecoration(shape: BoxShape.circle, color: AppColors.bg), child: Wif( condition: collection.image != null, builder: (context) => ClipOval( child: Image.file(File(collection.image!), fit: BoxFit.cover), ), fallback: (context) => Center( child: AppTypography( collection.title.substring(0, 1), type: Bold34px(), ), ), ), ), ); } }