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

Merged
Dimkov966 merged 8 commits from feature/collection into develop 2025-04-02 20:13:12 +00:00
13 changed files with 194 additions and 1231 deletions
Showing only changes of commit 588c026f27 - Show all commits

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -4,7 +4,6 @@ import 'package:remever/common/functions.dart';
import 'package:remever/database/database.dart';
import 'package:remever/database/tables.dart';
import 'package:remever/models/create_ticket_dto.dart';
import 'package:remever/models/crud_collection_dto.dart';
part 'tickets_dao.g.dart';
@@ -29,9 +28,11 @@ class TicketsDao extends DatabaseAccessor<AppDatabase> with _$TicketsDaoMixin {
}
/// Удаление билета
Future<void> deleteTicket(String id) async {
Future<void> removeTicket(String id) async {
try {
await db.managers.tickets.filter((f) => f.id(id)).delete();
await db.transaction(() {
return db.managers.tickets.filter((f) => f.id(id)).delete();
});
} catch (e, st) {
logger.logError('Ошибка в методе deleteTicket', e, st);
}
@@ -67,4 +68,15 @@ class TicketsDao extends DatabaseAccessor<AppDatabase> with _$TicketsDaoMixin {
logger.logError('Ошибка в методе createTicket', e, st);
}
}
/// Перенос билета с одной коллекции в другую
Future<void> transferTicket(String ticketId, String newCollectionId) async {
try {
await db.managers.tickets
.filter((f) => f.id(ticketId))
.update((o) => o(collectionId: Value<String>(newCollectionId)));
} catch (e, st) {
logger.logError('Ошибка в методе transferTicket', e, st);
}
}
}

View File

