Обновлен проект. Добавлена БД
This commit is contained in:
186
lib/screens/collections/collection_detail_screen.dart
Normal file
186
lib/screens/collections/collection_detail_screen.dart
Normal file
@@ -0,0 +1,186 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
|
||||
import 'package:remever/common/resources.dart';
|
||||
import 'package:remever/common/widgets/typography.dart';
|
||||
import 'package:remever/common/widgets/wspace.dart';
|
||||
import 'package:remever/components/extensions/context.dart';
|
||||
import 'package:remever/gen/assets.gen.dart';
|
||||
import 'package:remever/screens/collections/widgets/learning_card.dart';
|
||||
import 'package:remever/screens/dialogs/info_dialog.dart';
|
||||
import 'package:remever/widgets/primary_button.dart';
|
||||
|
||||
@RoutePage()
|
||||
class CollectionDetailScreen extends StatelessWidget {
|
||||
const CollectionDetailScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: AppColors.gray_bg,
|
||||
appBar: _buildAppBar(context),
|
||||
body: _buildMain(context),
|
||||
);
|
||||
}
|
||||
|
||||
/// Построение шапки
|
||||
AppBar _buildAppBar(BuildContext context) {
|
||||
return AppBar(
|
||||
toolbarHeight: 56.h,
|
||||
backgroundColor: AppColors.white,
|
||||
shadowColor: Colors.transparent,
|
||||
leading: IconButton(
|
||||
onPressed: () async {
|
||||
// context.read<HomeCubit>().toCollection();
|
||||
context.back();
|
||||
},
|
||||
icon: const Icon(CupertinoIcons.left_chevron, color: Colors.black),
|
||||
),
|
||||
centerTitle: false,
|
||||
title: _buildTitle(),
|
||||
actions: <Widget>[
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
showCupertinoModalBottomSheet(
|
||||
topRadius: const Radius.circular(24).r,
|
||||
backgroundColor: AppColors.white,
|
||||
context: context,
|
||||
builder: (BuildContext _) => const InfoDialog(),
|
||||
);
|
||||
},
|
||||
child: Assets.icons.typeDescription.image(height: 24.h, width: 24.w),
|
||||
),
|
||||
const WSpace(16),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTitle() {
|
||||
return Row(
|
||||
children: <Widget>[_buildAvatar(), const WSpace(5), _buildInfo()],
|
||||
);
|
||||
}
|
||||
|
||||
///
|
||||
/// Построение основной информации
|
||||
///
|
||||
Widget _buildInfo() {
|
||||
return Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
_buildCollectionTitle(),
|
||||
const HSpace(4),
|
||||
_buildCards(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
///
|
||||
/// Построение кол-ва карточек и лайков
|
||||
///
|
||||
Widget _buildCards() {
|
||||
return Row(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Assets.icons.typeCards.image(
|
||||
height: 18.h,
|
||||
width: 18.w,
|
||||
color: AppColors.disabled,
|
||||
),
|
||||
const WSpace(2),
|
||||
AppTypography(
|
||||
0.toString(),
|
||||
type: Regular14px(),
|
||||
color: AppColors.disabled,
|
||||
),
|
||||
],
|
||||
),
|
||||
const WSpace(8),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
///
|
||||
/// Название коллекции
|
||||
///
|
||||
Widget _buildCollectionTitle() {
|
||||
return AppTypography(
|
||||
'Астрономия и тайная комната Харли Хоттера',
|
||||
type: Medium16px(),
|
||||
maxLines: 1,
|
||||
softWrap: true,
|
||||
color: AppColors.primary,
|
||||
);
|
||||
}
|
||||
|
||||
///
|
||||
/// Обложка коллекции
|
||||
///
|
||||
Widget _buildAvatar() {
|
||||
return SizedBox.square(
|
||||
dimension: 40.r,
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
image: DecorationImage(image: Assets.images.img.provider()),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
///
|
||||
/// Построение основного содержимого
|
||||
///
|
||||
Widget _buildMain(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16).r,
|
||||
|
||||
child: _buildList(context),
|
||||
);
|
||||
}
|
||||
|
||||
/// Состояние пустого списка
|
||||
Widget _buildEmptyList(BuildContext context) {
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
const HSpace(40),
|
||||
Center(child: Assets.images.noData.image(width: 184.w, height: 101.h)),
|
||||
const Spacer(),
|
||||
_buildCreateBtn(context),
|
||||
const HSpace(40),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
///Кнопка создания
|
||||
Widget _buildCreateBtn(BuildContext context) {
|
||||
return PrimaryButton(
|
||||
height: 52,
|
||||
onTap: () {
|
||||
// context.read<HomeCubit>().toCollection();
|
||||
context.back();
|
||||
},
|
||||
color: AppColors.primary,
|
||||
child: AppTypography('Создать карточку', type: Regular14px()),
|
||||
);
|
||||
}
|
||||
|
||||
///
|
||||
/// Построение списка карточек
|
||||
///
|
||||
Widget _buildList(BuildContext context) {
|
||||
return ListView.builder(
|
||||
physics: BouncingScrollPhysics(),
|
||||
itemCount: 10,
|
||||
itemBuilder:
|
||||
(BuildContext context, int index) => LearningCard(index: index),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,17 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:get_it_mixin/get_it_mixin.dart';
|
||||
import 'package:remever/common/resources.dart';
|
||||
import 'package:remever/common/widgets/typography.dart';
|
||||
import 'package:remever/components/extensions/context.dart';
|
||||
import 'package:remever/components/notifiers/home_screen_data.dart';
|
||||
import 'package:remever/database/database.dart';
|
||||
import 'package:remever/database/tables.dart';
|
||||
import 'package:remever/inject.dart';
|
||||
import 'package:remever/router.gr.dart';
|
||||
import 'package:remever/screens/collections/cubit/collection_cubit.dart';
|
||||
import 'package:remever/screens/collections/widgets/collection_card.dart';
|
||||
import 'package:remever/screens/collections/widgets/collections_app_bar.dart';
|
||||
import 'package:remever/screens/collections/widgets/collections_filters.dart';
|
||||
|
||||
@RoutePage()
|
||||
class CollectionScreen extends StatelessWidget with GetItMixin {
|
||||
@@ -20,10 +28,9 @@ class CollectionScreen extends StatelessWidget with GetItMixin {
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider<CollectionCubit>(
|
||||
create: (context) => CollectionCubit(),
|
||||
|
||||
child: Scaffold(
|
||||
backgroundColor: AppColors.bg,
|
||||
// appBar: const CollectionsAppBar(),
|
||||
appBar: const CollectionsAppBar(),
|
||||
body: _buildMain(context),
|
||||
floatingActionButton: Builder(
|
||||
builder: (BuildContext context) {
|
||||
@@ -32,7 +39,9 @@ class CollectionScreen extends StatelessWidget with GetItMixin {
|
||||
duration: const Duration(milliseconds: 200),
|
||||
child: FloatingActionButton(
|
||||
backgroundColor: AppColors.primary,
|
||||
onPressed: () {},
|
||||
onPressed: () {
|
||||
context.pushRoute(CrudCollectionRoute());
|
||||
},
|
||||
// context.read<HomeCubit>().toCrudCollection(CrudType.CREATE),
|
||||
child: const Icon(Icons.add),
|
||||
),
|
||||
@@ -49,17 +58,16 @@ class CollectionScreen extends StatelessWidget with GetItMixin {
|
||||
Widget _buildMain(BuildContext context) {
|
||||
return BlocBuilder<CollectionCubit, CollectionState>(
|
||||
builder: (context, state) {
|
||||
return state.when(
|
||||
loading: () => _LoadingList(),
|
||||
data:
|
||||
() => const Column(
|
||||
children: <Widget>[
|
||||
// CollectionsFilters(),
|
||||
_CollectionList(),
|
||||
],
|
||||
),
|
||||
empty: () => _EmptyList(),
|
||||
error: () => _ErrorList(),
|
||||
return Column(
|
||||
children: [
|
||||
CollectionsFilters(),
|
||||
state.when(
|
||||
loading: () => _LoadingList(),
|
||||
data: () => _CollectionList(),
|
||||
empty: () => _EmptyList(),
|
||||
error: () => _ErrorList(),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
@@ -71,7 +79,10 @@ class _LoadingList extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const Placeholder(color: Colors.green);
|
||||
return SizedBox(
|
||||
height: MediaQuery.sizeOf(context).height / 2,
|
||||
child: Center(child: CircularProgressIndicator(color: AppColors.primary)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +91,12 @@ class _ErrorList extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const Placeholder(color: Colors.brown);
|
||||
return SizedBox(
|
||||
height: MediaQuery.sizeOf(context).height / 2,
|
||||
child: Center(
|
||||
child: AppTypography('Произошла ошибка при загрузке данных'),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +105,10 @@ class _EmptyList extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const Placeholder(color: Colors.red);
|
||||
return SizedBox(
|
||||
height: MediaQuery.sizeOf(context).height / 2,
|
||||
child: Center(child: AppTypography('Нет доступных коллекций')),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,15 +123,41 @@ class _CollectionList extends StatelessWidget {
|
||||
collectionCubit.initScrollListener();
|
||||
|
||||
return Expanded(
|
||||
child: ListView.builder(
|
||||
controller: collectionCubit.collectionController,
|
||||
itemCount: 20,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16).r,
|
||||
itemBuilder:
|
||||
(BuildContext context, int index) => Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8).r,
|
||||
// child: const CollectionCard(),
|
||||
),
|
||||
child: StreamBuilder(
|
||||
stream: getIt<AppDatabase>().collectionsDao.getCollections(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return Center(
|
||||
child: CircularProgressIndicator(color: AppColors.primary),
|
||||
);
|
||||
}
|
||||
|
||||
if (snapshot.connectionState == ConnectionState.active ||
|
||||
snapshot.connectionState == ConnectionState.done) {
|
||||
if (snapshot.hasError) {
|
||||
return _ErrorList();
|
||||
}
|
||||
|
||||
if (snapshot.data == null || snapshot.data!.isEmpty) {
|
||||
return _EmptyList();
|
||||
}
|
||||
|
||||
return ListView.builder(
|
||||
controller: collectionCubit.collectionController,
|
||||
itemCount: snapshot.data!.length,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16).r,
|
||||
itemBuilder:
|
||||
(BuildContext context, int index) => Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8).r,
|
||||
child: const CollectionCard(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Center(
|
||||
child: CircularProgressIndicator(color: AppColors.primary),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,13 +2,14 @@ import 'package:bloc/bloc.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:remever/components/notifiers/home_screen_data.dart';
|
||||
import 'package:remever/database/database.dart';
|
||||
import 'package:remever/inject.dart';
|
||||
|
||||
part 'collection_state.dart';
|
||||
part 'collection_cubit.freezed.dart';
|
||||
|
||||
class CollectionCubit extends Cubit<CollectionState> {
|
||||
CollectionCubit() : super(CollectionState.loading());
|
||||
CollectionCubit() : super(CollectionState.data());
|
||||
|
||||
/// Нотифаер домашнего экрана
|
||||
CollectionData get _cd => getIt<CollectionData>();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
part of 'collection_cubit.dart';
|
||||
|
||||
@freezed
|
||||
class CollectionState with _$CollectionState {
|
||||
sealed class CollectionState with _$CollectionState {
|
||||
const factory CollectionState.loading() = _Loading;
|
||||
const factory CollectionState.data() = _Data;
|
||||
const factory CollectionState.empty() = _Empty;
|
||||
|
||||
190
lib/screens/collections/widgets/collection_card.dart
Normal file
190
lib/screens/collections/widgets/collection_card.dart
Normal file
@@ -0,0 +1,190 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_slidable/flutter_slidable.dart';
|
||||
import 'package:remever/common/functions.dart';
|
||||
import 'package:remever/common/resources.dart';
|
||||
import 'package:remever/common/widgets/typography.dart';
|
||||
import 'package:remever/common/widgets/wspace.dart';
|
||||
import 'package:remever/components/extensions/context.dart';
|
||||
import 'package:remever/gen/assets.gen.dart';
|
||||
import 'package:remever/router.gr.dart';
|
||||
import 'package:remever/screens/collections/widgets/collection_progress_bar.dart';
|
||||
import 'package:remever/screens/dialogs/action_dialog.dart';
|
||||
|
||||
class CollectionCard extends StatelessWidget {
|
||||
const CollectionCard({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Slidable(
|
||||
endActionPane: ActionPane(
|
||||
extentRatio: 0.62,
|
||||
motion: const StretchMotion(),
|
||||
children: <Widget>[
|
||||
const WSpace(8),
|
||||
_buildSlidableAction(
|
||||
context: context,
|
||||
backgroundColor: const Color(0xFFD7E6F4),
|
||||
foregroundColor: const Color(0xFF0058AB),
|
||||
icon: Icons.info_outline,
|
||||
onPressed: () {},
|
||||
),
|
||||
const WSpace(8),
|
||||
_buildSlidableAction(
|
||||
context: context,
|
||||
backgroundColor: const Color(0xFFFFE4E6),
|
||||
foregroundColor: const Color(0xFFFF5C69),
|
||||
icon: Icons.favorite_border,
|
||||
onPressed: () {},
|
||||
),
|
||||
const WSpace(8),
|
||||
_buildSlidableAction(
|
||||
context: context,
|
||||
backgroundColor: AppColors.secondary,
|
||||
foregroundColor: AppColors.primary,
|
||||
icon: Icons.visibility_off_outlined,
|
||||
onPressed: () {},
|
||||
),
|
||||
],
|
||||
),
|
||||
child: GestureDetector(
|
||||
onTap: () => context.pushRoute(CollectionDetailRoute()),
|
||||
child: 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(),
|
||||
const Spacer(),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
showCuperModalBottomSheet(
|
||||
context: context,
|
||||
height: 477.h,
|
||||
builder: (BuildContext context) => const ActionDialog(),
|
||||
);
|
||||
},
|
||||
child: Assets.icons.typeMenuVertical.image(
|
||||
height: 24.h,
|
||||
width: 24.w,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
///
|
||||
/// Построение основной информации
|
||||
///
|
||||
Widget _buildInfo() {
|
||||
return SizedBox(
|
||||
width: 230.w,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
_buildTitle(),
|
||||
const HSpace(4),
|
||||
_buildLikeAndCardsLength(),
|
||||
const HSpace(6),
|
||||
const CollectionProgressBar(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
///
|
||||
/// Построение кол-ва карточек и лайков
|
||||
///
|
||||
Widget _buildLikeAndCardsLength() {
|
||||
return Row(
|
||||
children: <Widget>[
|
||||
_buildIconWithText(
|
||||
icon: Assets.icons.typeCards,
|
||||
color: AppColors.disabled,
|
||||
text: Random().nextInt(654).toString(),
|
||||
),
|
||||
const WSpace(8),
|
||||
_buildIconWithText(
|
||||
icon: Assets.icons.typeLike1818,
|
||||
color: AppColors.danger,
|
||||
text: Random().nextInt(7689).toString(),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
///
|
||||
/// Название коллекции
|
||||
///
|
||||
Widget _buildTitle() {
|
||||
return AppTypography(
|
||||
'Астрономия',
|
||||
type: Medium16px(),
|
||||
maxLines: 2,
|
||||
softWrap: true,
|
||||
);
|
||||
}
|
||||
|
||||
///
|
||||
/// Обложка коллекции
|
||||
///
|
||||
Widget _buildAvatar() {
|
||||
return SizedBox.square(
|
||||
dimension: 50.r,
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
image: DecorationImage(image: Assets.images.img.provider()),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
///
|
||||
/// Кнопка в меню свайпа
|
||||
///
|
||||
Widget _buildSlidableAction({
|
||||
required BuildContext context,
|
||||
required Color backgroundColor,
|
||||
required Color foregroundColor,
|
||||
required IconData icon,
|
||||
required VoidCallback onPressed,
|
||||
}) {
|
||||
return SlidableAction(
|
||||
borderRadius: BorderRadius.circular(12).r,
|
||||
onPressed: (_) => onPressed(),
|
||||
backgroundColor: backgroundColor,
|
||||
foregroundColor: foregroundColor,
|
||||
icon: icon,
|
||||
);
|
||||
}
|
||||
|
||||
///
|
||||
/// Построение инфо
|
||||
///
|
||||
Widget _buildIconWithText({
|
||||
required AssetGenImage icon,
|
||||
required Color color,
|
||||
required String text,
|
||||
}) {
|
||||
return Row(
|
||||
children: <Widget>[
|
||||
icon.image(height: 18.h, width: 18.w, color: color),
|
||||
const WSpace(2),
|
||||
AppTypography(text, type: Regular14px(), color: color),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
39
lib/screens/collections/widgets/collection_progress_bar.dart
Normal file
39
lib/screens/collections/widgets/collection_progress_bar.dart
Normal file
@@ -0,0 +1,39 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:remever/common/resources.dart';
|
||||
import 'package:remever/components/extensions/context.dart';
|
||||
|
||||
class CollectionProgressBar extends StatelessWidget {
|
||||
const CollectionProgressBar({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
height: 2.h,
|
||||
width: 230.w,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(2)).r,
|
||||
color: AppColors.gray,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
height: 2.h,
|
||||
width: Random().nextInt(230).w,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(2)).r,
|
||||
gradient: const LinearGradient(
|
||||
colors: <Color>[
|
||||
Color(0xFFA7DEDC),
|
||||
Color(0xFF318D89),
|
||||
Color(0xFF4633BF),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
|
||||
import 'package:remever/common/functions.dart';
|
||||
import 'package:remever/common/resources.dart';
|
||||
import 'package:remever/common/widgets/typography.dart';
|
||||
import 'package:remever/common/widgets/wspace.dart';
|
||||
import 'package:remever/components/extensions/context.dart';
|
||||
import 'package:remever/gen/assets.gen.dart';
|
||||
import 'package:remever/router.gr.dart';
|
||||
import 'package:remever/screens/dialogs/filters_dialog.dart';
|
||||
|
||||
class CollectionsAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
const CollectionsAppBar({super.key});
|
||||
|
||||
@override
|
||||
Size get preferredSize => Size.fromHeight(66.h);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AppBar(
|
||||
toolbarHeight: 66.h,
|
||||
backgroundColor: AppColors.white,
|
||||
shadowColor: Colors.transparent,
|
||||
title: Row(
|
||||
children: <Widget>[
|
||||
GestureDetector(
|
||||
onLongPress: () => context.pushRoute(const SandboxRoute()),
|
||||
child: AppTypography(
|
||||
'Коллекции',
|
||||
type: SemiBold28px(),
|
||||
color: AppColors.body_text,
|
||||
),
|
||||
),
|
||||
const WSpace(2),
|
||||
Container(
|
||||
height: 22.h,
|
||||
width: 38.w,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.secondary,
|
||||
borderRadius: BorderRadius.circular(40).r,
|
||||
),
|
||||
child: Center(
|
||||
child: AppTypography(
|
||||
'2213',
|
||||
type: Regular12px(),
|
||||
color: AppColors.body_text,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: <Widget>[
|
||||
AppBarIconButton(icon: Assets.icons.typeSearch, onTap: () {}),
|
||||
AppBarIconButton(icon: Assets.icons.typeDownload, onTap: () {}),
|
||||
AppBarIconButton(
|
||||
icon: Assets.icons.typeSort,
|
||||
onTap: () {
|
||||
showCuperModalBottomSheet(
|
||||
context: context,
|
||||
height: 424.h,
|
||||
builder: (BuildContext context) => const FiltersDialog(),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AppBarIconButton extends StatelessWidget {
|
||||
const AppBarIconButton({required this.icon, required this.onTap, super.key});
|
||||
|
||||
final AssetGenImage icon;
|
||||
final void Function()? onTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: SizedBox(
|
||||
width: 48.h,
|
||||
child: Center(child: icon.image(height: 24.h, width: 24.w)),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,6 @@ import 'package:remever/components/extensions/context.dart';
|
||||
import 'package:remever/gen/assets.gen.dart';
|
||||
import 'package:remever/router.gr.dart';
|
||||
import 'package:remever/screens/dialogs/filters_dialog.dart';
|
||||
import 'package:remever/screens/home/home_screen.dart';
|
||||
|
||||
class CollectionsAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
const CollectionsAppBar({super.key});
|
||||
@@ -22,10 +21,12 @@ class CollectionsAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
toolbarHeight: 66.h,
|
||||
backgroundColor: AppColors.white,
|
||||
shadowColor: Colors.transparent,
|
||||
// leading: SizedBox(),
|
||||
leadingWidth: 0,
|
||||
title: Row(
|
||||
children: <Widget>[
|
||||
GestureDetector(
|
||||
// onLongPress: () => context.pushRoute(const SandboxRoute()),
|
||||
onLongPress: () => context.pushRoute(const SandboxRoute()),
|
||||
child: AppTypography(
|
||||
'Коллекции',
|
||||
type: SemiBold28px(),
|
||||
|
||||
76
lib/screens/collections/widgets/collections_filters.dart
Normal file
76
lib/screens/collections/widgets/collections_filters.dart
Normal file
@@ -0,0 +1,76 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:remever/common/resources.dart';
|
||||
import 'package:remever/common/widgets/typography.dart';
|
||||
import 'package:remever/components/extensions/context.dart';
|
||||
import 'package:remever/components/extensions/state.dart';
|
||||
import 'package:remever/screens/collections/cubit/collection_cubit.dart';
|
||||
|
||||
class CollectionsFilters extends StatefulWidget {
|
||||
const CollectionsFilters({super.key});
|
||||
|
||||
@override
|
||||
State<CollectionsFilters> createState() => _CollectionsFiltersState();
|
||||
}
|
||||
|
||||
class _CollectionsFiltersState extends State<CollectionsFilters> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 28).r,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
_buildFilterButton(
|
||||
context.read<CollectionCubit>().collectionFiltersIndex == 0
|
||||
? AppColors.white
|
||||
: AppColors.gray_bg,
|
||||
'Все',
|
||||
() {
|
||||
context.read<CollectionCubit>().collectionFiltersIndex = 0;
|
||||
safeSetState(() {});
|
||||
},
|
||||
),
|
||||
_buildFilterButton(
|
||||
context.read<CollectionCubit>().collectionFiltersIndex == 1
|
||||
? AppColors.white
|
||||
: AppColors.gray_bg,
|
||||
'Публичные',
|
||||
() {
|
||||
context.read<CollectionCubit>().collectionFiltersIndex = 1;
|
||||
safeSetState(() {});
|
||||
},
|
||||
),
|
||||
_buildFilterButton(
|
||||
context.read<CollectionCubit>().collectionFiltersIndex == 2
|
||||
? AppColors.white
|
||||
: AppColors.gray_bg,
|
||||
'Подписки',
|
||||
() {
|
||||
context.read<CollectionCubit>().collectionFiltersIndex = 2;
|
||||
safeSetState(() {});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
///
|
||||
/// Построение кнопки фильтра
|
||||
///
|
||||
Widget _buildFilterButton(Color color, String title, void Function()? onTap) {
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
width: 103.h,
|
||||
height: 36.h,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(16)).r,
|
||||
color: color,
|
||||
),
|
||||
child: Center(child: AppTypography(title, type: SemiBold14px())),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
249
lib/screens/collections/widgets/learning_card.dart
Normal file
249
lib/screens/collections/widgets/learning_card.dart
Normal file
@@ -0,0 +1,249 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_slidable/flutter_slidable.dart';
|
||||
import 'package:readmore/readmore.dart';
|
||||
import 'package:remever/common/functions.dart';
|
||||
import 'package:remever/common/resources.dart';
|
||||
import 'package:remever/common/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/gen/assets.gen.dart';
|
||||
import 'package:remever/screens/dialogs/alert_dialog.dart';
|
||||
import 'package:remever/screens/dialogs/replace_diaog.dart';
|
||||
|
||||
enum CardType { CREATE, SHOW }
|
||||
|
||||
class LearningCard extends StatelessWidget {
|
||||
LearningCard({
|
||||
required this.index,
|
||||
super.key,
|
||||
this.type = CardType.SHOW,
|
||||
this.onTextTap,
|
||||
});
|
||||
|
||||
final int index;
|
||||
final CardType type;
|
||||
void Function()? onTextTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 8).r,
|
||||
child: Slidable(
|
||||
enabled: type == CardType.SHOW ? true : false,
|
||||
endActionPane: ActionPane(
|
||||
extentRatio: 0.62,
|
||||
motion: const StretchMotion(),
|
||||
children: <Widget>[
|
||||
const WSpace(8),
|
||||
_buildSlidableAction(
|
||||
context: context,
|
||||
backgroundColor: const Color(0xFFFFE4E6),
|
||||
foregroundColor: const Color(0xFFFF5C69),
|
||||
icon: CupertinoIcons.trash,
|
||||
onPressed: () {
|
||||
showCuperModalBottomSheet(
|
||||
context: context,
|
||||
height: 262.h,
|
||||
builder:
|
||||
(BuildContext context) => const AlertInfoDialog(
|
||||
title:
|
||||
'Вы хотите удалить карточку?\nЭто действие необратимо',
|
||||
acceptTitle: 'Да, удалить',
|
||||
declineTitle: 'Нет, оставить',
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
const WSpace(8),
|
||||
_buildSlidableAction(
|
||||
context: context,
|
||||
backgroundColor: const Color(0xFFD7E6F4),
|
||||
foregroundColor: const Color(0xFF0058AB),
|
||||
icon: CupertinoIcons.repeat,
|
||||
onPressed: () {},
|
||||
),
|
||||
const WSpace(8),
|
||||
_buildSlidableAction(
|
||||
context: context,
|
||||
backgroundColor: AppColors.secondary,
|
||||
foregroundColor: AppColors.primary,
|
||||
icon: CupertinoIcons.move,
|
||||
onPressed: () {
|
||||
showCuperModalBottomSheet(
|
||||
context: context,
|
||||
height: 394.h,
|
||||
backgroundColor: AppColors.gray_bg,
|
||||
builder: (BuildContext context) => const ReplaceDialog(),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(12)).r,
|
||||
color: Colors.white,
|
||||
),
|
||||
constraints: BoxConstraints(minHeight: 50.h),
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
SizedBox(
|
||||
height: 50.h,
|
||||
width: double.infinity,
|
||||
child: DecoratedBox(decoration: getDecoration()),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(12).r,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
_buildImage(),
|
||||
_buildText(context),
|
||||
Wif(
|
||||
condition: type == CardType.SHOW,
|
||||
builder: (BuildContext context) => _editBtm(),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Кнопка редактирования
|
||||
Widget _editBtm() {
|
||||
return GestureDetector(
|
||||
onTap: () {},
|
||||
child: Assets.icons.typeEdit.image(height: 24.h, width: 24.w),
|
||||
);
|
||||
}
|
||||
|
||||
///
|
||||
/// Кнопка в меню свайпа
|
||||
///
|
||||
Widget _buildSlidableAction({
|
||||
required BuildContext context,
|
||||
required Color backgroundColor,
|
||||
required Color foregroundColor,
|
||||
required IconData icon,
|
||||
required VoidCallback onPressed,
|
||||
}) {
|
||||
return SlidableAction(
|
||||
borderRadius: BorderRadius.circular(12).r,
|
||||
onPressed: (_) => onPressed(),
|
||||
backgroundColor: backgroundColor,
|
||||
foregroundColor: foregroundColor,
|
||||
icon: icon,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildText(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: onTextTap,
|
||||
child: SizedBox(
|
||||
width:
|
||||
type == CardType.CREATE
|
||||
? 250.w
|
||||
: index % 4 == 0
|
||||
? 228.w
|
||||
: 300.w,
|
||||
child: ReadMoreText(
|
||||
isExpandable: true,
|
||||
index % 2 == 0
|
||||
? 'Наше дело не так однозначно, как может показаться: высокотехнологичная концепция общественного уклада напрямую зависит от вывода текущих активов. Ясность нашей позиции очевидна: высокотехнологичная концепция общественного уклада влечет за собой процесс внедрения и модернизации первоочередных требований. Лишь многие известные личности будут указаны как претенденты на роль ключевых факторов.'
|
||||
: 'Аргумент или не аргумент, вот вообще хз',
|
||||
trimMode: TrimMode.Line,
|
||||
trimLines: 3,
|
||||
trimCollapsedText: '\nРазвернуть',
|
||||
trimExpandedText: '\nСвернуть',
|
||||
style: Regular16px().style,
|
||||
moreStyle: Regular12px().style.copyWith(
|
||||
color: AppColors.primary_blue,
|
||||
),
|
||||
lessStyle: Regular12px().style.copyWith(
|
||||
color: AppColors.primary_blue,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Картинка
|
||||
Widget _buildImage() {
|
||||
return Wif(
|
||||
condition: type == CardType.SHOW,
|
||||
builder: (BuildContext context) {
|
||||
return Wif(
|
||||
condition: index % 4 == 0,
|
||||
builder: (BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(right: 8).r,
|
||||
child: SizedBox.square(
|
||||
dimension: 64.r,
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(8)).r,
|
||||
image: DecorationImage(
|
||||
image: Assets.images.imgCard.provider(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
fallback: (BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(right: 8).r,
|
||||
child: SizedBox.square(
|
||||
dimension: 64.r,
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(8)).r,
|
||||
gradient: const LinearGradient(
|
||||
colors: <Color>[Color(0xFFDBD7F4), Color(0xFFB6AAFE)],
|
||||
begin: Alignment.topRight,
|
||||
end: Alignment.bottomLeft,
|
||||
),
|
||||
),
|
||||
child: Center(
|
||||
child: Assets.icons.typePhoto.image(
|
||||
height: 24.h,
|
||||
width: 24.w,
|
||||
color: AppColors.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Декорирование контейнера
|
||||
BoxDecoration getDecoration() {
|
||||
return BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(12)).r,
|
||||
gradient: LinearGradient(
|
||||
colors: <Color>[
|
||||
index % 3 == 0 ? AppColors.question : AppColors.answer,
|
||||
Colors.white,
|
||||
],
|
||||
begin: Alignment.topLeft,
|
||||
end: const Alignment(-0.6, 1),
|
||||
stops: const <double>[0.25, 0.25],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user