Feature: Верстка экранов настроек #5

Merged
Dimkov966 merged 1 commits from feature/settings into develop 2025-06-16 19:22:27 +00:00
23 changed files with 1386 additions and 4 deletions

View File

@@ -1130,7 +1130,7 @@
"languageVersion": "3.7"
}
],
"generated": "2025-06-16T17:17:10.994308Z",
"generated": "2025-06-16T19:03:33.328096Z",
"generator": "pub",
"generatorVersion": "3.7.0",
"flutterRoot": "file:///Users/vitalijnecitajlo/fvm/versions/3.29.0",

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 746 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 811 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 759 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 954 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 639 B

View File

@@ -21,6 +21,46 @@ class $AssetsIconsGen {
/// File path: assets/icons/mail.png
AssetGenImage get mail => const AssetGenImage('assets/icons/mail.png');
/// File path: assets/icons/settings_about.png
AssetGenImage get settingsAbout =>
const AssetGenImage('assets/icons/settings_about.png');
/// File path: assets/icons/settings_exit.png
AssetGenImage get settingsExit =>
const AssetGenImage('assets/icons/settings_exit.png');
/// File path: assets/icons/settings_faq.png
AssetGenImage get settingsFaq =>
const AssetGenImage('assets/icons/settings_faq.png');
/// File path: assets/icons/settings_mail.png
AssetGenImage get settingsMail =>
const AssetGenImage('assets/icons/settings_mail.png');
/// File path: assets/icons/settings_name.png
AssetGenImage get settingsName =>
const AssetGenImage('assets/icons/settings_name.png');
/// File path: assets/icons/settings_notification.png
AssetGenImage get settingsNotification =>
const AssetGenImage('assets/icons/settings_notification.png');
/// File path: assets/icons/settings_phone.png
AssetGenImage get settingsPhone =>
const AssetGenImage('assets/icons/settings_phone.png');
/// File path: assets/icons/settings_profile.png
AssetGenImage get settingsProfile =>
const AssetGenImage('assets/icons/settings_profile.png');
/// File path: assets/icons/settings_share.png
AssetGenImage get settingsShare =>
const AssetGenImage('assets/icons/settings_share.png');
/// File path: assets/icons/settings_trash.png
AssetGenImage get settingsTrash =>
const AssetGenImage('assets/icons/settings_trash.png');
/// File path: assets/icons/type=arrow_down.png
AssetGenImage get typeArrowDown =>
const AssetGenImage('assets/icons/type=arrow_down.png');
@@ -221,6 +261,16 @@ class $AssetsIconsGen {
back,
call,
mail,
settingsAbout,
settingsExit,
settingsFaq,
settingsMail,
settingsName,
settingsNotification,
settingsPhone,
settingsProfile,
settingsShare,
settingsTrash,
typeArrowDown,
typeBack,
typeBold,

View File

@@ -6,7 +6,7 @@
/// Locales: 2
/// Strings: 20 (10 per locale)
///
/// Built on 2025-06-16 at 17:17 UTC
/// Built on 2025-06-16 at 19:03 UTC
// coverage:ignore-file
// ignore_for_file: type=lint, unused_import

View File

@@ -0,0 +1,29 @@
import 'package:bloc/bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'settings_state.dart';
part 'settings_cubit.freezed.dart';
class SettingsCubit extends Cubit<SettingsState> {
SettingsCubit() : super(SettingsState.initial());
Future<void> toInitialState() async {
emit(SettingsState.initial());
}
Future<void> toProfileState() async {
emit(SettingsState.profile());
}
Future<void> toNotificationsState() async {
emit(SettingsState.notifications());
}
Future<void> toFaqState() async {
emit(SettingsState.faq());
}
Future<void> toAboutState() async {
emit(SettingsState.about());
}
}

View File

@@ -0,0 +1,713 @@
// 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 'settings_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 _$SettingsState {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() profile,
required TResult Function() notifications,
required TResult Function() faq,
required TResult Function() about,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? initial,
TResult? Function()? profile,
TResult? Function()? notifications,
TResult? Function()? faq,
TResult? Function()? about,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? profile,
TResult Function()? notifications,
TResult Function()? faq,
TResult Function()? about,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_Profile value) profile,
required TResult Function(_Notifications value) notifications,
required TResult Function(_Faq value) faq,
required TResult Function(_About value) about,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Initial value)? initial,
TResult? Function(_Profile value)? profile,
TResult? Function(_Notifications value)? notifications,
TResult? Function(_Faq value)? faq,
TResult? Function(_About value)? about,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_Profile value)? profile,
TResult Function(_Notifications value)? notifications,
TResult Function(_Faq value)? faq,
TResult Function(_About value)? about,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $SettingsStateCopyWith<$Res> {
factory $SettingsStateCopyWith(
SettingsState value,
$Res Function(SettingsState) then,
) = _$SettingsStateCopyWithImpl<$Res, SettingsState>;
}
/// @nodoc
class _$SettingsStateCopyWithImpl<$Res, $Val extends SettingsState>
implements $SettingsStateCopyWith<$Res> {
_$SettingsStateCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of SettingsState
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
abstract class _$$InitialImplCopyWith<$Res> {
factory _$$InitialImplCopyWith(
_$InitialImpl value,
$Res Function(_$InitialImpl) then,
) = __$$InitialImplCopyWithImpl<$Res>;
}
/// @nodoc
class __$$InitialImplCopyWithImpl<$Res>
extends _$SettingsStateCopyWithImpl<$Res, _$InitialImpl>
implements _$$InitialImplCopyWith<$Res> {
__$$InitialImplCopyWithImpl(
_$InitialImpl _value,
$Res Function(_$InitialImpl) _then,
) : super(_value, _then);
/// Create a copy of SettingsState
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
class _$InitialImpl implements _Initial {
const _$InitialImpl();
@override
String toString() {
return 'SettingsState.initial()';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType && other is _$InitialImpl);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() profile,
required TResult Function() notifications,
required TResult Function() faq,
required TResult Function() about,
}) {
return initial();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? initial,
TResult? Function()? profile,
TResult? Function()? notifications,
TResult? Function()? faq,
TResult? Function()? about,
}) {
return initial?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? profile,
TResult Function()? notifications,
TResult Function()? faq,
TResult Function()? about,
required TResult orElse(),
}) {
if (initial != null) {
return initial();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_Profile value) profile,
required TResult Function(_Notifications value) notifications,
required TResult Function(_Faq value) faq,
required TResult Function(_About value) about,
}) {
return initial(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Initial value)? initial,
TResult? Function(_Profile value)? profile,
TResult? Function(_Notifications value)? notifications,
TResult? Function(_Faq value)? faq,
TResult? Function(_About value)? about,
}) {
return initial?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_Profile value)? profile,
TResult Function(_Notifications value)? notifications,
TResult Function(_Faq value)? faq,
TResult Function(_About value)? about,
required TResult orElse(),
}) {
if (initial != null) {
return initial(this);
}
return orElse();
}
}
abstract class _Initial implements SettingsState {
const factory _Initial() = _$InitialImpl;
}
/// @nodoc
abstract class _$$ProfileImplCopyWith<$Res> {
factory _$$ProfileImplCopyWith(
_$ProfileImpl value,
$Res Function(_$ProfileImpl) then,
) = __$$ProfileImplCopyWithImpl<$Res>;
}
/// @nodoc
class __$$ProfileImplCopyWithImpl<$Res>
extends _$SettingsStateCopyWithImpl<$Res, _$ProfileImpl>
implements _$$ProfileImplCopyWith<$Res> {
__$$ProfileImplCopyWithImpl(
_$ProfileImpl _value,
$Res Function(_$ProfileImpl) _then,
) : super(_value, _then);
/// Create a copy of SettingsState
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
class _$ProfileImpl implements _Profile {
const _$ProfileImpl();
@override
String toString() {
return 'SettingsState.profile()';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType && other is _$ProfileImpl);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() profile,
required TResult Function() notifications,
required TResult Function() faq,
required TResult Function() about,
}) {
return profile();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? initial,
TResult? Function()? profile,
TResult? Function()? notifications,
TResult? Function()? faq,
TResult? Function()? about,
}) {
return profile?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? profile,
TResult Function()? notifications,
TResult Function()? faq,
TResult Function()? about,
required TResult orElse(),
}) {
if (profile != null) {
return profile();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_Profile value) profile,
required TResult Function(_Notifications value) notifications,
required TResult Function(_Faq value) faq,
required TResult Function(_About value) about,
}) {
return profile(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Initial value)? initial,
TResult? Function(_Profile value)? profile,
TResult? Function(_Notifications value)? notifications,
TResult? Function(_Faq value)? faq,
TResult? Function(_About value)? about,
}) {
return profile?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_Profile value)? profile,
TResult Function(_Notifications value)? notifications,
TResult Function(_Faq value)? faq,
TResult Function(_About value)? about,
required TResult orElse(),
}) {
if (profile != null) {
return profile(this);
}
return orElse();
}
}
abstract class _Profile implements SettingsState {
const factory _Profile() = _$ProfileImpl;
}
/// @nodoc
abstract class _$$NotificationsImplCopyWith<$Res> {
factory _$$NotificationsImplCopyWith(
_$NotificationsImpl value,
$Res Function(_$NotificationsImpl) then,
) = __$$NotificationsImplCopyWithImpl<$Res>;
}
/// @nodoc
class __$$NotificationsImplCopyWithImpl<$Res>
extends _$SettingsStateCopyWithImpl<$Res, _$NotificationsImpl>
implements _$$NotificationsImplCopyWith<$Res> {
__$$NotificationsImplCopyWithImpl(
_$NotificationsImpl _value,
$Res Function(_$NotificationsImpl) _then,
) : super(_value, _then);
/// Create a copy of SettingsState
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
class _$NotificationsImpl implements _Notifications {
const _$NotificationsImpl();
@override
String toString() {
return 'SettingsState.notifications()';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType && other is _$NotificationsImpl);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() profile,
required TResult Function() notifications,
required TResult Function() faq,
required TResult Function() about,
}) {
return notifications();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? initial,
TResult? Function()? profile,
TResult? Function()? notifications,
TResult? Function()? faq,
TResult? Function()? about,
}) {
return notifications?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? profile,
TResult Function()? notifications,
TResult Function()? faq,
TResult Function()? about,
required TResult orElse(),
}) {
if (notifications != null) {
return notifications();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_Profile value) profile,
required TResult Function(_Notifications value) notifications,
required TResult Function(_Faq value) faq,
required TResult Function(_About value) about,
}) {
return notifications(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Initial value)? initial,
TResult? Function(_Profile value)? profile,
TResult? Function(_Notifications value)? notifications,
TResult? Function(_Faq value)? faq,
TResult? Function(_About value)? about,
}) {
return notifications?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_Profile value)? profile,
TResult Function(_Notifications value)? notifications,
TResult Function(_Faq value)? faq,
TResult Function(_About value)? about,
required TResult orElse(),
}) {
if (notifications != null) {
return notifications(this);
}
return orElse();
}
}
abstract class _Notifications implements SettingsState {
const factory _Notifications() = _$NotificationsImpl;
}
/// @nodoc
abstract class _$$FaqImplCopyWith<$Res> {
factory _$$FaqImplCopyWith(_$FaqImpl value, $Res Function(_$FaqImpl) then) =
__$$FaqImplCopyWithImpl<$Res>;
}
/// @nodoc
class __$$FaqImplCopyWithImpl<$Res>
extends _$SettingsStateCopyWithImpl<$Res, _$FaqImpl>
implements _$$FaqImplCopyWith<$Res> {
__$$FaqImplCopyWithImpl(_$FaqImpl _value, $Res Function(_$FaqImpl) _then)
: super(_value, _then);
/// Create a copy of SettingsState
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
class _$FaqImpl implements _Faq {
const _$FaqImpl();
@override
String toString() {
return 'SettingsState.faq()';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType && other is _$FaqImpl);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() profile,
required TResult Function() notifications,
required TResult Function() faq,
required TResult Function() about,
}) {
return faq();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? initial,
TResult? Function()? profile,
TResult? Function()? notifications,
TResult? Function()? faq,
TResult? Function()? about,
}) {
return faq?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? profile,
TResult Function()? notifications,
TResult Function()? faq,
TResult Function()? about,
required TResult orElse(),
}) {
if (faq != null) {
return faq();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_Profile value) profile,
required TResult Function(_Notifications value) notifications,
required TResult Function(_Faq value) faq,
required TResult Function(_About value) about,
}) {
return faq(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Initial value)? initial,
TResult? Function(_Profile value)? profile,
TResult? Function(_Notifications value)? notifications,
TResult? Function(_Faq value)? faq,
TResult? Function(_About value)? about,
}) {
return faq?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_Profile value)? profile,
TResult Function(_Notifications value)? notifications,
TResult Function(_Faq value)? faq,
TResult Function(_About value)? about,
required TResult orElse(),
}) {
if (faq != null) {
return faq(this);
}
return orElse();
}
}
abstract class _Faq implements SettingsState {
const factory _Faq() = _$FaqImpl;
}
/// @nodoc
abstract class _$$AboutImplCopyWith<$Res> {
factory _$$AboutImplCopyWith(
_$AboutImpl value,
$Res Function(_$AboutImpl) then,
) = __$$AboutImplCopyWithImpl<$Res>;
}
/// @nodoc
class __$$AboutImplCopyWithImpl<$Res>
extends _$SettingsStateCopyWithImpl<$Res, _$AboutImpl>
implements _$$AboutImplCopyWith<$Res> {
__$$AboutImplCopyWithImpl(
_$AboutImpl _value,
$Res Function(_$AboutImpl) _then,
) : super(_value, _then);
/// Create a copy of SettingsState
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
class _$AboutImpl implements _About {
const _$AboutImpl();
@override
String toString() {
return 'SettingsState.about()';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType && other is _$AboutImpl);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() profile,
required TResult Function() notifications,
required TResult Function() faq,
required TResult Function() about,
}) {
return about();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? initial,
TResult? Function()? profile,
TResult? Function()? notifications,
TResult? Function()? faq,
TResult? Function()? about,
}) {
return about?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? profile,
TResult Function()? notifications,
TResult Function()? faq,
TResult Function()? about,
required TResult orElse(),
}) {
if (about != null) {
return about();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_Profile value) profile,
required TResult Function(_Notifications value) notifications,
required TResult Function(_Faq value) faq,
required TResult Function(_About value) about,
}) {
return about(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Initial value)? initial,
TResult? Function(_Profile value)? profile,
TResult? Function(_Notifications value)? notifications,
TResult? Function(_Faq value)? faq,
TResult? Function(_About value)? about,
}) {
return about?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_Profile value)? profile,
TResult Function(_Notifications value)? notifications,
TResult Function(_Faq value)? faq,
TResult Function(_About value)? about,
required TResult orElse(),
}) {
if (about != null) {
return about(this);
}
return orElse();
}
}
abstract class _About implements SettingsState {
const factory _About() = _$AboutImpl;
}

