feature(training): отбражение данных для тренировки
This commit is contained in:
@@ -28,6 +28,18 @@ class CollectionsDao extends DatabaseAccessor<AppDatabase>
|
||||
}
|
||||
}
|
||||
|
||||
Future<Collection?> getCollectionById(String? id) {
|
||||
try {
|
||||
return db.managers.collections
|
||||
.filter((f) => f.id.equals(id))
|
||||
.getSingleOrNull();
|
||||
} catch (e, st) {
|
||||
logger.logError('Ошибка в методе getCollectionById', e, st);
|
||||
|
||||
throw ('EXEPTION');
|
||||
}
|
||||
}
|
||||
|
||||
/// Создание коллекции
|
||||
Future<void> createCollection(CrudCollectionDto dto) async {
|
||||
try {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/// Locales: 2
|
||||
/// Strings: 20 (10 per locale)
|
||||
///
|
||||
/// Built on 2025-09-08 at 14:50 UTC
|
||||
/// Built on 2025-09-08 at 19:38 UTC
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: type=lint, unused_import
|
||||
|
||||
@@ -23,6 +23,8 @@ import 'services/core/theme_service.dart' as _i84;
|
||||
import 'services/logs/logs_service.dart' as _i393;
|
||||
import 'services/tickets/tickets_interface.dart' as _i147;
|
||||
import 'services/tickets/tickets_service.dart' as _i548;
|
||||
import 'services/training/training_interface.dart' as _i813;
|
||||
import 'services/training/training_service.dart' as _i162;
|
||||
import 'services/warmup_service.dart' as _i564;
|
||||
|
||||
extension GetItInjectableX on _i174.GetIt {
|
||||
@@ -37,6 +39,7 @@ extension GetItInjectableX on _i174.GetIt {
|
||||
gh.factory<_i84.ThemeService>(() => _i84.ThemeService());
|
||||
gh.singleton<_i565.AppDatabase>(() => _i565.AppDatabase());
|
||||
gh.singleton<_i393.LogsService>(() => _i393.LogsService());
|
||||
gh.singleton<_i813.TrainingInterface>(() => _i162.TrainingService());
|
||||
gh.singleton<_i147.TicketsInterface>(() => _i548.TicketsService());
|
||||
gh.singleton<_i764.CollectionsInterface>(() => _i1001.CollectionsService());
|
||||
gh.singleton<_i580.AuthInterface>(() => _i975.AuthService());
|
||||
|
||||
14
lib/models/training_dto.dart
Normal file
14
lib/models/training_dto.dart
Normal file
@@ -0,0 +1,14 @@
|
||||
// To parse this JSON data, do
|
||||
//
|
||||
// final collectionDto = collectionDtoFromJson(jsonString);
|
||||
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:remever/database/database.dart';
|
||||
|
||||
part 'training_dto.freezed.dart';
|
||||
|
||||
@Freezed(copyWith: true, equal: true, fromJson: false, toJson: false)
|
||||
abstract class TrainingDto with _$TrainingDto {
|
||||
const factory TrainingDto({Collection? collection, required Ticket ticket}) =
|
||||
_TrainingDto;
|
||||
}
|
||||
176
lib/models/training_dto.freezed.dart
Normal file
176
lib/models/training_dto.freezed.dart
Normal file
@@ -0,0 +1,176 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'training_dto.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models',
|
||||
);
|
||||
|
||||
/// @nodoc
|
||||
mixin _$TrainingDto {
|
||||
Collection? get collection => throw _privateConstructorUsedError;
|
||||
Ticket get ticket => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of TrainingDto
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$TrainingDtoCopyWith<TrainingDto> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $TrainingDtoCopyWith<$Res> {
|
||||
factory $TrainingDtoCopyWith(
|
||||
TrainingDto value,
|
||||
$Res Function(TrainingDto) then,
|
||||
) = _$TrainingDtoCopyWithImpl<$Res, TrainingDto>;
|
||||
@useResult
|
||||
$Res call({Collection? collection, Ticket ticket});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$TrainingDtoCopyWithImpl<$Res, $Val extends TrainingDto>
|
||||
implements $TrainingDtoCopyWith<$Res> {
|
||||
_$TrainingDtoCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of TrainingDto
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({Object? collection = freezed, Object? ticket = freezed}) {
|
||||
return _then(
|
||||
_value.copyWith(
|
||||
collection:
|
||||
freezed == collection
|
||||
? _value.collection
|
||||
: collection // ignore: cast_nullable_to_non_nullable
|
||||
as Collection?,
|
||||
ticket:
|
||||
freezed == ticket
|
||||
? _value.ticket
|
||||
: ticket // ignore: cast_nullable_to_non_nullable
|
||||
as Ticket,
|
||||
)
|
||||
as $Val,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$TrainingDtoImplCopyWith<$Res>
|
||||
implements $TrainingDtoCopyWith<$Res> {
|
||||
factory _$$TrainingDtoImplCopyWith(
|
||||
_$TrainingDtoImpl value,
|
||||
$Res Function(_$TrainingDtoImpl) then,
|
||||
) = __$$TrainingDtoImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({Collection? collection, Ticket ticket});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$TrainingDtoImplCopyWithImpl<$Res>
|
||||
extends _$TrainingDtoCopyWithImpl<$Res, _$TrainingDtoImpl>
|
||||
implements _$$TrainingDtoImplCopyWith<$Res> {
|
||||
__$$TrainingDtoImplCopyWithImpl(
|
||||
_$TrainingDtoImpl _value,
|
||||
$Res Function(_$TrainingDtoImpl) _then,
|
||||
) : super(_value, _then);
|
||||
|
||||
/// Create a copy of TrainingDto
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({Object? collection = freezed, Object? ticket = freezed}) {
|
||||
return _then(
|
||||
_$TrainingDtoImpl(
|
||||
collection:
|
||||
freezed == collection
|
||||
? _value.collection
|
||||
: collection // ignore: cast_nullable_to_non_nullable
|
||||
as Collection?,
|
||||
ticket:
|
||||
freezed == ticket
|
||||
? _value.ticket
|
||||
: ticket // ignore: cast_nullable_to_non_nullable
|
||||
as Ticket,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$TrainingDtoImpl implements _TrainingDto {
|
||||
const _$TrainingDtoImpl({this.collection, required this.ticket});
|
||||
|
||||
@override
|
||||
final Collection? collection;
|
||||
@override
|
||||
final Ticket ticket;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'TrainingDto(collection: $collection, ticket: $ticket)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$TrainingDtoImpl &&
|
||||
const DeepCollectionEquality().equals(
|
||||
other.collection,
|
||||
collection,
|
||||
) &&
|
||||
const DeepCollectionEquality().equals(other.ticket, ticket));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
const DeepCollectionEquality().hash(collection),
|
||||
const DeepCollectionEquality().hash(ticket),
|
||||
);
|
||||
|
||||
/// Create a copy of TrainingDto
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$TrainingDtoImplCopyWith<_$TrainingDtoImpl> get copyWith =>
|
||||
__$$TrainingDtoImplCopyWithImpl<_$TrainingDtoImpl>(this, _$identity);
|
||||
}
|
||||
|
||||
abstract class _TrainingDto implements TrainingDto {
|
||||
const factory _TrainingDto({
|
||||
final Collection? collection,
|
||||
required final Ticket ticket,
|
||||
}) = _$TrainingDtoImpl;
|
||||
|
||||
@override
|
||||
Collection? get collection;
|
||||
@override
|
||||
Ticket get ticket;
|
||||
|
||||
/// Create a copy of TrainingDto
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$TrainingDtoImplCopyWith<_$TrainingDtoImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -1,11 +1,17 @@
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:remever/database/database.dart';
|
||||
import 'package:remever/inject.dart';
|
||||
import 'package:remever/models/training_dto.dart';
|
||||
import 'package:remever/services/training/training_interface.dart';
|
||||
|
||||
part 'training_state.dart';
|
||||
part 'training_cubit.freezed.dart';
|
||||
|
||||
class TrainingCubit extends Cubit<TrainingState> {
|
||||
TrainingCubit() : super(TrainingState.data());
|
||||
TrainingCubit() : super(TrainingState.loading()) {
|
||||
init();
|
||||
}
|
||||
|
||||
Future<void> toLoading() async {
|
||||
emit(TrainingState.loading());
|
||||
@@ -16,10 +22,34 @@ class TrainingCubit extends Cubit<TrainingState> {
|
||||
}
|
||||
|
||||
Future<void> toDataState() async {
|
||||
emit(TrainingState.data());
|
||||
emit(TrainingState.data([]));
|
||||
}
|
||||
|
||||
Future<void> toResultState() async {
|
||||
emit(TrainingState.result());
|
||||
}
|
||||
|
||||
Future<void> init() async {
|
||||
final List<Ticket> data = await getIt<TrainingInterface>().getTraining();
|
||||
|
||||
if (data.isEmpty) {
|
||||
emit(TrainingState.empty());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
List<TrainingDto> dto = [];
|
||||
|
||||
for (final ticket in data) {
|
||||
dto.add(
|
||||
TrainingDto(
|
||||
ticket: ticket,
|
||||
collection: await getIt<AppDatabase>().collectionsDao
|
||||
.getCollectionById(ticket.collectionId),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
emit(TrainingState.data(dto));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,21 +21,21 @@ mixin _$TrainingState {
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() loading,
|
||||
required TResult Function() empty,
|
||||
required TResult Function() data,
|
||||
required TResult Function(List<TrainingDto> data) data,
|
||||
required TResult Function() result,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? loading,
|
||||
TResult? Function()? empty,
|
||||
TResult? Function()? data,
|
||||
TResult? Function(List<TrainingDto> data)? data,
|
||||
TResult? Function()? result,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? loading,
|
||||
TResult Function()? empty,
|
||||
TResult Function()? data,
|
||||
TResult Function(List<TrainingDto> data)? data,
|
||||
TResult Function()? result,
|
||||
required TResult orElse(),
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@@ -130,7 +130,7 @@ class _$LoadingImpl implements _Loading {
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() loading,
|
||||
required TResult Function() empty,
|
||||
required TResult Function() data,
|
||||
required TResult Function(List<TrainingDto> data) data,
|
||||
required TResult Function() result,
|
||||
}) {
|
||||
return loading();
|
||||
@@ -141,7 +141,7 @@ class _$LoadingImpl implements _Loading {
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? loading,
|
||||
TResult? Function()? empty,
|
||||
TResult? Function()? data,
|
||||
TResult? Function(List<TrainingDto> data)? data,
|
||||
TResult? Function()? result,
|
||||
}) {
|
||||
return loading?.call();
|
||||
@@ -152,7 +152,7 @@ class _$LoadingImpl implements _Loading {
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? loading,
|
||||
TResult Function()? empty,
|
||||
TResult Function()? data,
|
||||
TResult Function(List<TrainingDto> data)? data,
|
||||
TResult Function()? result,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
@@ -249,7 +249,7 @@ class _$EmptyImpl implements _Empty {
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() loading,
|
||||
required TResult Function() empty,
|
||||
required TResult Function() data,
|
||||
required TResult Function(List<TrainingDto> data) data,
|
||||
required TResult Function() result,
|
||||
}) {
|
||||
return empty();
|
||||
@@ -260,7 +260,7 @@ class _$EmptyImpl implements _Empty {
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? loading,
|
||||
TResult? Function()? empty,
|
||||
TResult? Function()? data,
|
||||
TResult? Function(List<TrainingDto> data)? data,
|
||||
TResult? Function()? result,
|
||||
}) {
|
||||
return empty?.call();
|
||||
@@ -271,7 +271,7 @@ class _$EmptyImpl implements _Empty {
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? loading,
|
||||
TResult Function()? empty,
|
||||
TResult Function()? data,
|
||||
TResult Function(List<TrainingDto> data)? data,
|
||||
TResult Function()? result,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
@@ -329,6 +329,8 @@ abstract class _$$DataImplCopyWith<$Res> {
|
||||
_$DataImpl value,
|
||||
$Res Function(_$DataImpl) then,
|
||||
) = __$$DataImplCopyWithImpl<$Res>;
|
||||
@useResult
|
||||
$Res call({List<TrainingDto> data});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -340,36 +342,67 @@ class __$$DataImplCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of TrainingState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({Object? data = null}) {
|
||||
return _then(
|
||||
_$DataImpl(
|
||||
null == data
|
||||
? _value._data
|
||||
: data // ignore: cast_nullable_to_non_nullable
|
||||
as List<TrainingDto>,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$DataImpl implements _Data {
|
||||
const _$DataImpl();
|
||||
const _$DataImpl(final List<TrainingDto> data) : _data = data;
|
||||
|
||||
final List<TrainingDto> _data;
|
||||
@override
|
||||
List<TrainingDto> get data {
|
||||
if (_data is EqualUnmodifiableListView) return _data;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_data);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'TrainingState.data()';
|
||||
return 'TrainingState.data(data: $data)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _$DataImpl);
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$DataImpl &&
|
||||
const DeepCollectionEquality().equals(other._data, _data));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => runtimeType.hashCode;
|
||||
int get hashCode =>
|
||||
Object.hash(runtimeType, const DeepCollectionEquality().hash(_data));
|
||||
|
||||
/// Create a copy of TrainingState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$DataImplCopyWith<_$DataImpl> get copyWith =>
|
||||
__$$DataImplCopyWithImpl<_$DataImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() loading,
|
||||
required TResult Function() empty,
|
||||
required TResult Function() data,
|
||||
required TResult Function(List<TrainingDto> data) data,
|
||||
required TResult Function() result,
|
||||
}) {
|
||||
return data();
|
||||
return data(this.data);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -377,10 +410,10 @@ class _$DataImpl implements _Data {
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? loading,
|
||||
TResult? Function()? empty,
|
||||
TResult? Function()? data,
|
||||
TResult? Function(List<TrainingDto> data)? data,
|
||||
TResult? Function()? result,
|
||||
}) {
|
||||
return data?.call();
|
||||
return data?.call(this.data);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -388,12 +421,12 @@ class _$DataImpl implements _Data {
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? loading,
|
||||
TResult Function()? empty,
|
||||
TResult Function()? data,
|
||||
TResult Function(List<TrainingDto> data)? data,
|
||||
TResult Function()? result,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (data != null) {
|
||||
return data();
|
||||
return data(this.data);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
@@ -437,7 +470,15 @@ class _$DataImpl implements _Data {
|
||||
}
|
||||
|
||||
abstract class _Data implements TrainingState {
|
||||
const factory _Data() = _$DataImpl;
|
||||
const factory _Data(final List<TrainingDto> data) = _$DataImpl;
|
||||
|
||||
List<TrainingDto> get data;
|
||||
|
||||
/// Create a copy of TrainingState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$DataImplCopyWith<_$DataImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -485,7 +526,7 @@ class _$ResultImpl implements _Result {
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() loading,
|
||||
required TResult Function() empty,
|
||||
required TResult Function() data,
|
||||
required TResult Function(List<TrainingDto> data) data,
|
||||
required TResult Function() result,
|
||||
}) {
|
||||
return result();
|
||||
@@ -496,7 +537,7 @@ class _$ResultImpl implements _Result {
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? loading,
|
||||
TResult? Function()? empty,
|
||||
TResult? Function()? data,
|
||||
TResult? Function(List<TrainingDto> data)? data,
|
||||
TResult? Function()? result,
|
||||
}) {
|
||||
return result?.call();
|
||||
@@ -507,7 +548,7 @@ class _$ResultImpl implements _Result {
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? loading,
|
||||
TResult Function()? empty,
|
||||
TResult Function()? data,
|
||||
TResult Function(List<TrainingDto> data)? data,
|
||||
TResult Function()? result,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
|
||||
@@ -4,6 +4,6 @@ part of 'training_cubit.dart';
|
||||
class TrainingState with _$TrainingState {
|
||||
const factory TrainingState.loading() = _Loading;
|
||||
const factory TrainingState.empty() = _Empty;
|
||||
const factory TrainingState.data() = _Data;
|
||||
const factory TrainingState.data(List<TrainingDto> data) = _Data;
|
||||
const factory TrainingState.result() = _Result;
|
||||
}
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:remever/common/resources.dart';
|
||||
import 'package:remever/common/typography.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/gen/assets.gen.dart';
|
||||
import 'package:remever/router.gr.dart';
|
||||
import 'package:remever/models/training_dto.dart';
|
||||
import 'package:remever/screens/training/cubit/training_cubit.dart';
|
||||
import 'package:remever/screens/training/states/empty.dart';
|
||||
import 'package:remever/screens/training/states/loading.dart';
|
||||
@@ -40,7 +37,7 @@ class TrainingScreen extends StatelessWidget {
|
||||
return state.when(
|
||||
loading: () => TrainingLoading(),
|
||||
empty: () => TrainingEmpty(),
|
||||
data: () => TrainingData(),
|
||||
data: (data) => TrainingData(data: data),
|
||||
result: () => Placeholder(),
|
||||
);
|
||||
},
|
||||
@@ -50,8 +47,9 @@ class TrainingScreen extends StatelessWidget {
|
||||
}
|
||||
|
||||
class TrainingData extends StatefulWidget {
|
||||
const TrainingData({super.key});
|
||||
const TrainingData({super.key, required this.data});
|
||||
|
||||
final List<TrainingDto> data;
|
||||
@override
|
||||
State<TrainingData> createState() => _TrainingDataState();
|
||||
}
|
||||
@@ -59,6 +57,8 @@ class TrainingData extends StatefulWidget {
|
||||
class _TrainingDataState extends State<TrainingData> {
|
||||
bool _showAnswer = false;
|
||||
|
||||
int _currentTicketIndex = 0;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
@@ -97,7 +97,12 @@ class _TrainingDataState extends State<TrainingData> {
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(3).r,
|
||||
child: Center(child: AppTypography('1 из 9', type: Regular14px())),
|
||||
child: Center(
|
||||
child: AppTypography(
|
||||
'${_currentTicketIndex + 1} из ${widget.data.length}',
|
||||
type: Regular14px(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -117,7 +122,13 @@ class _TrainingDataState extends State<TrainingData> {
|
||||
children: [
|
||||
Flexible(
|
||||
child: PrimaryButton(
|
||||
onTap: () {},
|
||||
onTap: () {
|
||||
if (widget.data.length == _currentTicketIndex + 1) {
|
||||
context.read<TrainingCubit>().toResultState();
|
||||
return;
|
||||
}
|
||||
safeSetState(() => _currentTicketIndex++);
|
||||
},
|
||||
color: AppColors.danger,
|
||||
child: AppTypography(
|
||||
'Не помню',
|
||||
@@ -133,7 +144,13 @@ class _TrainingDataState extends State<TrainingData> {
|
||||
type: Medium14px(),
|
||||
color: Colors.white,
|
||||
),
|
||||
onTap: () {},
|
||||
onTap: () {
|
||||
if (widget.data.length == _currentTicketIndex + 1) {
|
||||
context.read<TrainingCubit>().toResultState();
|
||||
return;
|
||||
}
|
||||
safeSetState(() => _currentTicketIndex++);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -171,10 +188,14 @@ class _TrainingDataState extends State<TrainingData> {
|
||||
child: Column(
|
||||
spacing: 8.r,
|
||||
children: [
|
||||
TrainingTicket(),
|
||||
TrainingTicket(trainingDto: widget.data[_currentTicketIndex]),
|
||||
Wif(
|
||||
condition: _showAnswer,
|
||||
builder: (context) => TrainingTicket(isAnswer: true),
|
||||
builder:
|
||||
(context) => TrainingTicket(
|
||||
trainingDto: widget.data[_currentTicketIndex],
|
||||
isAnswer: true,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -1,13 +1,22 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:remever/common/resources.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/database/database.dart';
|
||||
import 'package:remever/models/training_dto.dart';
|
||||
|
||||
class TrainingTicket extends StatelessWidget {
|
||||
const TrainingTicket({super.key, this.isAnswer = false});
|
||||
const TrainingTicket({
|
||||
super.key,
|
||||
this.isAnswer = false,
|
||||
required this.trainingDto,
|
||||
});
|
||||
|
||||
final TrainingDto trainingDto;
|
||||
final bool isAnswer;
|
||||
|
||||
@override
|
||||
@@ -43,8 +52,10 @@ class TrainingTicket extends StatelessWidget {
|
||||
}
|
||||
|
||||
Widget _buildCollectionInfo() {
|
||||
final collection = trainingDto.collection;
|
||||
|
||||
return Wif(
|
||||
condition: !isAnswer,
|
||||
condition: !isAnswer && collection != null,
|
||||
builder: (context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8).r,
|
||||
@@ -53,16 +64,28 @@ class TrainingTicket extends StatelessWidget {
|
||||
SizedBox(
|
||||
height: 24.h,
|
||||
width: 24.w,
|
||||
child: ClipOval(
|
||||
child: Image.network(
|
||||
'https://avatars.mds.yandex.net/i?id=56429b65e9098a58fcd538387d43bcbb_l-5384017-images-thumbs&n=13',
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
child: Wif(
|
||||
condition: collection!.image != null,
|
||||
builder:
|
||||
(context) => ClipOval(
|
||||
child: Image.file(
|
||||
File(collection.image!),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
fallback:
|
||||
(context) => Center(
|
||||
child: AppTypography(
|
||||
collection.title.substring(0, 1),
|
||||
type: Bold34px(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
WSpace(4),
|
||||
AppTypography(
|
||||
'Астрология и астрофизика',
|
||||
collection.title,
|
||||
type: Regular14px(),
|
||||
color: AppColors.disabled,
|
||||
),
|
||||
@@ -70,6 +93,7 @@ class TrainingTicket extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
},
|
||||
fallback: (context) => Row(children: []),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -90,20 +114,21 @@ class TrainingTicket extends StatelessWidget {
|
||||
}
|
||||
|
||||
Widget _buildText(BuildContext context) {
|
||||
final ticket = trainingDto.ticket;
|
||||
return AppTypography(
|
||||
'Родился 19 февраля 1473 года в Торуне в семье купца. После смерти отца воспитывался у дяди, епископа Вармийской епархии. Коперник изложил свои идеи в сочинении «Commentariolus» («Малый комментарий»), в котором сформулировал основные положения гелиоцентрической системы мира в виде 6 аксиом. Их смысл состоит в том, что Земля, как и другие планеты,'
|
||||
'Родился 19 февраля 1473 года в Торуне в семье купца. После смерти отца воспитывался у дяди, епископа Вармийской епархии. Коперник изложил свои идеи в сочинении «Commentariolus» («Малый комментарий»), в котором сформулировал основные положения гелиоцентрической системы мира в виде 6 аксиом. Их смысл состоит в том, что Земля, как и другие планеты,',
|
||||
isAnswer ? ticket.answer : ticket.question,
|
||||
maxLines: 99,
|
||||
type: Regular14px(),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildImage() {
|
||||
// final imageBytes =
|
||||
// isAnswer ? ticket.answerImage : ticket.questionImage;
|
||||
final ticket = trainingDto.ticket;
|
||||
final String? imagePath =
|
||||
isAnswer ? ticket.answerImage : ticket.questionImage;
|
||||
|
||||
return Wif(
|
||||
condition: true, // imageBytes != null,
|
||||
condition: imagePath != null,
|
||||
builder:
|
||||
(context) => Padding(
|
||||
padding: const EdgeInsets.only(right: 8).r,
|
||||
@@ -111,11 +136,7 @@ class TrainingTicket extends StatelessWidget {
|
||||
dimension: 100.r,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8).r,
|
||||
// child: Image.memory(imageBytes!, fit: BoxFit.cover),
|
||||
child: Image.network(
|
||||
'https://avatars.mds.yandex.net/i?id=56429b65e9098a58fcd538387d43bcbb_l-5384017-images-thumbs&n=13',
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
child: Image.file(File(imagePath!), fit: BoxFit.cover),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
10
lib/services/training/training_interface.dart
Normal file
10
lib/services/training/training_interface.dart
Normal file
@@ -0,0 +1,10 @@
|
||||
import 'package:remever/database/database.dart';
|
||||
import 'package:remever/models/crud_collection_dto.dart';
|
||||
|
||||
///
|
||||
/// Интерфейс взаимодействия с тренировкой
|
||||
///
|
||||
abstract interface class TrainingInterface {
|
||||
/// Получение списка тикетов для тренировки
|
||||
Future<List<Ticket>> getTraining();
|
||||
}
|
||||
49
lib/services/training/training_service.dart
Normal file
49
lib/services/training/training_service.dart
Normal file
@@ -0,0 +1,49 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:injectable/injectable.dart';
|
||||
import 'package:remever/database/database.dart';
|
||||
import 'package:remever/inject.dart';
|
||||
import 'package:remever/services/training/training_interface.dart';
|
||||
|
||||
@Singleton(as: TrainingInterface)
|
||||
final class TrainingService implements TrainingInterface {
|
||||
// @override
|
||||
// Future<void> removeTicket(String ticketId) async {
|
||||
// return await getIt<AppDatabase>().ticketsDao.removeTicket(ticketId);
|
||||
// }
|
||||
|
||||
@override
|
||||
Future<List<Ticket>> getTraining() async {
|
||||
try {
|
||||
final db = getIt<AppDatabase>();
|
||||
|
||||
final rows =
|
||||
await db
|
||||
.customSelect('SELECT * FROM tickets ORDER BY RANDOM() LIMIT 10')
|
||||
.get();
|
||||
|
||||
return rows.map((row) {
|
||||
final data = row.data;
|
||||
print("ALARMA $data");
|
||||
|
||||
// Преобразуем snake_case ключи в camelCase для Moor сериализатора
|
||||
final camelCaseData = {
|
||||
'id': data['id'],
|
||||
'createdAt': data['created_at'],
|
||||
'updatedAt': data['updated_at'],
|
||||
'question': data['question'],
|
||||
'questionImage': data['question_image'],
|
||||
'answer': data['answer'],
|
||||
'answerImage': data['answer_image'],
|
||||
'collectionId': data['collection_id'],
|
||||
'progress': data['progress'],
|
||||
};
|
||||
|
||||
return Ticket.fromJson(camelCaseData);
|
||||
}).toList();
|
||||
} catch (e) {
|
||||
print('Error in training $e');
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user