feature(training): Добавлен состояния загрузки, пустоты и наличие данных на экране тренировки
This commit is contained in:
@@ -37,7 +37,7 @@ class HomeScreen extends StatelessWidget {
|
||||
},
|
||||
),
|
||||
),
|
||||
_buildCentralButton(),
|
||||
_buildCentralButton(context),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -80,12 +80,12 @@ class HomeScreen extends StatelessWidget {
|
||||
}
|
||||
|
||||
/// Построение центральной кнопки
|
||||
Widget _buildCentralButton() {
|
||||
Widget _buildCentralButton(BuildContext context) {
|
||||
return Align(
|
||||
alignment: Alignment(0, 0.91),
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
// Логика нажатия на центральную кнопку
|
||||
context.pushRoute(TrainingRoute());
|
||||
},
|
||||
child: SizedBox.square(
|
||||
dimension: 60.r,
|
||||
|
||||
25
lib/screens/training/cubit/training_cubit.dart
Normal file
25
lib/screens/training/cubit/training_cubit.dart
Normal file
@@ -0,0 +1,25 @@
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'training_state.dart';
|
||||
part 'training_cubit.freezed.dart';
|
||||
|
||||
class TrainingCubit extends Cubit<TrainingState> {
|
||||
TrainingCubit() : super(TrainingState.data());
|
||||
|
||||
Future<void> toLoading() async {
|
||||
emit(TrainingState.loading());
|
||||
}
|
||||
|
||||
Future<void> toEmptyState() async {
|
||||
emit(TrainingState.empty());
|
||||
}
|
||||
|
||||
Future<void> toDataState() async {
|
||||
emit(TrainingState.data());
|
||||
}
|
||||
|
||||
Future<void> toResultState() async {
|
||||
emit(TrainingState.result());
|
||||
}
|
||||
}
|
||||
560
lib/screens/training/cubit/training_cubit.freezed.dart
Normal file
560
lib/screens/training/cubit/training_cubit.freezed.dart
Normal file
@@ -0,0 +1,560 @@
|
||||
// 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_cubit.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 _$TrainingState {
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() loading,
|
||||
required TResult Function() empty,
|
||||
required TResult Function() data,
|
||||
required TResult Function() result,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? loading,
|
||||
TResult? Function()? empty,
|
||||
TResult? Function()? data,
|
||||
TResult? Function()? result,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? loading,
|
||||
TResult Function()? empty,
|
||||
TResult Function()? data,
|
||||
TResult Function()? result,
|
||||
required TResult orElse(),
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_Loading value) loading,
|
||||
required TResult Function(_Empty value) empty,
|
||||
required TResult Function(_Data value) data,
|
||||
required TResult Function(_Result value) result,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_Loading value)? loading,
|
||||
TResult? Function(_Empty value)? empty,
|
||||
TResult? Function(_Data value)? data,
|
||||
TResult? Function(_Result value)? result,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_Loading value)? loading,
|
||||
TResult Function(_Empty value)? empty,
|
||||
TResult Function(_Data value)? data,
|
||||
TResult Function(_Result value)? result,
|
||||
required TResult orElse(),
|
||||
}) => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $TrainingStateCopyWith<$Res> {
|
||||
factory $TrainingStateCopyWith(
|
||||
TrainingState value,
|
||||
$Res Function(TrainingState) then,
|
||||
) = _$TrainingStateCopyWithImpl<$Res, TrainingState>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$TrainingStateCopyWithImpl<$Res, $Val extends TrainingState>
|
||||
implements $TrainingStateCopyWith<$Res> {
|
||||
_$TrainingStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of TrainingState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$LoadingImplCopyWith<$Res> {
|
||||
factory _$$LoadingImplCopyWith(
|
||||
_$LoadingImpl value,
|
||||
$Res Function(_$LoadingImpl) then,
|
||||
) = __$$LoadingImplCopyWithImpl<$Res>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$LoadingImplCopyWithImpl<$Res>
|
||||
extends _$TrainingStateCopyWithImpl<$Res, _$LoadingImpl>
|
||||
implements _$$LoadingImplCopyWith<$Res> {
|
||||
__$$LoadingImplCopyWithImpl(
|
||||
_$LoadingImpl _value,
|
||||
$Res Function(_$LoadingImpl) _then,
|
||||
) : super(_value, _then);
|
||||
|
||||
/// Create a copy of TrainingState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$LoadingImpl implements _Loading {
|
||||
const _$LoadingImpl();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'TrainingState.loading()';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _$LoadingImpl);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => runtimeType.hashCode;
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() loading,
|
||||
required TResult Function() empty,
|
||||
required TResult Function() data,
|
||||
required TResult Function() result,
|
||||
}) {
|
||||
return loading();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? loading,
|
||||
TResult? Function()? empty,
|
||||
TResult? Function()? data,
|
||||
TResult? Function()? result,
|
||||
}) {
|
||||
return loading?.call();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? loading,
|
||||
TResult Function()? empty,
|
||||
TResult Function()? data,
|
||||
TResult Function()? result,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (loading != null) {
|
||||
return loading();
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_Loading value) loading,
|
||||
required TResult Function(_Empty value) empty,
|
||||
required TResult Function(_Data value) data,
|
||||
required TResult Function(_Result value) result,
|
||||
}) {
|
||||
return loading(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_Loading value)? loading,
|
||||
TResult? Function(_Empty value)? empty,
|
||||
TResult? Function(_Data value)? data,
|
||||
TResult? Function(_Result value)? result,
|
||||
}) {
|
||||
return loading?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_Loading value)? loading,
|
||||
TResult Function(_Empty value)? empty,
|
||||
TResult Function(_Data value)? data,
|
||||
TResult Function(_Result value)? result,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (loading != null) {
|
||||
return loading(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _Loading implements TrainingState {
|
||||
const factory _Loading() = _$LoadingImpl;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$EmptyImplCopyWith<$Res> {
|
||||
factory _$$EmptyImplCopyWith(
|
||||
_$EmptyImpl value,
|
||||
$Res Function(_$EmptyImpl) then,
|
||||
) = __$$EmptyImplCopyWithImpl<$Res>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$EmptyImplCopyWithImpl<$Res>
|
||||
extends _$TrainingStateCopyWithImpl<$Res, _$EmptyImpl>
|
||||
implements _$$EmptyImplCopyWith<$Res> {
|
||||
__$$EmptyImplCopyWithImpl(
|
||||
_$EmptyImpl _value,
|
||||
$Res Function(_$EmptyImpl) _then,
|
||||
) : super(_value, _then);
|
||||
|
||||
/// Create a copy of TrainingState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$EmptyImpl implements _Empty {
|
||||
const _$EmptyImpl();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'TrainingState.empty()';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _$EmptyImpl);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => runtimeType.hashCode;
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() loading,
|
||||
required TResult Function() empty,
|
||||
required TResult Function() data,
|
||||
required TResult Function() result,
|
||||
}) {
|
||||
return empty();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? loading,
|
||||
TResult? Function()? empty,
|
||||
TResult? Function()? data,
|
||||
TResult? Function()? result,
|
||||
}) {
|
||||
return empty?.call();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? loading,
|
||||
TResult Function()? empty,
|
||||
TResult Function()? data,
|
||||
TResult Function()? result,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (empty != null) {
|
||||
return empty();
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_Loading value) loading,
|
||||
required TResult Function(_Empty value) empty,
|
||||
required TResult Function(_Data value) data,
|
||||
required TResult Function(_Result value) result,
|
||||
}) {
|
||||
return empty(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_Loading value)? loading,
|
||||
TResult? Function(_Empty value)? empty,
|
||||
TResult? Function(_Data value)? data,
|
||||
TResult? Function(_Result value)? result,
|
||||
}) {
|
||||
return empty?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_Loading value)? loading,
|
||||
TResult Function(_Empty value)? empty,
|
||||
TResult Function(_Data value)? data,
|
||||
TResult Function(_Result value)? result,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (empty != null) {
|
||||
return empty(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _Empty implements TrainingState {
|
||||
const factory _Empty() = _$EmptyImpl;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$DataImplCopyWith<$Res> {
|
||||
factory _$$DataImplCopyWith(
|
||||
_$DataImpl value,
|
||||
$Res Function(_$DataImpl) then,
|
||||
) = __$$DataImplCopyWithImpl<$Res>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$DataImplCopyWithImpl<$Res>
|
||||
extends _$TrainingStateCopyWithImpl<$Res, _$DataImpl>
|
||||
implements _$$DataImplCopyWith<$Res> {
|
||||
__$$DataImplCopyWithImpl(_$DataImpl _value, $Res Function(_$DataImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of TrainingState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$DataImpl implements _Data {
|
||||
const _$DataImpl();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'TrainingState.data()';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _$DataImpl);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => runtimeType.hashCode;
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() loading,
|
||||
required TResult Function() empty,
|
||||
required TResult Function() data,
|
||||
required TResult Function() result,
|
||||
}) {
|
||||
return data();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? loading,
|
||||
TResult? Function()? empty,
|
||||
TResult? Function()? data,
|
||||
TResult? Function()? result,
|
||||
}) {
|
||||
return data?.call();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? loading,
|
||||
TResult Function()? empty,
|
||||
TResult Function()? data,
|
||||
TResult Function()? result,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (data != null) {
|
||||
return data();
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_Loading value) loading,
|
||||
required TResult Function(_Empty value) empty,
|
||||
required TResult Function(_Data value) data,
|
||||
required TResult Function(_Result value) result,
|
||||
}) {
|
||||
return data(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_Loading value)? loading,
|
||||
TResult? Function(_Empty value)? empty,
|
||||
TResult? Function(_Data value)? data,
|
||||
TResult? Function(_Result value)? result,
|
||||
}) {
|
||||
return data?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_Loading value)? loading,
|
||||
TResult Function(_Empty value)? empty,
|
||||
TResult Function(_Data value)? data,
|
||||
TResult Function(_Result value)? result,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (data != null) {
|
||||
return data(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _Data implements TrainingState {
|
||||
const factory _Data() = _$DataImpl;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$ResultImplCopyWith<$Res> {
|
||||
factory _$$ResultImplCopyWith(
|
||||
_$ResultImpl value,
|
||||
$Res Function(_$ResultImpl) then,
|
||||
) = __$$ResultImplCopyWithImpl<$Res>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$ResultImplCopyWithImpl<$Res>
|
||||
extends _$TrainingStateCopyWithImpl<$Res, _$ResultImpl>
|
||||
implements _$$ResultImplCopyWith<$Res> {
|
||||
__$$ResultImplCopyWithImpl(
|
||||
_$ResultImpl _value,
|
||||
$Res Function(_$ResultImpl) _then,
|
||||
) : super(_value, _then);
|
||||
|
||||
/// Create a copy of TrainingState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$ResultImpl implements _Result {
|
||||
const _$ResultImpl();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'TrainingState.result()';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _$ResultImpl);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => runtimeType.hashCode;
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() loading,
|
||||
required TResult Function() empty,
|
||||
required TResult Function() data,
|
||||
required TResult Function() result,
|
||||
}) {
|
||||
return result();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? loading,
|
||||
TResult? Function()? empty,
|
||||
TResult? Function()? data,
|
||||
TResult? Function()? result,
|
||||
}) {
|
||||
return result?.call();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? loading,
|
||||
TResult Function()? empty,
|
||||
TResult Function()? data,
|
||||
TResult Function()? result,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (result != null) {
|
||||
return result();
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_Loading value) loading,
|
||||
required TResult Function(_Empty value) empty,
|
||||
required TResult Function(_Data value) data,
|
||||
required TResult Function(_Result value) result,
|
||||
}) {
|
||||
return result(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_Loading value)? loading,
|
||||
TResult? Function(_Empty value)? empty,
|
||||
TResult? Function(_Data value)? data,
|
||||
TResult? Function(_Result value)? result,
|
||||
}) {
|
||||
return result?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_Loading value)? loading,
|
||||
TResult Function(_Empty value)? empty,
|
||||
TResult Function(_Data value)? data,
|
||||
TResult Function(_Result value)? result,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (result != null) {
|
||||
return result(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _Result implements TrainingState {
|
||||
const factory _Result() = _$ResultImpl;
|
||||
}
|
||||
9
lib/screens/training/cubit/training_state.dart
Normal file
9
lib/screens/training/cubit/training_state.dart
Normal file
@@ -0,0 +1,9 @@
|
||||
part of 'training_cubit.dart';
|
||||
|
||||
@freezed
|
||||
class TrainingState with _$TrainingState {
|
||||
const factory TrainingState.loading() = _Loading;
|
||||
const factory TrainingState.empty() = _Empty;
|
||||
const factory TrainingState.data() = _Data;
|
||||
const factory TrainingState.result() = _Result;
|
||||
}
|
||||
71
lib/screens/training/states/empty.dart
Normal file
71
lib/screens/training/states/empty.dart
Normal file
@@ -0,0 +1,71 @@
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:remever/common/resources.dart';
|
||||
import 'package:remever/common/widgets/typography.dart';
|
||||
import 'package:remever/common/widgets/wspace.dart';
|
||||
import 'package:remever/components/extensions/context.dart';
|
||||
import 'package:remever/gen/assets.gen.dart';
|
||||
import 'package:remever/router.gr.dart';
|
||||
import 'package:remever/widgets/primary_button.dart';
|
||||
|
||||
class TrainingEmpty extends StatelessWidget {
|
||||
const TrainingEmpty({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: AppColors.bg,
|
||||
appBar: _buildAppBar(context),
|
||||
body: _buildMain(context),
|
||||
);
|
||||
}
|
||||
|
||||
/// Построение шапки
|
||||
AppBar _buildAppBar(BuildContext context) {
|
||||
return AppBar(
|
||||
backgroundColor: AppColors.white,
|
||||
shadowColor: Colors.transparent,
|
||||
leading: GestureDetector(
|
||||
onTap: () => context.back(),
|
||||
child: const Icon(Icons.close, color: Colors.black),
|
||||
),
|
||||
centerTitle: true,
|
||||
title: AppTypography(
|
||||
'Тренировка',
|
||||
type: SemiBold20px(),
|
||||
color: AppColors.body_text,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildMain(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16).r,
|
||||
child: Column(
|
||||
children: [
|
||||
HSpace(90),
|
||||
Assets.images.trainingEmpty.image(height: 127.h, width: 160.w),
|
||||
HSpace(20),
|
||||
AppTypography(
|
||||
'К сожалению, у вас нет карточек для изучения',
|
||||
type: SemiBold20px(),
|
||||
maxLines: 3,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
Spacer(),
|
||||
PrimaryButton(
|
||||
onTap: () {
|
||||
context.router.replaceAll([CreateRoute()]);
|
||||
},
|
||||
child: AppTypography(
|
||||
'Создать карточку',
|
||||
type: Medium14px(),
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
HSpace(90),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
35
lib/screens/training/states/loading.dart
Normal file
35
lib/screens/training/states/loading.dart
Normal file
@@ -0,0 +1,35 @@
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:remever/common/resources.dart';
|
||||
import 'package:remever/common/widgets/typography.dart';
|
||||
|
||||
class TrainingLoading extends StatelessWidget {
|
||||
const TrainingLoading({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: AppColors.bg,
|
||||
appBar: _buildAppBar(context),
|
||||
body: Center(child: CircularProgressIndicator(color: AppColors.primary)),
|
||||
);
|
||||
}
|
||||
|
||||
/// Построение шапки
|
||||
AppBar _buildAppBar(BuildContext context) {
|
||||
return AppBar(
|
||||
backgroundColor: AppColors.white,
|
||||
shadowColor: Colors.transparent,
|
||||
leading: GestureDetector(
|
||||
onTap: () => context.back(),
|
||||
child: const Icon(Icons.close, color: Colors.black),
|
||||
),
|
||||
centerTitle: true,
|
||||
title: AppTypography(
|
||||
'Тренировка',
|
||||
type: SemiBold20px(),
|
||||
color: AppColors.body_text,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
185
lib/screens/training/training_screen.dart
Normal file
185
lib/screens/training/training_screen.dart
Normal file
@@ -0,0 +1,185 @@
|
||||
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/screens/training/cubit/training_cubit.dart';
|
||||
import 'package:remever/screens/training/states/empty.dart';
|
||||
import 'package:remever/screens/training/states/loading.dart';
|
||||
import 'package:remever/screens/training/widgets/training_ticket.dart';
|
||||
import 'package:remever/widgets/primary_button.dart';
|
||||
|
||||
@RoutePage()
|
||||
class TrainingScreen extends StatelessWidget {
|
||||
const TrainingScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider<TrainingCubit>(
|
||||
create: (BuildContext context) => TrainingCubit(),
|
||||
child: _buildMain(),
|
||||
);
|
||||
}
|
||||
|
||||
///
|
||||
/// Построение основного блока
|
||||
///
|
||||
Widget _buildMain() {
|
||||
return PopScope(
|
||||
canPop: false,
|
||||
child: BlocBuilder<TrainingCubit, TrainingState>(
|
||||
builder: (BuildContext context, state) {
|
||||
return state.when(
|
||||
loading: () => TrainingLoading(),
|
||||
empty: () => TrainingEmpty(),
|
||||
data: () => TrainingData(),
|
||||
result: () => Placeholder(),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class TrainingData extends StatefulWidget {
|
||||
const TrainingData({super.key});
|
||||
|
||||
@override
|
||||
State<TrainingData> createState() => _TrainingDataState();
|
||||
}
|
||||
|
||||
class _TrainingDataState extends State<TrainingData> {
|
||||
bool _showAnswer = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: AppColors.bg,
|
||||
appBar: _buildAppBar(context),
|
||||
body: _buildMain(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Построение шапки
|
||||
AppBar _buildAppBar(BuildContext context) {
|
||||
return AppBar(
|
||||
backgroundColor: AppColors.white,
|
||||
shadowColor: Colors.transparent,
|
||||
leading: GestureDetector(
|
||||
onTap: () => context.back(),
|
||||
child: const Icon(Icons.close, color: Colors.black),
|
||||
),
|
||||
centerTitle: true,
|
||||
title: AppTypography(
|
||||
'Тренировка',
|
||||
type: SemiBold20px(),
|
||||
color: AppColors.body_text,
|
||||
),
|
||||
actions: [_buildCounter(), WSpace(16)],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCounter() {
|
||||
return Center(
|
||||
child: Container(
|
||||
height: 24.h,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(100)).r,
|
||||
color: AppColors.bg,
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(3).r,
|
||||
child: Center(child: AppTypography('1 из 9', type: Regular14px())),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildMain() {
|
||||
return Column(
|
||||
children: [_buildTickets(), _buildShowAnswerButton(), _buildActions()],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildActions() {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16).r,
|
||||
child: Row(
|
||||
spacing: 8.r,
|
||||
children: [
|
||||
Flexible(
|
||||
child: PrimaryButton(
|
||||
onTap: () {},
|
||||
color: AppColors.danger,
|
||||
child: AppTypography(
|
||||
'Не помню',
|
||||
type: Medium14px(),
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: PrimaryButton(
|
||||
child: AppTypography(
|
||||
'Помню',
|
||||
type: Medium14px(),
|
||||
color: Colors.white,
|
||||
),
|
||||
onTap: () {},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildShowAnswerButton() {
|
||||
return Wif(
|
||||
condition: !_showAnswer,
|
||||
builder:
|
||||
(context) => PrimaryButton(
|
||||
onTap: () {
|
||||
safeSetState(() {
|
||||
_showAnswer = true;
|
||||
});
|
||||
},
|
||||
color: AppColors.secondary,
|
||||
width: 170,
|
||||
child: AppTypography(
|
||||
'Показать ответ',
|
||||
type: Medium14px(),
|
||||
color: AppColors.primary,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTickets() {
|
||||
return Expanded(
|
||||
child: SingleChildScrollView(
|
||||
physics: BouncingScrollPhysics(),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16).r,
|
||||
child: Column(
|
||||
spacing: 8.r,
|
||||
children: [
|
||||
TrainingTicket(),
|
||||
Wif(
|
||||
condition: _showAnswer,
|
||||
builder: (context) => TrainingTicket(isAnswer: true),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
124
lib/screens/training/widgets/training_ticket.dart
Normal file
124
lib/screens/training/widgets/training_ticket.dart
Normal file
@@ -0,0 +1,124 @@
|
||||
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';
|
||||
|
||||
class TrainingTicket extends StatelessWidget {
|
||||
const TrainingTicket({super.key, this.isAnswer = false});
|
||||
|
||||
final bool isAnswer;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12).r,
|
||||
color: Colors.white,
|
||||
),
|
||||
constraints: BoxConstraints(minHeight: 50.h),
|
||||
child: Stack(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 90.h,
|
||||
width: double.infinity,
|
||||
child: DecoratedBox(decoration: getDecoration()),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(12).r,
|
||||
child: Column(
|
||||
children: [
|
||||
_buildCollectionInfo(),
|
||||
_buildImage(),
|
||||
HSpace(4),
|
||||
_buildText(context),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCollectionInfo() {
|
||||
return Wif(
|
||||
condition: !isAnswer,
|
||||
builder: (context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8).r,
|
||||
child: Row(
|
||||
children: [
|
||||
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,
|
||||
),
|
||||
),
|
||||
),
|
||||
WSpace(4),
|
||||
AppTypography(
|
||||
'Астрология и астрофизика',
|
||||
type: Regular14px(),
|
||||
color: AppColors.disabled,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Декорирование контейнера
|
||||
BoxDecoration getDecoration() {
|
||||
return BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12).r,
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
isAnswer ? AppColors.answer : AppColors.question,
|
||||
Colors.white,
|
||||
],
|
||||
begin: Alignment.topLeft,
|
||||
end: const Alignment(-0.5, 1),
|
||||
stops: const [0.25, 0.25],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildText(BuildContext context) {
|
||||
return AppTypography(
|
||||
'Родился 19 февраля 1473 года в Торуне в семье купца. После смерти отца воспитывался у дяди, епископа Вармийской епархии. Коперник изложил свои идеи в сочинении «Commentariolus» («Малый комментарий»), в котором сформулировал основные положения гелиоцентрической системы мира в виде 6 аксиом. Их смысл состоит в том, что Земля, как и другие планеты,'
|
||||
'Родился 19 февраля 1473 года в Торуне в семье купца. После смерти отца воспитывался у дяди, епископа Вармийской епархии. Коперник изложил свои идеи в сочинении «Commentariolus» («Малый комментарий»), в котором сформулировал основные положения гелиоцентрической системы мира в виде 6 аксиом. Их смысл состоит в том, что Земля, как и другие планеты,',
|
||||
maxLines: 99,
|
||||
type: Regular14px(),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildImage() {
|
||||
// final imageBytes =
|
||||
// isAnswer ? ticket.answerImage : ticket.questionImage;
|
||||
|
||||
return Wif(
|
||||
condition: true, // imageBytes != null,
|
||||
builder:
|
||||
(context) => Padding(
|
||||
padding: const EdgeInsets.only(right: 8).r,
|
||||
child: SizedBox.square(
|
||||
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,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user