View File

@@ -0,0 +1,10 @@
part of 'settings_cubit.dart';
@freezed
class SettingsState with _$SettingsState {
const factory SettingsState.initial() = _Initial;
const factory SettingsState.profile() = _Profile;
const factory SettingsState.notifications() = _Notifications;
const factory SettingsState.faq() = _Faq;
const factory SettingsState.about() = _About;
}

View File

@@ -1,5 +1,20 @@
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/functions.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/screens/settings/cubit/settings_cubit.dart';
import 'package:remever/screens/settings/states/about.dart';
import 'package:remever/screens/settings/states/faq.dart';
import 'package:remever/screens/settings/states/initial.dart';
import 'package:remever/screens/settings/states/notifications.dart';
import 'package:remever/screens/settings/states/profile.dart';
import 'package:remever/widgets/primary_button.dart';
@RoutePage()
class SettingsScreen extends StatelessWidget {
@@ -7,6 +22,29 @@ class SettingsScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return const Placeholder(color: Colors.red);
return BlocProvider<SettingsCubit>(
create: (BuildContext context) => SettingsCubit(),
child: _buildMain(),
);
}
///
/// Построение основного блока
///
Widget _buildMain() {
return PopScope(
canPop: false,
child: BlocBuilder<SettingsCubit, SettingsState>(
builder: (BuildContext context, state) {
return state.when(
initial: () => InitialSettingsState(),
profile: () => ProfileSettingsState(),
notifications: () => NotificationsSettingsState(),
faq: () => FaqSettingsState(),
about: () => AboutSettingsState(),
);
},
),
);
}
}

