Создание карточки в коллекции + экран поиска коллекции
This commit is contained in:
273
lib/screens/collections/collection_search_screen.dart
Normal file
273
lib/screens/collections/collection_search_screen.dart
Normal file
@@ -0,0 +1,273 @@
|
||||
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<CollectionSearchScreen> createState() => _CollectionSearchScreenState();
|
||||
}
|
||||
|
||||
class _CollectionSearchScreenState extends State<CollectionSearchScreen> {
|
||||
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<List<Collection>>(
|
||||
stream: getIt<CollectionsInterface>().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,
|
||||
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: <Widget>[_buildAvatar(), const WSpace(5), _buildInfo()],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
///
|
||||
/// Построение основной информации
|
||||
///
|
||||
Widget _buildInfo() {
|
||||
return SizedBox(
|
||||
width: 230.w,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
_buildTitle(),
|
||||
const HSpace(4),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
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.memory(collection.image!, fit: BoxFit.cover),
|
||||
),
|
||||
fallback:
|
||||
(context) => Center(
|
||||
child: AppTypography(
|
||||
collection.title.substring(0, 1),
|
||||
type: Bold34px(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user