Пачка экранов и логики #3
File diff suppressed because one or more lines are too long
Binary file not shown.
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
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,95 +1,132 @@
|
||||
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(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
const DialogHeader(title: 'Переместить карточку'),
|
||||
const HSpace(16),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 28).r,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
AppTypography('из коллекции', type: Medium16px()),
|
||||
const HSpace(8),
|
||||
_buildCollection(context),
|
||||
const HSpace(16),
|
||||
Center(
|
||||
child: SizedBox.square(
|
||||
dimension: 34.r,
|
||||
child: DecoratedBox(
|
||||
decoration: const BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: AppColors.gray,
|
||||
),
|
||||
child: Center(
|
||||
child: Assets.icons.typeArrowDown.image(
|
||||
height: 18.h,
|
||||
width: 18.w,
|
||||
return Material(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
const DialogHeader(title: 'Переместить карточку'),
|
||||
const HSpace(16),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 28).r,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
AppTypography('из коллекции', type: Medium16px()),
|
||||
const HSpace(8),
|
||||
_buildCollection(widget.currentCollection),
|
||||
const HSpace(16),
|
||||
Center(
|
||||
child: SizedBox.square(
|
||||
dimension: 34.r,
|
||||
child: DecoratedBox(
|
||||
decoration: const BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: AppColors.gray,
|
||||
),
|
||||
child: Center(
|
||||
child: Assets.icons.typeArrowDown.image(
|
||||
height: 18.h,
|
||||
width: 18.w,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const HSpace(16),
|
||||
AppTypography('в коллекцию', type: Medium16px()),
|
||||
const HSpace(8),
|
||||
_buildCollection(context),
|
||||
const HSpace(16),
|
||||
_createBtn(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 HSpace(16),
|
||||
AppTypography('в коллекцию', type: Medium16px()),
|
||||
const HSpace(8),
|
||||
_buildCollection(_collectionToTransfer, isSelectable: true),
|
||||
const HSpace(16),
|
||||
_buildTransferButton(context),
|
||||
],
|
||||
),
|
||||
),
|
||||
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,9 +134,21 @@ 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(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user