View File

@@ -0,0 +1,81 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:remever/common/functions.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/screens/settings/cubit/settings_cubit.dart';
import 'package:remever/widgets/primary_button.dart';
class AboutSettingsState extends StatelessWidget {
const AboutSettingsState({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.bg,
appBar: AppBar(
toolbarHeight: 66.h,
backgroundColor: AppColors.white,
shadowColor: Colors.transparent,
centerTitle: true,
title: AppTypography('О приложении', type: SemiBold20px()),
leading: IconButton(
onPressed: () {
context.read<SettingsCubit>().toInitialState();
},
icon: Icon(CupertinoIcons.left_chevron),
color: Colors.black,
),
actions: <Widget>[
IconButton(
onPressed: () {
showInfoToast('тут будет sharing');
},
icon: Assets.icons.settingsShare.image(height: 24.h, width: 24.w),
color: Colors.black,
),
],
),
body: Padding(
padding: const EdgeInsets.all(16).r,
child: Column(
children: [
Spacer(),
Assets.images.logo.image(width: 308.w, height: 100.h),
AppTypography(
'Версия приложения: 1.10.12\nот 23.05.2025',
type: Regular12px(),
maxLines: 2,
textAlign: TextAlign.center,
),
Spacer(),
AppTypography(
'Лицензионное соглашение',
type: Regular14px(),
color: AppColors.primary,
),
HSpace(10),
AppTypography(
'Политика конфиденциальности',
type: Regular14px(),
color: AppColors.primary,
),
HSpace(60),
PrimaryButton(
onTap: () {},
child: AppTypography(
'Обновить приложение',
type: Medium14px(),
color: AppColors.white,
),
),
],
),
),
);
}
}

