feature(training): Добавлен состояния загрузки, пустоты и наличие данных на экране тренировки

This commit is contained in:
2025-06-17 22:27:22 +03:00
parent 0842c479c7
commit 285c4ca3f2
17 changed files with 1098 additions and 65 deletions

View File

@@ -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,

View 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());
}
}

View 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;
}

View 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;
}

View 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),
],
),
);
}
}

View 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,
),
);
}
}

View 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),
),
],
),
),
),
);
}
}

View 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,
),
),
),
),
);
}
}