diff --git a/lib/screens/collections/collection_detail_screen.dart b/lib/screens/collections/collection_detail_screen.dart index 934fb48..f4e4d65 100644 --- a/lib/screens/collections/collection_detail_screen.dart +++ b/lib/screens/collections/collection_detail_screen.dart @@ -13,6 +13,7 @@ import 'package:remever/components/extensions/context.dart'; import 'package:remever/database/database.dart'; import 'package:remever/gen/assets.gen.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/dialogs/info_dialog.dart'; import 'package:remever/services/tickets/tickets_interface.dart'; @@ -50,7 +51,6 @@ class CollectionDetailScreen extends StatelessWidget { shadowColor: Colors.transparent, leading: IconButton( onPressed: () async { - // context.read().toCollection(); context.back(); }, icon: const Icon(CupertinoIcons.left_chevron, color: Colors.black), @@ -172,7 +172,34 @@ class CollectionDetailScreen extends StatelessWidget { return Padding( padding: const EdgeInsets.symmetric(horizontal: 16).r, - child: _buildList(context), + child: StreamBuilder>( + stream: getIt().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()), ); } - - /// - /// Построение списка карточек - /// - Widget _buildList(BuildContext context) { - return ListView.builder( - physics: BouncingScrollPhysics(), - itemCount: 10, - itemBuilder: - (BuildContext context, int index) => TicketCard(index: index), - ); - } } diff --git a/lib/screens/collections/collection_search_screen.dart b/lib/screens/collections/collection_search_screen.dart index 3213ba0..61cbfee 100644 --- a/lib/screens/collections/collection_search_screen.dart +++ b/lib/screens/collections/collection_search_screen.dart @@ -129,6 +129,7 @@ class _CollectionSearchScreenState extends State { return ListView.builder( itemCount: collections.length, + physics: BouncingScrollPhysics(), padding: const EdgeInsets.symmetric(horizontal: 16).r, itemBuilder: (context, index) => Padding( diff --git a/lib/screens/collections/collections_screen.dart b/lib/screens/collections/collections_screen.dart index c44e4cf..7420c81 100644 --- a/lib/screens/collections/collections_screen.dart +++ b/lib/screens/collections/collections_screen.dart @@ -96,6 +96,7 @@ class _CollectionScreenState extends State { } return ListView.builder( + physics: BouncingScrollPhysics(), controller: _scrollController, itemCount: collections.length, padding: const EdgeInsets.symmetric(horizontal: 16).r, diff --git a/lib/screens/collections/widgets/ticket_card.dart b/lib/screens/collections/widgets/ticket_card.dart index 0430464..fc6ce23 100644 --- a/lib/screens/collections/widgets/ticket_card.dart +++ b/lib/screens/collections/widgets/ticket_card.dart @@ -8,30 +8,61 @@ 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/components/extensions/state.dart'; +import 'package:remever/database/database.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 TicketCard extends StatelessWidget { - TicketCard({ - required this.index, +class TicketCard extends StatefulWidget { + const TicketCard({ + required this.ticket, + required this.currentCollection, super.key, - this.type = CardType.SHOW, - this.onTextTap, }); - final int index; - final CardType type; - void Function()? onTextTap; + final Collection currentCollection; + final Ticket ticket; + + @override + State createState() => _TicketCardState(); +} + +class _TicketCardState extends State { + 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 Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.only(top: 8).r, child: Slidable( - enabled: type == CardType.SHOW ? true : false, + enabled: true, endActionPane: ActionPane( extentRatio: 0.62, motion: const StretchMotion(), @@ -42,19 +73,7 @@ class TicketCard extends StatelessWidget { 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: 'Нет, оставить', - ), - ); - }, + onPressed: () => _onDeleteTap(), ), const WSpace(8), _buildSlidableAction( @@ -62,7 +81,7 @@ class TicketCard extends StatelessWidget { backgroundColor: const Color(0xFFD7E6F4), foregroundColor: const Color(0xFF0058AB), icon: CupertinoIcons.repeat, - onPressed: () {}, + onPressed: () => _onRollTap(), ), const WSpace(8), _buildSlidableAction( @@ -70,14 +89,7 @@ class TicketCard extends StatelessWidget { 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(), - ); - }, + onPressed: () => _onReplaceTap(), ), ], ), @@ -104,10 +116,7 @@ class TicketCard extends StatelessWidget { children: [ _buildImage(), _buildText(context), - Wif( - condition: type == CardType.SHOW, - builder: (BuildContext context) => _editBtm(), - ), + _buildEditButton(), ], ), ], @@ -121,7 +130,7 @@ class TicketCard extends StatelessWidget { } /// Кнопка редактирования - Widget _editBtm() { + Widget _buildEditButton() { return GestureDetector( onTap: () {}, child: Assets.icons.typeEdit.image(height: 24.h, width: 24.w), @@ -148,32 +157,17 @@ class TicketCard extends StatelessWidget { } 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, - ), - ), + return Expanded( + child: ReadMoreText( + isExpandable: true, + _isRolled ? widget.ticket.answer : widget.ticket.question, + 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), ), ); } @@ -181,53 +175,45 @@ class TicketCard extends StatelessWidget { /// Картинка 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( + condition: _isRolled, + builder: + (context) => Wif( + condition: widget.ticket.answerImage != null, + builder: (BuildContext context) { + return Padding( + padding: const EdgeInsets.only(right: 8).r, + child: SizedBox.square( + dimension: 64.r, + child: ClipRRect( borderRadius: const BorderRadius.all(Radius.circular(8)).r, - image: DecorationImage( - image: Assets.images.imgCard.provider(), + child: Image.memory( + widget.ticket.answerImage!, + fit: BoxFit.cover, ), ), ), - ), - ); - }, - ); - }, - 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(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, - ), - ), - ), + ); + }, + ), + fallback: + (context) => Wif( + condition: widget.ticket.questionImage != null, + builder: (BuildContext context) { + return Padding( + padding: const EdgeInsets.only(right: 8).r, + child: SizedBox.square( + dimension: 64.r, + child: ClipRRect( + borderRadius: const BorderRadius.all(Radius.circular(8)).r, + child: Image.memory( + widget.ticket.questionImage!, + fit: BoxFit.cover, + ), + ), + ), + ); + }, ), - ); - }, ); } @@ -237,7 +223,7 @@ class TicketCard extends StatelessWidget { borderRadius: const BorderRadius.all(Radius.circular(12)).r, gradient: LinearGradient( colors: [ - index % 3 == 0 ? AppColors.question : AppColors.answer, + _isRolled ? AppColors.answer : AppColors.question, Colors.white, ], begin: Alignment.topLeft,