View File

@@ -0,0 +1,92 @@
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/wspace.dart';
import 'package:remever/components/extensions/context.dart';
import 'package:remever/screens/settings/cubit/settings_cubit.dart';
import 'package:remever/widgets/primary_button.dart';
class FaqSettingsState extends StatelessWidget {
const FaqSettingsState({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.bg,
appBar: _buildAppBar(context),
body: Padding(
padding: const EdgeInsets.all(16).r,
child: Column(
children: [
Expanded(
child: Container(
width: double.infinity,
decoration: BoxDecoration(
color: AppColors.white,
borderRadius: BorderRadius.all(Radius.circular(12)).r,
),
child: _buildFaqList(),
),
),
HSpace(16),
PrimaryButton(
onTap: () {},
child: AppTypography(
'Задать свой вопрос',
type: Medium14px(),
color: AppColors.white,
),
),
],
),
),
);
}
Widget _buildFaqList() {
return ListView(
children: [
_buildExpansion('Есть ли ограничения по количеству коллекций?', 'Нет'),
Divider(thickness: 1, height: 1, color: AppColors.bg),
_buildExpansion(
'Как поделиться коллекцией с друзьями?',
'Другу необходимо установить приложение Remever на свой телефон, после этого вы сможете обмениваться друг с другом коллекциями',
),
Divider(thickness: 1, height: 1, color: AppColors.bg),
_buildExpansion('Можно ли пользоваться бесплатно?', 'Пока да'),
Divider(thickness: 1, height: 1, color: AppColors.bg),
],
);
}
/// AppBar экрана FAQ
AppBar _buildAppBar(BuildContext context) {
return AppBar(
toolbarHeight: 66.h,
backgroundColor: AppColors.white,
shadowColor: Colors.transparent,
centerTitle: true,
title: AppTypography('FAQ', type: SemiBold20px()),
leading: IconButton(
onPressed: () => context.read<SettingsCubit>().toInitialState(),
icon: Icon(CupertinoIcons.left_chevron),
color: Colors.black,
),
);
}
Widget _buildExpansion(String title, String answer) {
return ExpansionTile(
title: AppTypography(title, type: Medium16px(), maxLines: 2),
textColor: Colors.black,
children: [
ListTile(
title: AppTypography(answer, type: Regular14px(), maxLines: 99),
),
],
);
}
}

