Пачка экранов и логики #3

Merged
Dimkov966 merged 8 commits from feature/collection into develop 2025-04-02 20:13:12 +00:00
4 changed files with 124 additions and 121 deletions
Showing only changes of commit 49d21cc34b - Show all commits

View File

@@ -13,6 +13,7 @@ import 'package:remever/components/extensions/context.dart';
import 'package:remever/database/database.dart'; import 'package:remever/database/database.dart';
import 'package:remever/gen/assets.gen.dart'; import 'package:remever/gen/assets.gen.dart';
import 'package:remever/inject.dart'; import 'package:remever/inject.dart';
import 'package:remever/screens/collections/collections_screen.dart';
import 'package:remever/screens/collections/widgets/ticket_card.dart'; import 'package:remever/screens/collections/widgets/ticket_card.dart';
import 'package:remever/screens/dialogs/info_dialog.dart'; import 'package:remever/screens/dialogs/info_dialog.dart';
import 'package:remever/services/tickets/tickets_interface.dart'; import 'package:remever/services/tickets/tickets_interface.dart';
@@ -50,7 +51,6 @@ class CollectionDetailScreen extends StatelessWidget {
shadowColor: Colors.transparent, shadowColor: Colors.transparent,
leading: IconButton( leading: IconButton(
onPressed: () async { onPressed: () async {
// context.read<HomeCubit>().toCollection();
context.back(); context.back();
}, },
icon: const Icon(CupertinoIcons.left_chevron, color: Colors.black), icon: const Icon(CupertinoIcons.left_chevron, color: Colors.black),
@@ -172,7 +172,34 @@ class CollectionDetailScreen extends StatelessWidget {
return Padding( return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16).r, padding: const EdgeInsets.symmetric(horizontal: 16).r,
child: _buildList(context), child: StreamBuilder<List<Ticket>>(
stream: getIt<TicketsInterface>().watchTicketsList(collection.id),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const LoadingList();
}
if (snapshot.hasError) {
return const ErrorList();
}
final tickets = snapshot.data;
if (tickets == null || tickets.isEmpty) {
return _buildEmptyList(context);
}
return ListView.builder(
itemCount: tickets.length,
physics: BouncingScrollPhysics(),
itemBuilder:
(context, index) => TicketCard(
currentCollection: collection,
ticket: tickets[index],
),
);
},
),
// child: _buildList(context),
); );
} }
@@ -201,16 +228,4 @@ class CollectionDetailScreen extends StatelessWidget {
child: AppTypography('Создать карточку', type: Regular14px()), child: AppTypography('Создать карточку', type: Regular14px()),
); );
} }
///
/// Построение списка карточек
///
Widget _buildList(BuildContext context) {
return ListView.builder(
physics: BouncingScrollPhysics(),
itemCount: 10,
itemBuilder:
(BuildContext context, int index) => TicketCard(index: index),
);
}
} }

View File

