mirror of
https://github.com/smmarty/friflex_flutter_starter.git
synced 2025-12-22 01:20:46 +00:00
feat(update): добавить модуль управления Hard & Soft обновлений (#30)
1. Реализован интерфейс и репозитории для проверки обновлений. 2. Добавлены состояния и кубит для управления процессом обновления. 3. Созданы UI-компоненты для отображения информации об обновлениях. 4. Обновлен README.md с описанием нового модуля и его интеграции
This commit is contained in:
@@ -1,6 +1,12 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:friflex_starter/app/ui_kit/app_box.dart';
|
||||
import 'package:friflex_starter/app/ui_kit/app_snackbar.dart';
|
||||
import 'package:friflex_starter/features/update/domain/state/cubit/update_cubit.dart';
|
||||
import 'package:friflex_starter/features/update/presentation/components/soft_modal_sheet.dart';
|
||||
import 'package:friflex_starter/features/update/update_routes.dart';
|
||||
import 'package:friflex_starter/features/update/update_type.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
/// {@template components_screen}
|
||||
/// Экран для демонстрации и тестирования компонентов приложения.
|
||||
@@ -66,6 +72,33 @@ class _ComponentsScreenState extends State<ComponentsScreen> {
|
||||
},
|
||||
child: const Text('Показать снекбар с информацией'),
|
||||
),
|
||||
const HBox(16),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
final updateCubitState = context.read<UpdateCubit>().state;
|
||||
if (updateCubitState is UpdateSuccessState &&
|
||||
updateCubitState.updateInfo.updateType == UpdateType.soft) {
|
||||
SoftUpdateModal.show(
|
||||
context,
|
||||
updateEntity: updateCubitState.updateInfo,
|
||||
onUpdate: () {
|
||||
AppSnackBar.showSuccess(
|
||||
context: context,
|
||||
message: 'Начато обновление приложения',
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
child: const Text('Показать модальное окно обновления'),
|
||||
),
|
||||
const HBox(16),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
context.pushNamed(UpdateRoutes.hardUpdateScreenName);
|
||||
},
|
||||
child: const Text('Переход на экран Hard Update обновления'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:friflex_starter/app/app_context_ext.dart';
|
||||
import 'package:friflex_starter/app/app_env.dart';
|
||||
import 'package:friflex_starter/features/debug/debug_routes.dart';
|
||||
import 'package:friflex_starter/features/update/domain/state/cubit/update_cubit.dart';
|
||||
import 'package:friflex_starter/features/update/presentation/components/soft_modal_sheet.dart';
|
||||
import 'package:friflex_starter/features/update/update_type.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
/// {@template root_screen}
|
||||
@@ -13,7 +17,7 @@ import 'package:go_router/go_router.dart';
|
||||
/// - Отображение кнопки отладки в не-продакшн окружениях
|
||||
/// - Интеграцию с GoRouter для навигации
|
||||
/// {@endtemplate}
|
||||
class RootScreen extends StatelessWidget {
|
||||
class RootScreen extends StatefulWidget {
|
||||
/// {@macro root_screen}
|
||||
const RootScreen({required this.navigationShell, super.key});
|
||||
|
||||
@@ -21,6 +25,38 @@ class RootScreen extends StatelessWidget {
|
||||
/// Содержит информацию о текущем состоянии навигации
|
||||
final StatefulNavigationShell navigationShell;
|
||||
|
||||
@override
|
||||
State<RootScreen> createState() => _RootScreenState();
|
||||
}
|
||||
|
||||
class _RootScreenState extends State<RootScreen> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
// После построения виджета, проверяем состояние кубита обновлений
|
||||
// и если есть обновление, то показываем модальное окно
|
||||
_checkSoftUpdate();
|
||||
}
|
||||
|
||||
/// Проверяет состояние кубита обновлений и показывает модальное окно при наличии мягкого обновления
|
||||
void _checkSoftUpdate() {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
final updateState = context.read<UpdateCubit>().state;
|
||||
|
||||
// Проверяем только состояние успеха с доступной информацией об обновлении
|
||||
if (updateState is UpdateSuccessState &&
|
||||
updateState.updateInfo.updateType == UpdateType.soft) {
|
||||
SoftUpdateModal.show(
|
||||
context,
|
||||
updateEntity: updateState.updateInfo,
|
||||
onUpdate: () {
|
||||
// TODO(yura): реализовать логику обновления приложения
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
@@ -32,14 +68,14 @@ class RootScreen extends StatelessWidget {
|
||||
},
|
||||
)
|
||||
: null,
|
||||
body: navigationShell,
|
||||
body: widget.navigationShell,
|
||||
bottomNavigationBar: BottomNavigationBar(
|
||||
items: const <BottomNavigationBarItem>[
|
||||
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Главная'),
|
||||
BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Профиль'),
|
||||
],
|
||||
currentIndex: navigationShell.currentIndex,
|
||||
onTap: navigationShell.goBranch,
|
||||
currentIndex: widget.navigationShell.currentIndex,
|
||||
onTap: widget.navigationShell.goBranch,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
88
lib/features/update/README.md
Normal file
88
lib/features/update/README.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# Модуль Hard/Soft Updates
|
||||
|
||||
Модуль для управления обновлениями приложения. Поддерживает мягкие (soft) и обязательные (hard) обновления.
|
||||
|
||||
## Ключевые сущности и состояния
|
||||
|
||||
- **`UpdateEntity`**: доменная сущность с данными об обновлении
|
||||
- `availableVersion`: доступная версия
|
||||
- `updateUrl`: ссылка на обновление
|
||||
- `updateType`: тип (`soft` | `hard`), см. `UpdateType`
|
||||
- `whatIsNew`: описание изменений
|
||||
|
||||
- **`UpdateType`**: перечисление типов обновления
|
||||
- `UpdateType.soft`
|
||||
- `UpdateType.hard`
|
||||
- `UpdateType.none`
|
||||
|
||||
- **`UpdateCubit`**: управление состоянием проверки обновлений
|
||||
- Состояния: `UpdateInitialState`, `UpdateLoadingState`, `UpdateSuccessState(UpdateEntity?)`, `UpdateErrorState(message)`
|
||||
- Метод: `checkForUpdates({required String versionCode, required String platform})`
|
||||
|
||||
## Репозитории
|
||||
|
||||
- **`IUpdateRepository`**: Интерфейс, описывающий методы для проверки обновлений.
|
||||
- Возвращает `Future<UpdateEntity>` (не может быть `null`)
|
||||
|
||||
- **`UpdateRepository`**: заготовка для реальной интеграции (бэкенд/стор)
|
||||
- Реализуйте логику в `checkForUpdates`
|
||||
|
||||
- **`UpdateMockRepository`**: мок-реализация для разработки/демо
|
||||
- Возвращает фиктивное обновление (по умолчанию soft)
|
||||
|
||||
## UI
|
||||
|
||||
- **Soft update** — `SoftUpdateModal`
|
||||
- BottomSheet с заголовком, списком изменений и кнопками: «Отложить» и «Обновить»
|
||||
- Статический метод `show` безопасно не откроет модалку, если `updateEntity == null`
|
||||
|
||||
Пример показа модального окна:
|
||||
```dart
|
||||
await SoftUpdateModal.show(
|
||||
context,
|
||||
updateEntity: updateEntity, // экземпляр UpdateEntity
|
||||
onUpdate: () {
|
||||
// TODO: переход в стор/браузер по updateEntity.updateUrl
|
||||
},
|
||||
);
|
||||
```
|
||||
|
||||
- **Hard update** — `HardUpdateScreen`
|
||||
- Блокирующий экран, информирует и не даёт продолжить без обновления
|
||||
|
||||
## Роуты
|
||||
|
||||
- `UpdateRoutes.buildRoutes()` — регистрирует экран hard-обновления по пути `/update`
|
||||
|
||||
|
||||
## Структура модуля
|
||||
|
||||
```
|
||||
features/update/
|
||||
├── data/
|
||||
│ └── repository/
|
||||
│ ├── update_repository.dart # реализация для интеграции
|
||||
│ └── update_mock_repository.dart # мок-репозиторий
|
||||
├── domain/
|
||||
│ ├── entity/
|
||||
│ │ └── update_entity.dart # доменная сущность
|
||||
│ ├── repository/
|
||||
│ │ └── i_update_repository.dart # контракт репозитория
|
||||
│ └── state/
|
||||
│ └── cubit/
|
||||
│ ├── update_cubit.dart # кубит и логика
|
||||
│ └── update_state.dart # состояния
|
||||
├── presentation/
|
||||
│ ├── components/
|
||||
│ │ └── soft_modal_sheet.dart # модалка для soft-обновления
|
||||
│ └── screens/
|
||||
│ └── hard_update_screen.dart # экран для hard-обновления
|
||||
├── update_type.dart # константы типов обновления
|
||||
└── update_routes.dart # роут на hard-экран
|
||||
```
|
||||
|
||||
## Заметки по реализации
|
||||
|
||||
- Для продакшена реализуйте переход в магазин или браузер по `updateUrl`
|
||||
- Для soft-обновления не блокируйте UX; для hard — перенаправляйте на блокирующий экран
|
||||
- Возвращайте `null` из репозитория, если обновлений нет
|
||||
@@ -0,0 +1,43 @@
|
||||
import 'package:friflex_starter/features/update/domain/entity/update_entity.dart';
|
||||
import 'package:friflex_starter/features/update/domain/repository/i_update_repository.dart';
|
||||
import 'package:friflex_starter/features/update/update_type.dart';
|
||||
|
||||
/// Мок обновления обязательное, можно использовать для тестирования
|
||||
const mockHardUpdateEntity = UpdateEntity(
|
||||
availableVersion: '2.0.0',
|
||||
updateUrl: 'https://example.com/update',
|
||||
updateType: UpdateType.hard,
|
||||
whatIsNew: 'Добавлены новые функции и исправлены ошибки.',
|
||||
);
|
||||
|
||||
/// Мок обновления мягкое, можно использовать для тестирования
|
||||
const mockSoftUpdateEntity = UpdateEntity(
|
||||
availableVersion: '2.0.0',
|
||||
updateUrl: 'https://example.com/update',
|
||||
updateType: UpdateType.soft,
|
||||
whatIsNew: 'Добавлены новые функции и исправлены ошибки.',
|
||||
);
|
||||
|
||||
/// {@template UpdateMockRepository}
|
||||
/// Репозиторий для моковой реализации проверки обновлений
|
||||
/// {@endtemplate}
|
||||
final class UpdateMockRepository implements IUpdateRepository {
|
||||
/// {@macro UpdateMockRepository}
|
||||
const UpdateMockRepository();
|
||||
|
||||
@override
|
||||
Future<UpdateEntity> checkForUpdates({
|
||||
required String versionCode,
|
||||
required String platform,
|
||||
}) async {
|
||||
// Имитация задержки для асинхронной операции
|
||||
await Future<void>.delayed(const Duration(seconds: 1));
|
||||
|
||||
// Возвращаем фиктивные данные об обновлении
|
||||
// Можно возвращать [_mockHardUpdateEntity] или [_mockSoftUpdateEntity]
|
||||
return mockSoftUpdateEntity;
|
||||
}
|
||||
|
||||
@override
|
||||
String get name => 'UpdateMockRepository';
|
||||
}
|
||||
23
lib/features/update/data/repository/update_repository.dart
Normal file
23
lib/features/update/data/repository/update_repository.dart
Normal file
@@ -0,0 +1,23 @@
|
||||
import 'package:friflex_starter/features/update/domain/entity/update_entity.dart';
|
||||
import 'package:friflex_starter/features/update/domain/repository/i_update_repository.dart';
|
||||
|
||||
/// {@template UpdateRepository}
|
||||
/// Репозиторий для реализации проверки обновлений
|
||||
/// {@endtemplate}
|
||||
final class UpdateRepository implements IUpdateRepository {
|
||||
/// {@macro UpdateRepository}
|
||||
const UpdateRepository();
|
||||
|
||||
@override
|
||||
Future<UpdateEntity> checkForUpdates({
|
||||
required String versionCode,
|
||||
required String platform,
|
||||
}) {
|
||||
// TODO: Реализовать реальную логику проверки обновлений
|
||||
// Если обновления нет, возвращаем null
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
String get name => 'UpdateRepository';
|
||||
}
|
||||
35
lib/features/update/domain/entity/update_entity.dart
Normal file
35
lib/features/update/domain/entity/update_entity.dart
Normal file
@@ -0,0 +1,35 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:friflex_starter/features/update/update_type.dart';
|
||||
|
||||
/// {@template UpdateEntity}
|
||||
/// Сущность для представления информации об обновлении
|
||||
/// {@endtemplate}
|
||||
class UpdateEntity extends Equatable {
|
||||
/// {@macro UpdateEntity}
|
||||
const UpdateEntity({
|
||||
required this.availableVersion,
|
||||
required this.updateUrl,
|
||||
required this.updateType,
|
||||
required this.whatIsNew,
|
||||
});
|
||||
|
||||
/// Доступная версия обновления
|
||||
final String availableVersion;
|
||||
|
||||
/// URL для загрузки обновления
|
||||
final String updateUrl;
|
||||
|
||||
/// Тип обновления (например, 'hard' или 'soft', или не требуется)
|
||||
final UpdateType updateType;
|
||||
|
||||
/// Описание изменений в обновлении
|
||||
final String whatIsNew;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
availableVersion,
|
||||
updateUrl,
|
||||
updateType,
|
||||
whatIsNew,
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import 'package:friflex_starter/di/di_base_repo.dart';
|
||||
import 'package:friflex_starter/features/update/domain/entity/update_entity.dart';
|
||||
|
||||
/// {@template IUpdateRepository}
|
||||
/// Интерфейс репозитория для Hard&Soft обновлений
|
||||
/// {@endtemplate}
|
||||
abstract interface class IUpdateRepository with DiBaseRepo {
|
||||
/// Проверяет наличие обновлений
|
||||
/// [versionCode] - текущий код версии приложения
|
||||
/// [platform] - платформа (например, 'android' или 'ios')
|
||||
/// Возвращает [UpdateEntity] с информацией об обновлении
|
||||
Future<UpdateEntity> checkForUpdates({
|
||||
required String versionCode,
|
||||
required String platform,
|
||||
});
|
||||
}
|
||||
38
lib/features/update/domain/state/cubit/update_cubit.dart
Normal file
38
lib/features/update/domain/state/cubit/update_cubit.dart
Normal file
@@ -0,0 +1,38 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:friflex_starter/features/update/domain/entity/update_entity.dart';
|
||||
import 'package:friflex_starter/features/update/domain/repository/i_update_repository.dart';
|
||||
|
||||
part 'update_state.dart';
|
||||
|
||||
/// {@template UpdateCubit}
|
||||
/// Кубит для управления состояниями обновления приложения
|
||||
/// {@endtemplate}
|
||||
class UpdateCubit extends Cubit<UpdateState> {
|
||||
/// {@macro UpdateCubit}
|
||||
UpdateCubit(this._updatesRepository) : super(UpdateInitialState());
|
||||
|
||||
/// Репозиторий для проверки обновлений
|
||||
final IUpdateRepository _updatesRepository;
|
||||
|
||||
/// Метод для проверки доступности обновлений
|
||||
/// [versionCode] - текущий код версии приложения
|
||||
/// [platform] - платформа (например, 'android' или 'ios')
|
||||
Future<void> checkForUpdates({
|
||||
required String versionCode,
|
||||
required String platform,
|
||||
}) async {
|
||||
if (state is UpdateLoadingState) return;
|
||||
emit(UpdateLoadingState());
|
||||
try {
|
||||
final updateInfo = await _updatesRepository.checkForUpdates(
|
||||
versionCode: versionCode,
|
||||
platform: platform,
|
||||
);
|
||||
emit(UpdateSuccessState(updateInfo));
|
||||
} on Object catch (e, st) {
|
||||
emit(UpdateErrorState(e.toString()));
|
||||
addError(e, st);
|
||||
}
|
||||
}
|
||||
}
|
||||
56
lib/features/update/domain/state/cubit/update_state.dart
Normal file
56
lib/features/update/domain/state/cubit/update_state.dart
Normal file
@@ -0,0 +1,56 @@
|
||||
part of 'update_cubit.dart';
|
||||
|
||||
/// {@template UpdateState}
|
||||
/// Состояния для управления процессом обновления приложения
|
||||
/// {@endtemplate}
|
||||
sealed class UpdateState extends Equatable {
|
||||
/// {@macro UpdateState}
|
||||
const UpdateState();
|
||||
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
/// {@template UpdateInitialState}
|
||||
/// Состояние начальной инициализации
|
||||
/// {@endtemplate}
|
||||
final class UpdateInitialState extends UpdateState {
|
||||
/// {@macro UpdateInitialState}
|
||||
const UpdateInitialState();
|
||||
}
|
||||
|
||||
/// {@template UpdateLoadingState}
|
||||
/// Состояние загрузки информации об обновлении
|
||||
/// {@endtemplate}
|
||||
final class UpdateLoadingState extends UpdateState {
|
||||
/// {@macro UpdateLoadingState}
|
||||
const UpdateLoadingState();
|
||||
}
|
||||
|
||||
/// {@template UpdateSuccessState}
|
||||
/// Состояние успешного получения информации об обновлении
|
||||
/// {@endtemplate}
|
||||
final class UpdateSuccessState extends UpdateState {
|
||||
/// {@macro UpdateSuccessState}
|
||||
const UpdateSuccessState(this.updateInfo);
|
||||
|
||||
/// Информация об обновлении
|
||||
final UpdateEntity updateInfo;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [updateInfo];
|
||||
}
|
||||
|
||||
/// {@template UpdateErrorState}
|
||||
/// Состояние ошибки при получении информации об обновлении
|
||||
/// {@endtemplate}
|
||||
final class UpdateErrorState extends UpdateState {
|
||||
/// {@macro UpdateErrorState}
|
||||
const UpdateErrorState(this.message);
|
||||
|
||||
/// Сообщение об ошибке в UI
|
||||
final String message;
|
||||
|
||||
@override
|
||||
List<Object> get props => [message];
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:friflex_starter/app/ui_kit/app_box.dart';
|
||||
import 'package:friflex_starter/features/update/domain/entity/update_entity.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
/// {@template soft_update_modal}
|
||||
/// Модальное окно для уведомления о доступности новой версии приложения.
|
||||
///
|
||||
/// Отвечает за:
|
||||
/// - Отображение информации о новой версии приложения
|
||||
/// - Предоставление возможности обновления или отложения
|
||||
/// - Показ описания изменений в новой версии
|
||||
/// - Мягкое уведомление пользователя без принуждения к обновлению
|
||||
/// {@endtemplate}
|
||||
class SoftUpdateModal extends StatelessWidget {
|
||||
/// {@macro soft_update_modal}
|
||||
const SoftUpdateModal({required this.updateEntity, this.onUpdate, super.key});
|
||||
|
||||
/// Информация об обновлении
|
||||
final UpdateEntity updateEntity;
|
||||
|
||||
/// Обратный вызов при нажатии "Обновить"
|
||||
final VoidCallback? onUpdate;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Заголовок
|
||||
Text(
|
||||
'Доступна новая версия: ${updateEntity.availableVersion} ',
|
||||
style: Theme.of(
|
||||
context,
|
||||
).textTheme.headlineSmall?.copyWith(fontWeight: FontWeight.bold),
|
||||
),
|
||||
|
||||
const HBox(16),
|
||||
|
||||
// Описание изменений
|
||||
Text(
|
||||
'Что нового:',
|
||||
style: Theme.of(
|
||||
context,
|
||||
).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w600),
|
||||
),
|
||||
const HBox(8),
|
||||
Text(
|
||||
updateEntity.whatIsNew,
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
),
|
||||
|
||||
const HBox(24),
|
||||
|
||||
// Кнопки действий
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: OutlinedButton(
|
||||
onPressed: () {
|
||||
context.pop();
|
||||
},
|
||||
child: const Text('Отложить'),
|
||||
),
|
||||
),
|
||||
const WBox(12),
|
||||
Expanded(
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
context.pop();
|
||||
onUpdate?.call();
|
||||
},
|
||||
child: const Text('Обновить'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Показать модальное окно обновления
|
||||
///
|
||||
/// [context] - контекст для отображения модального окна
|
||||
/// [updateEntity] - информация об обновлении
|
||||
/// [onUpdate] - функция при нажатии "Обновить"
|
||||
static Future<void> show(
|
||||
BuildContext context, {
|
||||
required UpdateEntity updateEntity,
|
||||
VoidCallback? onUpdate,
|
||||
}) {
|
||||
return showModalBottomSheet<void>(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
builder: (context) =>
|
||||
SoftUpdateModal(updateEntity: updateEntity, onUpdate: onUpdate),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:friflex_starter/app/ui_kit/app_box.dart';
|
||||
import 'package:friflex_starter/features/update/domain/state/cubit/update_cubit.dart';
|
||||
|
||||
/// Блокирующий экран для обязательного обновления приложения
|
||||
class HardUpdateScreen extends StatelessWidget {
|
||||
const HardUpdateScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('Hard Обновление')),
|
||||
body: Center(
|
||||
child: BlocBuilder<UpdateCubit, UpdateState>(
|
||||
builder: (context, updateCubitState) {
|
||||
final updateEntity = updateCubitState is UpdateSuccessState
|
||||
? updateCubitState.updateInfo
|
||||
: null;
|
||||
return Column(
|
||||
children: [
|
||||
const Text(
|
||||
'Доступна новая версия приложения. Пожалуйста, обновите его.',
|
||||
),
|
||||
const HBox(16),
|
||||
Text(
|
||||
'Доступная версия: ${updateEntity?.availableVersion ?? ''}',
|
||||
),
|
||||
const HBox(8),
|
||||
Text('Что нового: ${updateEntity?.whatIsNew ?? ''}'),
|
||||
const HBox(8),
|
||||
Text('Тип обновления: ${updateEntity?.updateType ?? ''}'),
|
||||
const HBox(8),
|
||||
Text('URL для обновления: ${updateEntity?.updateUrl ?? ''}'),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
20
lib/features/update/update_routes.dart
Normal file
20
lib/features/update/update_routes.dart
Normal file
@@ -0,0 +1,20 @@
|
||||
import 'package:friflex_starter/features/update/presentation/screens/hard_update_screen.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
abstract final class UpdateRoutes {
|
||||
/// Название роута главной страницы
|
||||
static const String hardUpdateScreenName = 'update_screen';
|
||||
|
||||
/// Путь роута экрана обновления
|
||||
static const String _hardUpdateScreenPath = '/update';
|
||||
|
||||
/// Метод для построения роутов по Update
|
||||
///
|
||||
/// Принимает:
|
||||
/// - [routes] - вложенные роуты
|
||||
static GoRoute buildRoutes({List<RouteBase> routes = const []}) => GoRoute(
|
||||
path: _hardUpdateScreenPath,
|
||||
name: hardUpdateScreenName,
|
||||
builder: (context, state) => const HardUpdateScreen(),
|
||||
);
|
||||
}
|
||||
13
lib/features/update/update_type.dart
Normal file
13
lib/features/update/update_type.dart
Normal file
@@ -0,0 +1,13 @@
|
||||
/// {@template UpdateType}
|
||||
/// Тип обновления
|
||||
/// {@endtemplate}
|
||||
enum UpdateType {
|
||||
/// Обязательное обновление
|
||||
hard,
|
||||
|
||||
/// Мягкое обновление
|
||||
soft,
|
||||
|
||||
/// Не требуется обновление
|
||||
none,
|
||||
}
|
||||
Reference in New Issue
Block a user