View File

@@ -0,0 +1,136 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:remever/common/functions.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/screens/settings/cubit/settings_cubit.dart';
import 'package:remever/widgets/primary_button.dart';
class InitialSettingsState extends StatelessWidget {
const InitialSettingsState({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.bg,
appBar: _buildAppBar(context),
body: Padding(
padding: EdgeInsets.all(16.r),
child: Column(
children: [
_buildSettingsItem(
context,
Assets.icons.settingsProfile,
'Профиль',
SettingsCubitType.profile,
),
HSpace(8),
_buildSettingsItem(
context,
Assets.icons.settingsNotification,
'Уведомления',
SettingsCubitType.notifications,
),
HSpace(8),
_buildSettingsItem(
context,
Assets.icons.settingsFaq,
'FAQ',
SettingsCubitType.faq,
),
HSpace(8),
_buildSettingsItem(
context,
Assets.icons.settingsAbout,
'О приложении',
SettingsCubitType.about,
),
const Spacer(),
_buildContactDeveloperButton(),
],
),
),
);
}
/// AppBar экрана настроек
AppBar _buildAppBar(BuildContext context) {
return AppBar(
toolbarHeight: 66.h,
backgroundColor: AppColors.white,
shadowColor: Colors.transparent,
centerTitle: true,
leadingWidth: 0,
title: AppTypography('Настройки', type: SemiBold20px()),
actions: [
IconButton(
onPressed: () => showInfoToast('Тут будет выход'),
icon: Assets.icons.settingsExit.image(height: 24.h, width: 24.w),
color: Colors.black,
),
],
);
}
/// Общий метод для построения пункта меню
Widget _buildSettingsItem(
BuildContext context,
AssetGenImage icon,
String title,
SettingsCubitType cubitType,
) {
return GestureDetector(
onTap: () => _navigateToSection(context, cubitType),
child: Container(
width: double.infinity,
decoration: BoxDecoration(
color: AppColors.white,
borderRadius: BorderRadius.circular(12.r),
),
margin: EdgeInsets.zero,
padding: EdgeInsets.symmetric(vertical: 16.r, horizontal: 12.r),
child: Row(
children: [
icon.image(height: 24.h, width: 24.w),
WSpace(8),
AppTypography(title, type: Regular16px()),
],
),
),
);
}
/// Метод для навигации к разделу через Cubit
void _navigateToSection(BuildContext context, SettingsCubitType cubitType) {
switch (cubitType) {
case SettingsCubitType.initial:
context.read<SettingsCubit>().toInitialState();
case SettingsCubitType.profile:
context.read<SettingsCubit>().toProfileState();
case SettingsCubitType.notifications:
context.read<SettingsCubit>().toNotificationsState();
case SettingsCubitType.faq:
context.read<SettingsCubit>().toFaqState();
case SettingsCubitType.about:
context.read<SettingsCubit>().toAboutState();
}
}
/// Кнопка "Написать разработчику"
Widget _buildContactDeveloperButton() {
return PrimaryButton(
child: AppTypography(
'Написать разработчику',
color: AppColors.white,
type: Medium14px(),
),
onTap: () {},
);
}
}
/// Перечисление типов состояний для SettingsCubit
enum SettingsCubitType { initial, profile, notifications, faq, about }