@@ -11,8 +11,10 @@ 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/screens/dialogs/alert_dialog.dart';
import 'package:remever/screens/dialogs/replace_diaog.dart';
import 'package:remever/services/tickets/tickets_interface.dart';
class TicketCard extends StatefulWidget {
const TicketCard({
@@ -31,8 +33,8 @@ class TicketCard extends StatefulWidget {
class _TicketCardState extends State<TicketCard> {
bool _isRolled = false;
void _onDeleteTap() {
showCuperModalBottomSheet(
void _onDeleteTap() async {
final bool? res = await showCuperModalBottomSheet(
context: context,
height: 262.h,
builder:
@@ -42,14 +44,22 @@ class _TicketCardState extends State<TicketCard> {
declineTitle: 'Нет, оставить',
),
);
if (res != null && res) {
await getIt<TicketsInterface>().removeTicket(widget.ticket.id);
}
}
void _onReplaceTap() {
showCuperModalBottomSheet(
context: context,
height: 394.h,
height: 420.h,
backgroundColor: AppColors.gray_bg,
builder: (_) => const ReplaceDialog(),
builder:
(_) => ReplaceDialog(
currentCollection: widget.currentCollection,
ticket: widget.ticket,
),
);
}

View File

@@ -1,23 +1,74 @@
import 'dart:math';
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:remever/common/functions.dart';
import 'package:remever/common/resources.dart';
import 'package:remever/common/utils.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/i18n/strings.g.dart';
import 'package:remever/inject.dart';
import 'package:remever/router.gr.dart';
import 'package:remever/screens/collections/widgets/collection_progress_bar.dart';
import 'package:remever/screens/dialogs/dialog_header.dart';
import 'package:remever/services/tickets/tickets_interface.dart';
import 'package:remever/widgets/primary_button.dart';
class ReplaceDialog extends StatelessWidget {
const ReplaceDialog({super.key});
class ReplaceDialog extends StatefulWidget {
const ReplaceDialog({
super.key,
required this.currentCollection,
required this.ticket,
});
final Collection currentCollection;
final Ticket ticket;
@override
State<ReplaceDialog> createState() => _ReplaceDialogState();
}
class _ReplaceDialogState extends State<ReplaceDialog> {
Collection? _collectionToTransfer;
void _onCollectionTap() {
context.pushRoute(
CollectionSearchRoute(
onCollectionSelect: (collection) {
safeSetState(() => _collectionToTransfer = collection);
},
),
);
}
void _onTransferTap() async {
if (_collectionToTransfer == null) {
showErrorToast('Необходимо выбрать место для переноса');
return;
}
if (_collectionToTransfer!.id == widget.currentCollection.id) {
showErrorToast('Карточка итак в этой коллекции, выберете другую');
return;
}
await getIt<TicketsInterface>().transferTicket(
widget.ticket.id,
_collectionToTransfer!.id,
);
Navigator.of(context).pop();
}
@override
Widget build(BuildContext context) {
return Column(
return Material(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
const DialogHeader(title: 'Переместить карточку'),
@@ -29,7 +80,7 @@ class ReplaceDialog extends StatelessWidget {
children: <Widget>[
AppTypography('из коллекции', type: Medium16px()),
const HSpace(8),
_buildCollection(context),
_buildCollection(widget.currentCollection),
const HSpace(16),
Center(
child: SizedBox.square(
@@ -51,45 +102,31 @@ class ReplaceDialog extends StatelessWidget {
const HSpace(16),
AppTypography('в коллекцию', type: Medium16px()),
const HSpace(8),
_buildCollection(context),
_buildCollection(_collectionToTransfer, isSelectable: true),
const HSpace(16),
_createBtn(context),
_buildTransferButton(context),
],
),
),
],
);
}
Widget _createBtn(BuildContext context) {
return GestureDetector(
onTap: () {
Navigator.of(context).pop();
// context.read<HomeCubit>().toCrudCollection(CrudType.CREATE);
context.pushRoute(CrudCollectionRoute());
},
child: Row(
children: <Widget>[
SizedBox.square(
dimension: 20.r,
child: DecoratedBox(
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: AppColors.gray,
),
child: Assets.icons.typePlus.image(color: Colors.black54),
),
),
const WSpace(4),
AppTypography('Создать и перенести в новую', type: Regular16px()),
],
),
);
}
Widget _buildCollection(BuildContext context) {
Widget _buildTransferButton(BuildContext context) {
return PrimaryButton(
child: AppTypography(
'Перенести',
type: Regular14px(),
color: AppColors.white,
),
onTap: () => _onTransferTap(),
);
}
Widget _buildCollection(Collection? collection, {bool isSelectable = false}) {
return GestureDetector(
onTap: () {},
onTap: isSelectable ? () => _onCollectionTap() : null,
child: Container(
constraints: BoxConstraints(minHeight: 66.h, maxHeight: 84.h),
decoration: BoxDecoration(
@@ -97,8 +134,20 @@ class ReplaceDialog extends StatelessWidget {
color: AppColors.white,
),
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8).r,
child: Row(
children: <Widget>[_buildAvatar(), const WSpace(5), _buildInfo()],
child:
collection == null
? Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
AppTypography('Выберите коллекцию', type: Bold14px()),
],
)
: Row(
children: <Widget>[
_buildAvatar(collection),
const WSpace(5),
_buildInfo(collection),
],
),
),
);
@@ -107,17 +156,17 @@ class ReplaceDialog extends StatelessWidget {
///
/// Построение основной информации
///
Widget _buildInfo() {
Widget _buildInfo(Collection collection) {
return SizedBox(
width: 230.w,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
_buildTitle(),
_buildTitle(collection),
const HSpace(4),
Row(
children: <Widget>[
children: [
Assets.icons.typeCards.image(
height: 18.h,
width: 18.w,
@@ -125,7 +174,7 @@ class ReplaceDialog extends StatelessWidget {
),
const WSpace(2),
AppTypography(
Random().nextInt(654).toString(),
'${collection.likesCount.toString()} ${Utils.declOfNum(collection.likesCount, ['карточек', 'карточки', 'карточек'])}',
type: Regular14px(),
color: AppColors.disabled,
),
@@ -141,9 +190,9 @@ class ReplaceDialog extends StatelessWidget {
///
/// Название коллекции
///
Widget _buildTitle() {
Widget _buildTitle(Collection collection) {
return AppTypography(
'Астрономия',
collection.title,
type: Medium16px(),
maxLines: 2,
softWrap: true,
@@ -153,13 +202,24 @@ class ReplaceDialog extends StatelessWidget {
///
/// Обложка коллекции
///
Widget _buildAvatar() {
Widget _buildAvatar(Collection collection) {
return SizedBox.square(
dimension: 50.r,
child: DecoratedBox(
decoration: BoxDecoration(
shape: BoxShape.circle,
image: DecorationImage(image: Assets.images.img.provider()),
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(),
),
),
),
),
);

View File

@@ -10,4 +10,10 @@ abstract interface class TicketsInterface {
/// Создание нового билета
Future<void> createTicket(CreateTicketDto dto);
/// Удаление нового билета
Future<void> removeTicket(String ticketId);
/// Перенос билета в другую коллекцию
Future<void> transferTicket(String ticketId, String newCollectionId);
}

View File

@@ -19,4 +19,17 @@ final class TicketsService implements TicketsInterface {
Future<void> createTicket(CreateTicketDto dto) async {
return await getIt<AppDatabase>().ticketsDao.createTicket(dto);
}
@override
Future<void> removeTicket(String ticketId) async {
return await getIt<AppDatabase>().ticketsDao.removeTicket(ticketId);
}
@override
Future<void> transferTicket(String ticketId, String newCollectionId) async {
return await getIt<AppDatabase>().ticketsDao.transferTicket(
ticketId,
newCollectionId,
);
}
}