@@ -129,6 +129,7 @@ class _CollectionSearchScreenState extends State<CollectionSearchScreen> {
return ListView.builder( return ListView.builder(
itemCount: collections.length, itemCount: collections.length,
physics: BouncingScrollPhysics(),
padding: const EdgeInsets.symmetric(horizontal: 16).r, padding: const EdgeInsets.symmetric(horizontal: 16).r,
itemBuilder: itemBuilder:
(context, index) => Padding( (context, index) => Padding(

View File

@@ -96,6 +96,7 @@ class _CollectionScreenState extends State<CollectionScreen> {
} }
return ListView.builder( return ListView.builder(
physics: BouncingScrollPhysics(),
controller: _scrollController, controller: _scrollController,
itemCount: collections.length, itemCount: collections.length,
padding: const EdgeInsets.symmetric(horizontal: 16).r, padding: const EdgeInsets.symmetric(horizontal: 16).r,

View File

@@ -8,30 +8,61 @@ import 'package:remever/common/typography.dart';
import 'package:remever/common/widgets/w_if.dart'; import 'package:remever/common/widgets/w_if.dart';
import 'package:remever/common/widgets/wspace.dart'; import 'package:remever/common/widgets/wspace.dart';
import 'package:remever/components/extensions/context.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/gen/assets.gen.dart';
import 'package:remever/screens/dialogs/alert_dialog.dart'; import 'package:remever/screens/dialogs/alert_dialog.dart';
import 'package:remever/screens/dialogs/replace_diaog.dart'; import 'package:remever/screens/dialogs/replace_diaog.dart';
enum CardType { CREATE, SHOW } class TicketCard extends StatefulWidget {
const TicketCard({
class TicketCard extends StatelessWidget { required this.ticket,
TicketCard({ required this.currentCollection,
required this.index,
super.key, super.key,
this.type = CardType.SHOW,
this.onTextTap,
}); });
final int index; final Collection currentCollection;
final CardType type; final Ticket ticket;
void Function()? onTextTap;
@override
State<TicketCard> createState() => _TicketCardState();
}
class _TicketCardState extends State<TicketCard> {
bool _isRolled = false;
void _onDeleteTap() {
showCuperModalBottomSheet(
context: context,
height: 262.h,
builder:
(BuildContext context) => const AlertInfoDialog(
title: 'Вы хотите удалить карточку?\nЭто действие необратимо',
acceptTitle: 'Да, удалить',
declineTitle: 'Нет, оставить',
),
);
}
void _onReplaceTap() {
showCuperModalBottomSheet(
context: context,
height: 394.h,
backgroundColor: AppColors.gray_bg,
builder: (BuildContext context) => const ReplaceDialog(),
);
}
void _onRollTap() {
safeSetState(() => _isRolled = !_isRolled);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Padding( return Padding(
padding: const EdgeInsets.only(top: 8).r, padding: const EdgeInsets.only(top: 8).r,
child: Slidable( child: Slidable(
enabled: type == CardType.SHOW ? true : false, enabled: true,
endActionPane: ActionPane( endActionPane: ActionPane(
extentRatio: 0.62, extentRatio: 0.62,
motion: const StretchMotion(), motion: const StretchMotion(),
@@ -42,19 +73,7 @@ class TicketCard extends StatelessWidget {
backgroundColor: const Color(0xFFFFE4E6), backgroundColor: const Color(0xFFFFE4E6),
foregroundColor: const Color(0xFFFF5C69), foregroundColor: const Color(0xFFFF5C69),
icon: CupertinoIcons.trash, icon: CupertinoIcons.trash,
onPressed: () { onPressed: () => _onDeleteTap(),
showCuperModalBottomSheet(
context: context,
height: 262.h,
builder:
(BuildContext context) => const AlertInfoDialog(
title:
'Вы хотите удалить карточку?\nЭто действие необратимо',
acceptTitle: 'Да, удалить',
declineTitle: 'Нет, оставить',
),
);
},
), ),
const WSpace(8), const WSpace(8),
_buildSlidableAction( _buildSlidableAction(
@@ -62,7 +81,7 @@ class TicketCard extends StatelessWidget {
backgroundColor: const Color(0xFFD7E6F4), backgroundColor: const Color(0xFFD7E6F4),
foregroundColor: const Color(0xFF0058AB), foregroundColor: const Color(0xFF0058AB),
icon: CupertinoIcons.repeat, icon: CupertinoIcons.repeat,
onPressed: () {}, onPressed: () => _onRollTap(),
), ),
const WSpace(8), const WSpace(8),
_buildSlidableAction( _buildSlidableAction(
@@ -70,14 +89,7 @@ class TicketCard extends StatelessWidget {
backgroundColor: AppColors.secondary, backgroundColor: AppColors.secondary,
foregroundColor: AppColors.primary, foregroundColor: AppColors.primary,
icon: CupertinoIcons.move, icon: CupertinoIcons.move,
onPressed: () { onPressed: () => _onReplaceTap(),
showCuperModalBottomSheet(
context: context,
height: 394.h,
backgroundColor: AppColors.gray_bg,
builder: (BuildContext context) => const ReplaceDialog(),
);
},
), ),
], ],
), ),
@@ -104,10 +116,7 @@ class TicketCard extends StatelessWidget {
children: <Widget>[ children: <Widget>[
_buildImage(), _buildImage(),
_buildText(context), _buildText(context),
Wif( _buildEditButton(),
condition: type == CardType.SHOW,
builder: (BuildContext context) => _editBtm(),
),
], ],
), ),
], ],
@@ -121,7 +130,7 @@ class TicketCard extends StatelessWidget {
} }
/// Кнопка редактирования /// Кнопка редактирования
Widget _editBtm() { Widget _buildEditButton() {
return GestureDetector( return GestureDetector(
onTap: () {}, onTap: () {},
child: Assets.icons.typeEdit.image(height: 24.h, width: 24.w), child: Assets.icons.typeEdit.image(height: 24.h, width: 24.w),
@@ -148,32 +157,17 @@ class TicketCard extends StatelessWidget {
} }
Widget _buildText(BuildContext context) { Widget _buildText(BuildContext context) {
return GestureDetector( return Expanded(
onTap: onTextTap,
child: SizedBox(
width:
type == CardType.CREATE
? 250.w
: index % 4 == 0
? 228.w
: 300.w,
child: ReadMoreText( child: ReadMoreText(
isExpandable: true, isExpandable: true,
index % 2 == 0 _isRolled ? widget.ticket.answer : widget.ticket.question,
? 'Наше дело не так однозначно, как может показаться: высокотехнологичная концепция общественного уклада напрямую зависит от вывода текущих активов. Ясность нашей позиции очевидна: высокотехнологичная концепция общественного уклада влечет за собой процесс внедрения и модернизации первоочередных требований. Лишь многие известные личности будут указаны как претенденты на роль ключевых факторов.'
: 'Аргумент или не аргумент, вот вообще хз',
trimMode: TrimMode.Line, trimMode: TrimMode.Line,
trimLines: 3, trimLines: 3,
trimCollapsedText: '\nРазвернуть', trimCollapsedText: '\nРазвернуть',
trimExpandedText: '\nСвернуть', trimExpandedText: '\nСвернуть',
style: Regular16px().style, style: Regular16px().style,
moreStyle: Regular12px().style.copyWith( moreStyle: Regular12px().style.copyWith(color: AppColors.primary_blue),
color: AppColors.primary_blue, lessStyle: Regular12px().style.copyWith(color: AppColors.primary_blue),
),
lessStyle: Regular12px().style.copyWith(
color: AppColors.primary_blue,
),
),
), ),
); );
} }
@@ -181,53 +175,45 @@ class TicketCard extends StatelessWidget {
/// Картинка /// Картинка
Widget _buildImage() { Widget _buildImage() {
return Wif( return Wif(
condition: type == CardType.SHOW, condition: _isRolled,
builder: (BuildContext context) { builder:
return Wif( (context) => Wif(
condition: index % 4 == 0, condition: widget.ticket.answerImage != null,
builder: (BuildContext context) { builder: (BuildContext context) {
return Padding( return Padding(
padding: const EdgeInsets.only(right: 8).r, padding: const EdgeInsets.only(right: 8).r,
child: SizedBox.square( child: SizedBox.square(
dimension: 64.r, dimension: 64.r,
child: DecoratedBox( child: ClipRRect(
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(8)).r, borderRadius: const BorderRadius.all(Radius.circular(8)).r,
image: DecorationImage( child: Image.memory(
image: Assets.images.imgCard.provider(), widget.ticket.answerImage!,
), fit: BoxFit.cover,
), ),
), ),
), ),
); );
}, },
); ),
}, fallback:
fallback: (BuildContext context) { (context) => Wif(
condition: widget.ticket.questionImage != null,
builder: (BuildContext context) {
return Padding( return Padding(
padding: const EdgeInsets.only(right: 8).r, padding: const EdgeInsets.only(right: 8).r,
child: SizedBox.square( child: SizedBox.square(
dimension: 64.r, dimension: 64.r,
child: DecoratedBox( child: ClipRRect(
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(8)).r, borderRadius: const BorderRadius.all(Radius.circular(8)).r,
gradient: const LinearGradient( child: Image.memory(
colors: <Color>[Color(0xFFDBD7F4), Color(0xFFB6AAFE)], widget.ticket.questionImage!,
begin: Alignment.topRight, fit: BoxFit.cover,
end: Alignment.bottomLeft,
),
),
child: Center(
child: Assets.icons.typePhoto.image(
height: 24.h,
width: 24.w,
color: AppColors.primary,
),
), ),
), ),
), ),
); );
}, },
),
); );
} }
@@ -237,7 +223,7 @@ class TicketCard extends StatelessWidget {
borderRadius: const BorderRadius.all(Radius.circular(12)).r, borderRadius: const BorderRadius.all(Radius.circular(12)).r,
gradient: LinearGradient( gradient: LinearGradient(
colors: <Color>[ colors: <Color>[
index % 3 == 0 ? AppColors.question : AppColors.answer, _isRolled ? AppColors.answer : AppColors.question,
Colors.white, Colors.white,
], ],
begin: Alignment.topLeft, begin: Alignment.topLeft,