View File

@@ -0,0 +1,103 @@
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/widgets/typography.dart';
import 'package:remever/components/extensions/context.dart';
import 'package:remever/screens/settings/cubit/settings_cubit.dart';
class NotificationsSettingsState extends StatelessWidget {
const NotificationsSettingsState({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.bg,
appBar: AppBar(
toolbarHeight: 66.h,
backgroundColor: AppColors.white,
shadowColor: Colors.transparent,
centerTitle: true,
title: AppTypography('Уведомления', type: SemiBold20px()),
leading: IconButton(
onPressed: () {
context.read<SettingsCubit>().toInitialState();
},
icon: Icon(CupertinoIcons.left_chevron),
color: Colors.black,
),
),
body: Padding(
padding: const EdgeInsets.all(16).r,
child: Column(
spacing: 10,
children: [
_buildInfoLine(
context,
'Напоминание о тренировке',
'Начнешь тренировку вовремя для эффективного запоминания. Уведомления будут приходить в период с 9:00 до 23:00',
),
_buildInfoLine(
context,
'От разработчика',
'Обновление приложения, скидки и акции',
),
_buildInfoLine(
context,
'Мои коллекции',
'Появление новых карточек в избранных коллекциях и новых коллекций у любимых авторов',
),
_buildInfoLine(
context,
'Авторам коллекций',
'Новые подписчики в ваших публичных коллекциях и предложенные ими карточки',
),
],
),
),
);
}
Widget _buildInfoLine(BuildContext context, String title, String subTitle) {
return GestureDetector(
onTap: () {},
child: Container(
width: double.infinity,
decoration: BoxDecoration(
color: AppColors.white,
borderRadius: BorderRadius.all(Radius.circular(12)).r,
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 16).r,
child: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AppTypography(
title,
type: Regular16px(),
color: Colors.black,
),
AppTypography(
subTitle,
type: Regular12px(),
color: AppColors.disabled,
maxLines: 99,
),
],
),
),
CupertinoSwitch(
value: true,
onChanged: (value) {},
activeTrackColor: AppColors.primary,
),
],
),
),
),
);
}
}

View File

@@ -0,0 +1,130 @@
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/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/screens/settings/cubit/settings_cubit.dart';
import 'package:remever/common/functions.dart';
class ProfileSettingsState extends StatelessWidget {
const ProfileSettingsState({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.bg,
appBar: _buildAppBar(context),
body: Padding(
padding: EdgeInsets.all(16.r),
child: Container(
width: double.infinity,
height: 410.h,
decoration: BoxDecoration(
color: AppColors.white,
borderRadius: BorderRadius.circular(12.r),
),
child: Column(
children: [
HSpace(32),
_buildAvatar(),
HSpace(12),
_buildInfoLine(
context,
Assets.icons.settingsName,
'Антон Городецкий',
Colors.black,
() {},
),
_buildDivider(),
_buildInfoLine(
context,
Assets.icons.settingsMail,
'anton.gorod@gmail.com',
Colors.black,
() {},
),
_buildDivider(),
_buildInfoLine(
context,
Assets.icons.settingsPhone,
'+7 900 123 45 67',
Colors.black,
() {},
),
_buildDivider(thickness: 3),
_buildInfoLine(
context,
Assets.icons.settingsTrash,
'Удалить профиль',
AppColors.danger,
() {},
),
],
),
),
),
);
}
/// AppBar экрана профиля
AppBar _buildAppBar(BuildContext context) {
return AppBar(
toolbarHeight: 66.h,
backgroundColor: AppColors.white,
shadowColor: Colors.transparent,
centerTitle: true,
title: AppTypography('Профиль', type: SemiBold20px()),
leading: IconButton(
onPressed: () => context.read<SettingsCubit>().toInitialState(),
icon: const Icon(CupertinoIcons.left_chevron),
color: Colors.black,
),
actions: [
IconButton(
onPressed: () => showInfoToast('Тут будет выход'),
icon: Assets.icons.settingsExit.image(height: 24.h, width: 24.w),
color: Colors.black,
),
],
);
}
/// Аватар пользователя
Widget _buildAvatar() {
return CircleAvatar(
backgroundImage: Assets.images.imgCard.provider(),
radius: 82.r,
);
}
/// Общий элемент информации
Widget _buildInfoLine(
BuildContext context,
AssetGenImage icon,
String title,
Color color,
void Function()? onTap,
) {
return GestureDetector(
onTap: onTap,
child: Padding(
padding: EdgeInsets.all(16.r),
child: Row(
children: [
icon.image(height: 20.h, width: 20.w),
WSpace(12),
AppTypography(title, type: Medium16px(), color: color),
],
),
),
);
}
/// Переиспользуемый разделитель
Widget _buildDivider({double thickness = 1}) {
return Divider(height: 1, thickness: thickness);
}
}