Приложение на флаторе, настройки
This commit is contained in:
44
client-mobile/.gitignore
vendored
Normal file
44
client-mobile/.gitignore
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
# Miscellaneous
|
||||
*.class
|
||||
*.log
|
||||
*.pyc
|
||||
*.swp
|
||||
.DS_Store
|
||||
.atom/
|
||||
.buildlog/
|
||||
.history
|
||||
.svn/
|
||||
migrate_working_dir/
|
||||
|
||||
# IntelliJ related
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
|
||||
# The .vscode folder contains launch configuration and tasks you configure in
|
||||
# VS Code which you may wish to be included in version control, so this line
|
||||
# is commented out by default.
|
||||
#.vscode/
|
||||
|
||||
# Flutter/Dart/Pub related
|
||||
**/doc/api/
|
||||
**/ios/Flutter/.last_build_id
|
||||
.dart_tool/
|
||||
.flutter-plugins
|
||||
.flutter-plugins-dependencies
|
||||
.packages
|
||||
.pub-cache/
|
||||
.pub/
|
||||
/build/
|
||||
|
||||
# Symbolication related
|
||||
app.*.symbols
|
||||
|
||||
# Obfuscation related
|
||||
app.*.map.json
|
||||
|
||||
# Android Studio will place build artifacts here
|
||||
/android/app/debug
|
||||
/android/app/profile
|
||||
/android/app/release
|
||||
20
client-mobile/.metadata
Normal file
20
client-mobile/.metadata
Normal file
@@ -0,0 +1,20 @@
|
||||
# This file tracks properties of this Flutter project.
|
||||
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||
#
|
||||
# This file should be version controlled and should not be manually edited.
|
||||
|
||||
version:
|
||||
revision: 5f120583730cedfc49a0e0872e3e1ac7a0a3c8eb
|
||||
channel: stable
|
||||
|
||||
project_type: app
|
||||
|
||||
# Tracks metadata for the flutter migrate command
|
||||
migration:
|
||||
platforms:
|
||||
- platform: root
|
||||
create_revision: 5f120583730cedfc49a0e0872e3e1ac7a0a3c8eb
|
||||
base_revision: 5f120583730cedfc49a0e0872e3e1ac7a0a3c8eb
|
||||
- platform: android
|
||||
create_revision: 5f120583730cedfc49a0e0872e3e1ac7a0a3c8eb
|
||||
base_revision: 5f120583730cedfc49a0e0872e3e1ac7a0a3c8eb
|
||||
125
client-mobile/GETTING_STARTED.md
Normal file
125
client-mobile/GETTING_STARTED.md
Normal file
@@ -0,0 +1,125 @@
|
||||
# Инструкция по запуску проекта
|
||||
|
||||
## Предварительные требования
|
||||
|
||||
1. **Flutter SDK** (версия 3.0.0 или выше)
|
||||
- Установите Flutter: https://docs.flutter.dev/get-started/install
|
||||
- Проверьте установку: `flutter doctor`
|
||||
|
||||
2. **Android Studio** или **VS Code** с Flutter плагином
|
||||
|
||||
3. **Android SDK** (для сборки под Android)
|
||||
- MinSDK: 21
|
||||
- TargetSDK: 34
|
||||
- CompileSDK: 34
|
||||
|
||||
## Установка зависимостей
|
||||
|
||||
```bash
|
||||
cd client-mobile
|
||||
flutter pub get
|
||||
```
|
||||
|
||||
## Генерация кода
|
||||
|
||||
Проект использует code generation для:
|
||||
- Freezed (immutable модели)
|
||||
- AutoRoute (навигация)
|
||||
- Isar (база данных)
|
||||
|
||||
```bash
|
||||
dart run build_runner build --delete-conflicting-outputs
|
||||
```
|
||||
|
||||
Для автоматической генерации при изменениях:
|
||||
```bash
|
||||
dart run build_runner watch --delete-conflicting-outputs
|
||||
```
|
||||
|
||||
## Запуск приложения
|
||||
|
||||
### Android
|
||||
```bash
|
||||
flutter run
|
||||
```
|
||||
|
||||
### Сборка релиза
|
||||
```bash
|
||||
flutter build apk --release
|
||||
```
|
||||
|
||||
## Структура проекта
|
||||
|
||||
```
|
||||
lib/
|
||||
├── core/ # Общие компоненты
|
||||
│ ├── constants/ # Константы приложения
|
||||
│ ├── errors/ # Обработка ошибок
|
||||
│ ├── network/ # Сетевой клиент (Dio)
|
||||
│ └── theme/ # Темы оформления
|
||||
├── features/ # Функциональные модули
|
||||
│ ├── auth/ # Аутентификация
|
||||
│ │ ├── data/ # Data layer
|
||||
│ │ ├── domain/ # Domain layer
|
||||
│ │ └── presentation/ # UI layer (BLoC, страницы)
|
||||
│ ├── chat/ # Чаты
|
||||
│ ├── profile/ # Профиль
|
||||
│ └── settings/ # Настройки
|
||||
└── internal/ # Внутренняя конфигурация
|
||||
├── di/ # Dependency Injection (GetIt)
|
||||
└── router/ # Навигация
|
||||
```
|
||||
|
||||
## Архитектура
|
||||
|
||||
Проект следует принципам **Clean Architecture**:
|
||||
|
||||
- **Domain Layer**: Бизнес-логика, entities, use cases, repository interfaces
|
||||
- **Data Layer**: Реализации репозиториев, datasources, модели
|
||||
- **Presentation Layer**: UI, BLoC, страницы, виджеты
|
||||
|
||||
## State Management
|
||||
|
||||
Используется **flutter_bloc** для управления состоянием:
|
||||
- Каждый feature имеет свой BLoC
|
||||
- События и состояния генерируются через Freezed
|
||||
- DI через GetIt
|
||||
|
||||
## Навигация
|
||||
|
||||
Используется **auto_route** для декларативной навигации.
|
||||
|
||||
## База данных
|
||||
|
||||
Используется **Isar** - быстрая NoSQL база данных для Flutter.
|
||||
|
||||
## Сетевые запросы
|
||||
|
||||
- **Dio** для REST API запросов
|
||||
- **SignalR** для real-time обновлений
|
||||
|
||||
## Тестирование
|
||||
|
||||
```bash
|
||||
flutter test
|
||||
```
|
||||
|
||||
## Полезные команды
|
||||
|
||||
```bash
|
||||
# Анализ кода
|
||||
flutter analyze
|
||||
|
||||
# Форматирование
|
||||
dart format .
|
||||
|
||||
# Очистка
|
||||
flutter clean
|
||||
|
||||
# Проверка зависимостей
|
||||
flutter pub outdated
|
||||
```
|
||||
|
||||
## Контакты
|
||||
|
||||
Для вопросов и предложений обращайтесь к команде разработки.
|
||||
51
client-mobile/README.md
Normal file
51
client-mobile/README.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# Messenger App
|
||||
|
||||
A Telegram-like mobile messenger application built with Flutter using Clean Architecture.
|
||||
|
||||
## Architecture
|
||||
|
||||
This project follows Clean Architecture principles with the following structure:
|
||||
|
||||
```
|
||||
lib/
|
||||
├── core/ # Core utilities, network, errors, theme
|
||||
├── features/ # Feature modules (auth, chat, profile, settings)
|
||||
│ └── [feature]/
|
||||
│ ├── data/ # Data layer (repositories, datasources)
|
||||
│ ├── domain/ # Domain layer (entities, usecases, repository interfaces)
|
||||
│ └── presentation/ # UI layer (bloc, pages, widgets)
|
||||
└── internal/ # App configuration, DI, routing
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
- **State Management**: flutter_bloc, bloc
|
||||
- **Architecture & DI**: get_it, injectable, freezed_annotation
|
||||
- **Network & Real-time**: dio, signalr_netcore
|
||||
- **Navigation**: auto_route
|
||||
- **Database**: isar, isar_flutter_libs
|
||||
|
||||
## Setup
|
||||
|
||||
1. Install Flutter dependencies:
|
||||
```bash
|
||||
flutter pub get
|
||||
```
|
||||
|
||||
2. Generate code:
|
||||
```bash
|
||||
dart run build_runner build --delete-conflicting-outputs
|
||||
```
|
||||
|
||||
3. Run the app:
|
||||
```bash
|
||||
flutter run
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Authentication (Login/Register)
|
||||
- Real-time Chat
|
||||
- Contacts
|
||||
- Profile Management
|
||||
- Settings
|
||||
8
client-mobile/analysis_options.yaml
Normal file
8
client-mobile/analysis_options.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
include: package:flutter_lints/flutter.yaml
|
||||
|
||||
linter:
|
||||
rules:
|
||||
prefer_const_constructors: true
|
||||
prefer_const_declarations: true
|
||||
avoid_print: false
|
||||
prefer_single_quotes: true
|
||||
7
client-mobile/android/.gitignore
vendored
Normal file
7
client-mobile/android/.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
gradle-wrapper.jar
|
||||
/.gradle
|
||||
/captures/
|
||||
/gradlew
|
||||
/gradlew.bat
|
||||
/local.properties
|
||||
GeneratedPluginRegistrant.java
|
||||
69
client-mobile/android/app/build.gradle
Normal file
69
client-mobile/android/app/build.gradle
Normal file
@@ -0,0 +1,69 @@
|
||||
plugins {
|
||||
id "com.android.application"
|
||||
id "kotlin-android"
|
||||
id "dev.flutter.flutter-gradle-plugin"
|
||||
}
|
||||
|
||||
def localProperties = new Properties()
|
||||
def localPropertiesFile = rootProject.file('local.properties')
|
||||
if (localPropertiesFile.exists()) {
|
||||
localPropertiesFile.withReader('UTF-8') { reader ->
|
||||
localProperties.load(reader)
|
||||
}
|
||||
}
|
||||
|
||||
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
|
||||
if (flutterVersionCode == null) {
|
||||
flutterVersionCode = '1'
|
||||
}
|
||||
|
||||
def flutterVersionName = localProperties.getProperty('flutter.versionName')
|
||||
if (flutterVersionName == null) {
|
||||
flutterVersionName = '1.0'
|
||||
}
|
||||
|
||||
android {
|
||||
namespace "com.example.messenger_app"
|
||||
compileSdkVersion 35
|
||||
ndkVersion flutter.ndkVersion
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_17
|
||||
targetCompatibility JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = '17'
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main.java.srcDirs += 'src/main/kotlin'
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.example.messenger_app"
|
||||
minSdkVersion flutter.minSdkVersion
|
||||
targetSdkVersion 35
|
||||
versionCode flutterVersionCode.toInteger()
|
||||
versionName flutterVersionName
|
||||
multiDexEnabled true
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
resources {
|
||||
excludes += '/META-INF/{AL2.0,LGPL2.1}'
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
signingConfig signingConfigs.debug
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flutter {
|
||||
source '../..'
|
||||
}
|
||||
|
||||
dependencies {}
|
||||
28
client-mobile/android/app/src/main/AndroidManifest.xml
Normal file
28
client-mobile/android/app/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<application
|
||||
android:label="Messenger"
|
||||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:hardwareAccelerated="true"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.NormalTheme"
|
||||
android:resource="@style/NormalTheme"
|
||||
/>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
</application>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
</manifest>
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.example.messenger_app
|
||||
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
|
||||
class MainActivity: FlutterActivity()
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@android:color/white" />
|
||||
</layer-list>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="#2481CC" />
|
||||
</shape>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="#2481CC" />
|
||||
</shape>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="#2481CC" />
|
||||
</shape>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="#2481CC" />
|
||||
</shape>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="#2481CC" />
|
||||
</shape>
|
||||
9
client-mobile/android/app/src/main/res/values/styles.xml
Normal file
9
client-mobile/android/app/src/main/res/values/styles.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
</style>
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
||||
25
client-mobile/android/build.gradle
Normal file
25
client-mobile/android/build.gradle
Normal file
@@ -0,0 +1,25 @@
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.buildDir = '../build'
|
||||
|
||||
subprojects {
|
||||
project.buildDir = "${rootProject.buildDir}/${project.name}"
|
||||
afterEvaluate { project ->
|
||||
if (project.hasProperty("android")) {
|
||||
project.android {
|
||||
if (namespace == null) {
|
||||
namespace project.group
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register("clean", Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
3
client-mobile/android/gradle.properties
Normal file
3
client-mobile/android/gradle.properties
Normal file
@@ -0,0 +1,3 @@
|
||||
org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
5
client-mobile/android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
client-mobile/android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip
|
||||
25
client-mobile/android/settings.gradle
Normal file
25
client-mobile/android/settings.gradle
Normal file
@@ -0,0 +1,25 @@
|
||||
pluginManagement {
|
||||
def flutterSdkPath = {
|
||||
def properties = new Properties()
|
||||
file("local.properties").withInputStream { properties.load(it) }
|
||||
def flutterSdkPath = properties.getProperty("flutter.sdk")
|
||||
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
|
||||
return flutterSdkPath
|
||||
}()
|
||||
|
||||
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
|
||||
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||
id "com.android.application" version "8.6.0" apply false
|
||||
id "org.jetbrains.kotlin.android" version "2.1.0" apply false
|
||||
}
|
||||
|
||||
include ":app"
|
||||
14
client-mobile/ios/Flutter/Generated.xcconfig
Normal file
14
client-mobile/ios/Flutter/Generated.xcconfig
Normal file
@@ -0,0 +1,14 @@
|
||||
// This is a generated file; do not edit or check into version control.
|
||||
FLUTTER_ROOT=C:\src\flutter
|
||||
FLUTTER_APPLICATION_PATH=E:\GIT\forkmessager\client-mobile
|
||||
COCOAPODS_PARALLEL_CODE_SIGN=true
|
||||
FLUTTER_TARGET=lib\main.dart
|
||||
FLUTTER_BUILD_DIR=build
|
||||
FLUTTER_BUILD_NAME=1.0.0
|
||||
FLUTTER_BUILD_NUMBER=1
|
||||
EXCLUDED_ARCHS[sdk=iphonesimulator*]=i386
|
||||
EXCLUDED_ARCHS[sdk=iphoneos*]=armv7
|
||||
DART_OBFUSCATION=false
|
||||
TRACK_WIDGET_CREATION=true
|
||||
TREE_SHAKE_ICONS=false
|
||||
PACKAGE_CONFIG=.dart_tool/package_config.json
|
||||
32
client-mobile/ios/Flutter/ephemeral/flutter_lldb_helper.py
Normal file
32
client-mobile/ios/Flutter/ephemeral/flutter_lldb_helper.py
Normal file
@@ -0,0 +1,32 @@
|
||||
#
|
||||
# Generated file, do not edit.
|
||||
#
|
||||
|
||||
import lldb
|
||||
|
||||
def handle_new_rx_page(frame: lldb.SBFrame, bp_loc, extra_args, intern_dict):
|
||||
"""Intercept NOTIFY_DEBUGGER_ABOUT_RX_PAGES and touch the pages."""
|
||||
base = frame.register["x0"].GetValueAsAddress()
|
||||
page_len = frame.register["x1"].GetValueAsUnsigned()
|
||||
|
||||
# Note: NOTIFY_DEBUGGER_ABOUT_RX_PAGES will check contents of the
|
||||
# first page to see if handled it correctly. This makes diagnosing
|
||||
# misconfiguration (e.g. missing breakpoint) easier.
|
||||
data = bytearray(page_len)
|
||||
data[0:8] = b'IHELPED!'
|
||||
|
||||
error = lldb.SBError()
|
||||
frame.GetThread().GetProcess().WriteMemory(base, data, error)
|
||||
if not error.Success():
|
||||
print(f'Failed to write into {base}[+{page_len}]', error)
|
||||
return
|
||||
|
||||
def __lldb_init_module(debugger: lldb.SBDebugger, _):
|
||||
target = debugger.GetDummyTarget()
|
||||
# Caveat: must use BreakpointCreateByRegEx here and not
|
||||
# BreakpointCreateByName. For some reasons callback function does not
|
||||
# get carried over from dummy target for the later.
|
||||
bp = target.BreakpointCreateByRegex("^NOTIFY_DEBUGGER_ABOUT_RX_PAGES$")
|
||||
bp.SetScriptCallbackFunction('{}.handle_new_rx_page'.format(__name__))
|
||||
bp.SetAutoContinue(True)
|
||||
print("-- LLDB integration loaded --")
|
||||
5
client-mobile/ios/Flutter/ephemeral/flutter_lldbinit
Normal file
5
client-mobile/ios/Flutter/ephemeral/flutter_lldbinit
Normal file
@@ -0,0 +1,5 @@
|
||||
#
|
||||
# Generated file, do not edit.
|
||||
#
|
||||
|
||||
command script import --relative-to-command-file flutter_lldb_helper.py
|
||||
13
client-mobile/ios/Flutter/flutter_export_environment.sh
Normal file
13
client-mobile/ios/Flutter/flutter_export_environment.sh
Normal file
@@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
# This is a generated file; do not edit or check into version control.
|
||||
export "FLUTTER_ROOT=C:\src\flutter"
|
||||
export "FLUTTER_APPLICATION_PATH=E:\GIT\forkmessager\client-mobile"
|
||||
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
|
||||
export "FLUTTER_TARGET=lib\main.dart"
|
||||
export "FLUTTER_BUILD_DIR=build"
|
||||
export "FLUTTER_BUILD_NAME=1.0.0"
|
||||
export "FLUTTER_BUILD_NUMBER=1"
|
||||
export "DART_OBFUSCATION=false"
|
||||
export "TRACK_WIDGET_CREATION=true"
|
||||
export "TREE_SHAKE_ICONS=false"
|
||||
export "PACKAGE_CONFIG=.dart_tool/package_config.json"
|
||||
13
client-mobile/ios/Runner/AppDelegate.swift
Normal file
13
client-mobile/ios/Runner/AppDelegate.swift
Normal file
@@ -0,0 +1,13 @@
|
||||
import UIKit
|
||||
import Flutter
|
||||
|
||||
@UIApplicationMain
|
||||
@objc class AppDelegate: FlutterAppDelegate {
|
||||
override func application(
|
||||
_ application: UIApplication,
|
||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||
) -> Bool {
|
||||
GeneratedPluginRegistrant.register(with: self)
|
||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||
}
|
||||
}
|
||||
19
client-mobile/ios/Runner/GeneratedPluginRegistrant.h
Normal file
19
client-mobile/ios/Runner/GeneratedPluginRegistrant.h
Normal file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// Generated file. Do not edit.
|
||||
//
|
||||
|
||||
// clang-format off
|
||||
|
||||
#ifndef GeneratedPluginRegistrant_h
|
||||
#define GeneratedPluginRegistrant_h
|
||||
|
||||
#import <Flutter/Flutter.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface GeneratedPluginRegistrant : NSObject
|
||||
+ (void)registerWithRegistry:(NSObject<FlutterPluginRegistry>*)registry;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
#endif /* GeneratedPluginRegistrant_h */
|
||||
28
client-mobile/ios/Runner/GeneratedPluginRegistrant.m
Normal file
28
client-mobile/ios/Runner/GeneratedPluginRegistrant.m
Normal file
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// Generated file. Do not edit.
|
||||
//
|
||||
|
||||
// clang-format off
|
||||
|
||||
#import "GeneratedPluginRegistrant.h"
|
||||
|
||||
#if __has_include(<isar_flutter_libs/IsarFlutterLibsPlugin.h>)
|
||||
#import <isar_flutter_libs/IsarFlutterLibsPlugin.h>
|
||||
#else
|
||||
@import isar_flutter_libs;
|
||||
#endif
|
||||
|
||||
#if __has_include(<shared_preferences_foundation/SharedPreferencesPlugin.h>)
|
||||
#import <shared_preferences_foundation/SharedPreferencesPlugin.h>
|
||||
#else
|
||||
@import shared_preferences_foundation;
|
||||
#endif
|
||||
|
||||
@implementation GeneratedPluginRegistrant
|
||||
|
||||
+ (void)registerWithRegistry:(NSObject<FlutterPluginRegistry>*)registry {
|
||||
[IsarFlutterLibsPlugin registerWithRegistrar:[registry registrarForPlugin:@"IsarFlutterLibsPlugin"]];
|
||||
[SharedPreferencesPlugin registerWithRegistrar:[registry registrarForPlugin:@"SharedPreferencesPlugin"]];
|
||||
}
|
||||
|
||||
@end
|
||||
4
client-mobile/l10n.yaml
Normal file
4
client-mobile/l10n.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
arb-dir: l10n
|
||||
template-arb-file: app_ru.arb
|
||||
output-localization-file: app_localizations.dart
|
||||
output-class: AppLocalizations
|
||||
51
client-mobile/l10n/app_en.arb
Normal file
51
client-mobile/l10n/app_en.arb
Normal file
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"@@locale": "en",
|
||||
"appTitle": "Messenger",
|
||||
"chats": "Chats",
|
||||
"contacts": "Contacts",
|
||||
"settings": "Settings",
|
||||
"login": "Login",
|
||||
"email": "Email",
|
||||
"password": "Password",
|
||||
"name": "Name",
|
||||
"loginButton": "Sign In",
|
||||
"register": "Register",
|
||||
"noAccount": "No account? Sign up",
|
||||
"logout": "Sign Out",
|
||||
"serverSettings": "Server Settings",
|
||||
"apiUrl": "API URL",
|
||||
"apiUrlHint": "https://api.example.com",
|
||||
"save": "Save",
|
||||
"serverConfig": "Server Configuration",
|
||||
"system": "System",
|
||||
"stories": "Stories",
|
||||
"chatsModule": "Chats",
|
||||
"messages": "Messages",
|
||||
"calls": "Calls",
|
||||
"klipy": "Klipy",
|
||||
"import": "Import",
|
||||
"federation": "Federation",
|
||||
"domainUrl": "Domain",
|
||||
"enableRegistration": "Registration Enabled",
|
||||
"enabled": "Enabled",
|
||||
"disabled": "Disabled",
|
||||
"language": "Language",
|
||||
"russian": "Русский",
|
||||
"english": "English",
|
||||
"notifications": "Notifications",
|
||||
"privacy": "Privacy",
|
||||
"soundsAndVibration": "Sounds & Vibration",
|
||||
"dataAndStorage": "Data & Storage",
|
||||
"aboutApp": "About App",
|
||||
"help": "Help",
|
||||
"version": "Version",
|
||||
"loading": "Loading...",
|
||||
"error": "Error",
|
||||
"retry": "Retry",
|
||||
"noChats": "No chats yet",
|
||||
"inDevelopment": "In development",
|
||||
"user": "User",
|
||||
"edit": "Edit",
|
||||
"serverConnectionError": "Server connection error",
|
||||
"settingsSaved": "Settings saved"
|
||||
}
|
||||
421
client-mobile/l10n/app_localizations.dart
Normal file
421
client-mobile/l10n/app_localizations.dart
Normal file
@@ -0,0 +1,421 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:intl/intl.dart' as intl;
|
||||
|
||||
import 'app_localizations_en.dart';
|
||||
import 'app_localizations_ru.dart';
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
|
||||
/// Callers can lookup localized strings with an instance of AppLocalizations
|
||||
/// returned by `AppLocalizations.of(context)`.
|
||||
///
|
||||
/// Applications need to include `AppLocalizations.delegate()` in their app's
|
||||
/// `localizationDelegates` list, and the locales they support in the app's
|
||||
/// `supportedLocales` list. For example:
|
||||
///
|
||||
/// ```dart
|
||||
/// import 'l10n/app_localizations.dart';
|
||||
///
|
||||
/// return MaterialApp(
|
||||
/// localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
/// supportedLocales: AppLocalizations.supportedLocales,
|
||||
/// home: MyApplicationHome(),
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// ## Update pubspec.yaml
|
||||
///
|
||||
/// Please make sure to update your pubspec.yaml to include the following
|
||||
/// packages:
|
||||
///
|
||||
/// ```yaml
|
||||
/// dependencies:
|
||||
/// # Internationalization support.
|
||||
/// flutter_localizations:
|
||||
/// sdk: flutter
|
||||
/// intl: any # Use the pinned version from flutter_localizations
|
||||
///
|
||||
/// # Rest of dependencies
|
||||
/// ```
|
||||
///
|
||||
/// ## iOS Applications
|
||||
///
|
||||
/// iOS applications define key application metadata, including supported
|
||||
/// locales, in an Info.plist file that is built into the application bundle.
|
||||
/// To configure the locales supported by your app, you’ll need to edit this
|
||||
/// file.
|
||||
///
|
||||
/// First, open your project’s ios/Runner.xcworkspace Xcode workspace file.
|
||||
/// Then, in the Project Navigator, open the Info.plist file under the Runner
|
||||
/// project’s Runner folder.
|
||||
///
|
||||
/// Next, select the Information Property List item, select Add Item from the
|
||||
/// Editor menu, then select Localizations from the pop-up menu.
|
||||
///
|
||||
/// Select and expand the newly-created Localizations item then, for each
|
||||
/// locale your application supports, add a new item and select the locale
|
||||
/// you wish to add from the pop-up menu in the Value field. This list should
|
||||
/// be consistent with the languages listed in the AppLocalizations.supportedLocales
|
||||
/// property.
|
||||
abstract class AppLocalizations {
|
||||
AppLocalizations(String locale)
|
||||
: localeName = intl.Intl.canonicalizedLocale(locale.toString());
|
||||
|
||||
final String localeName;
|
||||
|
||||
static AppLocalizations? of(BuildContext context) {
|
||||
return Localizations.of<AppLocalizations>(context, AppLocalizations);
|
||||
}
|
||||
|
||||
static const LocalizationsDelegate<AppLocalizations> delegate =
|
||||
_AppLocalizationsDelegate();
|
||||
|
||||
/// A list of this localizations delegate along with the default localizations
|
||||
/// delegates.
|
||||
///
|
||||
/// Returns a list of localizations delegates containing this delegate along with
|
||||
/// GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate,
|
||||
/// and GlobalWidgetsLocalizations.delegate.
|
||||
///
|
||||
/// Additional delegates can be added by appending to this list in
|
||||
/// MaterialApp. This list does not have to be used at all if a custom list
|
||||
/// of delegates is preferred or required.
|
||||
static const List<LocalizationsDelegate<dynamic>> localizationsDelegates =
|
||||
<LocalizationsDelegate<dynamic>>[
|
||||
delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
];
|
||||
|
||||
/// A list of this localizations delegate's supported locales.
|
||||
static const List<Locale> supportedLocales = <Locale>[
|
||||
Locale('en'),
|
||||
Locale('ru')
|
||||
];
|
||||
|
||||
/// No description provided for @appTitle.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Мессенджер'**
|
||||
String get appTitle;
|
||||
|
||||
/// No description provided for @chats.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Чаты'**
|
||||
String get chats;
|
||||
|
||||
/// No description provided for @contacts.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Контакты'**
|
||||
String get contacts;
|
||||
|
||||
/// No description provided for @settings.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Настройки'**
|
||||
String get settings;
|
||||
|
||||
/// No description provided for @login.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Вход'**
|
||||
String get login;
|
||||
|
||||
/// No description provided for @email.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Email'**
|
||||
String get email;
|
||||
|
||||
/// No description provided for @password.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Пароль'**
|
||||
String get password;
|
||||
|
||||
/// No description provided for @name.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Имя'**
|
||||
String get name;
|
||||
|
||||
/// No description provided for @loginButton.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Войти'**
|
||||
String get loginButton;
|
||||
|
||||
/// No description provided for @register.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Зарегистрироваться'**
|
||||
String get register;
|
||||
|
||||
/// No description provided for @noAccount.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Нет аккаунта? Зарегистрироваться'**
|
||||
String get noAccount;
|
||||
|
||||
/// No description provided for @logout.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Выйти из аккаунта'**
|
||||
String get logout;
|
||||
|
||||
/// No description provided for @serverSettings.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Настройки сервера'**
|
||||
String get serverSettings;
|
||||
|
||||
/// No description provided for @apiUrl.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Адрес API'**
|
||||
String get apiUrl;
|
||||
|
||||
/// No description provided for @apiUrlHint.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'https://api.example.com'**
|
||||
String get apiUrlHint;
|
||||
|
||||
/// No description provided for @save.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Сохранить'**
|
||||
String get save;
|
||||
|
||||
/// No description provided for @serverConfig.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Конфигурация сервера'**
|
||||
String get serverConfig;
|
||||
|
||||
/// No description provided for @system.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Система'**
|
||||
String get system;
|
||||
|
||||
/// No description provided for @stories.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Истории'**
|
||||
String get stories;
|
||||
|
||||
/// No description provided for @chatsModule.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Чаты'**
|
||||
String get chatsModule;
|
||||
|
||||
/// No description provided for @messages.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Сообщения'**
|
||||
String get messages;
|
||||
|
||||
/// No description provided for @calls.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Звонки'**
|
||||
String get calls;
|
||||
|
||||
/// No description provided for @klipy.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Клипы'**
|
||||
String get klipy;
|
||||
|
||||
/// No description provided for @import.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Импорт'**
|
||||
String get import;
|
||||
|
||||
/// No description provided for @federation.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Федерация'**
|
||||
String get federation;
|
||||
|
||||
/// No description provided for @domainUrl.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Домен'**
|
||||
String get domainUrl;
|
||||
|
||||
/// No description provided for @enableRegistration.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Регистрация включена'**
|
||||
String get enableRegistration;
|
||||
|
||||
/// No description provided for @enabled.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Включено'**
|
||||
String get enabled;
|
||||
|
||||
/// No description provided for @disabled.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Отключено'**
|
||||
String get disabled;
|
||||
|
||||
/// No description provided for @language.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Язык'**
|
||||
String get language;
|
||||
|
||||
/// No description provided for @russian.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Русский'**
|
||||
String get russian;
|
||||
|
||||
/// No description provided for @english.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'English'**
|
||||
String get english;
|
||||
|
||||
/// No description provided for @notifications.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Уведомления'**
|
||||
String get notifications;
|
||||
|
||||
/// No description provided for @privacy.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Конфиденциальность'**
|
||||
String get privacy;
|
||||
|
||||
/// No description provided for @soundsAndVibration.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Звуки и вибрация'**
|
||||
String get soundsAndVibration;
|
||||
|
||||
/// No description provided for @dataAndStorage.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Данные и память'**
|
||||
String get dataAndStorage;
|
||||
|
||||
/// No description provided for @aboutApp.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'О приложении'**
|
||||
String get aboutApp;
|
||||
|
||||
/// No description provided for @help.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Помощь'**
|
||||
String get help;
|
||||
|
||||
/// No description provided for @version.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Версия'**
|
||||
String get version;
|
||||
|
||||
/// No description provided for @loading.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Загрузка...'**
|
||||
String get loading;
|
||||
|
||||
/// No description provided for @error.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Ошибка'**
|
||||
String get error;
|
||||
|
||||
/// No description provided for @retry.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Повторить'**
|
||||
String get retry;
|
||||
|
||||
/// No description provided for @noChats.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'У вас пока нет чатов'**
|
||||
String get noChats;
|
||||
|
||||
/// No description provided for @inDevelopment.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Функция в разработке'**
|
||||
String get inDevelopment;
|
||||
|
||||
/// No description provided for @user.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Пользователь'**
|
||||
String get user;
|
||||
|
||||
/// No description provided for @edit.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Редактировать'**
|
||||
String get edit;
|
||||
|
||||
/// No description provided for @serverConnectionError.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Ошибка подключения к серверу'**
|
||||
String get serverConnectionError;
|
||||
|
||||
/// No description provided for @settingsSaved.
|
||||
///
|
||||
/// In ru, this message translates to:
|
||||
/// **'Настройки сохранены'**
|
||||
String get settingsSaved;
|
||||
}
|
||||
|
||||
class _AppLocalizationsDelegate
|
||||
extends LocalizationsDelegate<AppLocalizations> {
|
||||
const _AppLocalizationsDelegate();
|
||||
|
||||
@override
|
||||
Future<AppLocalizations> load(Locale locale) {
|
||||
return SynchronousFuture<AppLocalizations>(lookupAppLocalizations(locale));
|
||||
}
|
||||
|
||||
@override
|
||||
bool isSupported(Locale locale) =>
|
||||
<String>['en', 'ru'].contains(locale.languageCode);
|
||||
|
||||
@override
|
||||
bool shouldReload(_AppLocalizationsDelegate old) => false;
|
||||
}
|
||||
|
||||
AppLocalizations lookupAppLocalizations(Locale locale) {
|
||||
// Lookup logic when only language code is specified.
|
||||
switch (locale.languageCode) {
|
||||
case 'en':
|
||||
return AppLocalizationsEn();
|
||||
case 'ru':
|
||||
return AppLocalizationsRu();
|
||||
}
|
||||
|
||||
throw FlutterError(
|
||||
'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely '
|
||||
'an issue with the localizations generation tool. Please file an issue '
|
||||
'on GitHub with a reproducible sample app and the gen-l10n configuration '
|
||||
'that was used.');
|
||||
}
|
||||
154
client-mobile/l10n/app_localizations_en.dart
Normal file
154
client-mobile/l10n/app_localizations_en.dart
Normal file
@@ -0,0 +1,154 @@
|
||||
// ignore: unused_import
|
||||
import 'package:intl/intl.dart' as intl;
|
||||
import 'app_localizations.dart';
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
|
||||
/// The translations for English (`en`).
|
||||
class AppLocalizationsEn extends AppLocalizations {
|
||||
AppLocalizationsEn([String locale = 'en']) : super(locale);
|
||||
|
||||
@override
|
||||
String get appTitle => 'Messenger';
|
||||
|
||||
@override
|
||||
String get chats => 'Chats';
|
||||
|
||||
@override
|
||||
String get contacts => 'Contacts';
|
||||
|
||||
@override
|
||||
String get settings => 'Settings';
|
||||
|
||||
@override
|
||||
String get login => 'Login';
|
||||
|
||||
@override
|
||||
String get email => 'Email';
|
||||
|
||||
@override
|
||||
String get password => 'Password';
|
||||
|
||||
@override
|
||||
String get name => 'Name';
|
||||
|
||||
@override
|
||||
String get loginButton => 'Sign In';
|
||||
|
||||
@override
|
||||
String get register => 'Register';
|
||||
|
||||
@override
|
||||
String get noAccount => 'No account? Sign up';
|
||||
|
||||
@override
|
||||
String get logout => 'Sign Out';
|
||||
|
||||
@override
|
||||
String get serverSettings => 'Server Settings';
|
||||
|
||||
@override
|
||||
String get apiUrl => 'API URL';
|
||||
|
||||
@override
|
||||
String get apiUrlHint => 'https://api.example.com';
|
||||
|
||||
@override
|
||||
String get save => 'Save';
|
||||
|
||||
@override
|
||||
String get serverConfig => 'Server Configuration';
|
||||
|
||||
@override
|
||||
String get system => 'System';
|
||||
|
||||
@override
|
||||
String get stories => 'Stories';
|
||||
|
||||
@override
|
||||
String get chatsModule => 'Chats';
|
||||
|
||||
@override
|
||||
String get messages => 'Messages';
|
||||
|
||||
@override
|
||||
String get calls => 'Calls';
|
||||
|
||||
@override
|
||||
String get klipy => 'Klipy';
|
||||
|
||||
@override
|
||||
String get import => 'Import';
|
||||
|
||||
@override
|
||||
String get federation => 'Federation';
|
||||
|
||||
@override
|
||||
String get domainUrl => 'Domain';
|
||||
|
||||
@override
|
||||
String get enableRegistration => 'Registration Enabled';
|
||||
|
||||
@override
|
||||
String get enabled => 'Enabled';
|
||||
|
||||
@override
|
||||
String get disabled => 'Disabled';
|
||||
|
||||
@override
|
||||
String get language => 'Language';
|
||||
|
||||
@override
|
||||
String get russian => 'Русский';
|
||||
|
||||
@override
|
||||
String get english => 'English';
|
||||
|
||||
@override
|
||||
String get notifications => 'Notifications';
|
||||
|
||||
@override
|
||||
String get privacy => 'Privacy';
|
||||
|
||||
@override
|
||||
String get soundsAndVibration => 'Sounds & Vibration';
|
||||
|
||||
@override
|
||||
String get dataAndStorage => 'Data & Storage';
|
||||
|
||||
@override
|
||||
String get aboutApp => 'About App';
|
||||
|
||||
@override
|
||||
String get help => 'Help';
|
||||
|
||||
@override
|
||||
String get version => 'Version';
|
||||
|
||||
@override
|
||||
String get loading => 'Loading...';
|
||||
|
||||
@override
|
||||
String get error => 'Error';
|
||||
|
||||
@override
|
||||
String get retry => 'Retry';
|
||||
|
||||
@override
|
||||
String get noChats => 'No chats yet';
|
||||
|
||||
@override
|
||||
String get inDevelopment => 'In development';
|
||||
|
||||
@override
|
||||
String get user => 'User';
|
||||
|
||||
@override
|
||||
String get edit => 'Edit';
|
||||
|
||||
@override
|
||||
String get serverConnectionError => 'Server connection error';
|
||||
|
||||
@override
|
||||
String get settingsSaved => 'Settings saved';
|
||||
}
|
||||
154
client-mobile/l10n/app_localizations_ru.dart
Normal file
154
client-mobile/l10n/app_localizations_ru.dart
Normal file
@@ -0,0 +1,154 @@
|
||||
// ignore: unused_import
|
||||
import 'package:intl/intl.dart' as intl;
|
||||
import 'app_localizations.dart';
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
|
||||
/// The translations for Russian (`ru`).
|
||||
class AppLocalizationsRu extends AppLocalizations {
|
||||
AppLocalizationsRu([String locale = 'ru']) : super(locale);
|
||||
|
||||
@override
|
||||
String get appTitle => 'Мессенджер';
|
||||
|
||||
@override
|
||||
String get chats => 'Чаты';
|
||||
|
||||
@override
|
||||
String get contacts => 'Контакты';
|
||||
|
||||
@override
|
||||
String get settings => 'Настройки';
|
||||
|
||||
@override
|
||||
String get login => 'Вход';
|
||||
|
||||
@override
|
||||
String get email => 'Email';
|
||||
|
||||
@override
|
||||
String get password => 'Пароль';
|
||||
|
||||
@override
|
||||
String get name => 'Имя';
|
||||
|
||||
@override
|
||||
String get loginButton => 'Войти';
|
||||
|
||||
@override
|
||||
String get register => 'Зарегистрироваться';
|
||||
|
||||
@override
|
||||
String get noAccount => 'Нет аккаунта? Зарегистрироваться';
|
||||
|
||||
@override
|
||||
String get logout => 'Выйти из аккаунта';
|
||||
|
||||
@override
|
||||
String get serverSettings => 'Настройки сервера';
|
||||
|
||||
@override
|
||||
String get apiUrl => 'Адрес API';
|
||||
|
||||
@override
|
||||
String get apiUrlHint => 'https://api.example.com';
|
||||
|
||||
@override
|
||||
String get save => 'Сохранить';
|
||||
|
||||
@override
|
||||
String get serverConfig => 'Конфигурация сервера';
|
||||
|
||||
@override
|
||||
String get system => 'Система';
|
||||
|
||||
@override
|
||||
String get stories => 'Истории';
|
||||
|
||||
@override
|
||||
String get chatsModule => 'Чаты';
|
||||
|
||||
@override
|
||||
String get messages => 'Сообщения';
|
||||
|
||||
@override
|
||||
String get calls => 'Звонки';
|
||||
|
||||
@override
|
||||
String get klipy => 'Клипы';
|
||||
|
||||
@override
|
||||
String get import => 'Импорт';
|
||||
|
||||
@override
|
||||
String get federation => 'Федерация';
|
||||
|
||||
@override
|
||||
String get domainUrl => 'Домен';
|
||||
|
||||
@override
|
||||
String get enableRegistration => 'Регистрация включена';
|
||||
|
||||
@override
|
||||
String get enabled => 'Включено';
|
||||
|
||||
@override
|
||||
String get disabled => 'Отключено';
|
||||
|
||||
@override
|
||||
String get language => 'Язык';
|
||||
|
||||
@override
|
||||
String get russian => 'Русский';
|
||||
|
||||
@override
|
||||
String get english => 'English';
|
||||
|
||||
@override
|
||||
String get notifications => 'Уведомления';
|
||||
|
||||
@override
|
||||
String get privacy => 'Конфиденциальность';
|
||||
|
||||
@override
|
||||
String get soundsAndVibration => 'Звуки и вибрация';
|
||||
|
||||
@override
|
||||
String get dataAndStorage => 'Данные и память';
|
||||
|
||||
@override
|
||||
String get aboutApp => 'О приложении';
|
||||
|
||||
@override
|
||||
String get help => 'Помощь';
|
||||
|
||||
@override
|
||||
String get version => 'Версия';
|
||||
|
||||
@override
|
||||
String get loading => 'Загрузка...';
|
||||
|
||||
@override
|
||||
String get error => 'Ошибка';
|
||||
|
||||
@override
|
||||
String get retry => 'Повторить';
|
||||
|
||||
@override
|
||||
String get noChats => 'У вас пока нет чатов';
|
||||
|
||||
@override
|
||||
String get inDevelopment => 'Функция в разработке';
|
||||
|
||||
@override
|
||||
String get user => 'Пользователь';
|
||||
|
||||
@override
|
||||
String get edit => 'Редактировать';
|
||||
|
||||
@override
|
||||
String get serverConnectionError => 'Ошибка подключения к серверу';
|
||||
|
||||
@override
|
||||
String get settingsSaved => 'Настройки сохранены';
|
||||
}
|
||||
51
client-mobile/l10n/app_ru.arb
Normal file
51
client-mobile/l10n/app_ru.arb
Normal file
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"@@locale": "ru",
|
||||
"appTitle": "Мессенджер",
|
||||
"chats": "Чаты",
|
||||
"contacts": "Контакты",
|
||||
"settings": "Настройки",
|
||||
"login": "Вход",
|
||||
"email": "Email",
|
||||
"password": "Пароль",
|
||||
"name": "Имя",
|
||||
"loginButton": "Войти",
|
||||
"register": "Зарегистрироваться",
|
||||
"noAccount": "Нет аккаунта? Зарегистрироваться",
|
||||
"logout": "Выйти из аккаунта",
|
||||
"serverSettings": "Настройки сервера",
|
||||
"apiUrl": "Адрес API",
|
||||
"apiUrlHint": "https://api.example.com",
|
||||
"save": "Сохранить",
|
||||
"serverConfig": "Конфигурация сервера",
|
||||
"system": "Система",
|
||||
"stories": "Истории",
|
||||
"chatsModule": "Чаты",
|
||||
"messages": "Сообщения",
|
||||
"calls": "Звонки",
|
||||
"klipy": "Клипы",
|
||||
"import": "Импорт",
|
||||
"federation": "Федерация",
|
||||
"domainUrl": "Домен",
|
||||
"enableRegistration": "Регистрация включена",
|
||||
"enabled": "Включено",
|
||||
"disabled": "Отключено",
|
||||
"language": "Язык",
|
||||
"russian": "Русский",
|
||||
"english": "English",
|
||||
"notifications": "Уведомления",
|
||||
"privacy": "Конфиденциальность",
|
||||
"soundsAndVibration": "Звуки и вибрация",
|
||||
"dataAndStorage": "Данные и память",
|
||||
"aboutApp": "О приложении",
|
||||
"help": "Помощь",
|
||||
"version": "Версия",
|
||||
"loading": "Загрузка...",
|
||||
"error": "Ошибка",
|
||||
"retry": "Повторить",
|
||||
"noChats": "У вас пока нет чатов",
|
||||
"inDevelopment": "Функция в разработке",
|
||||
"user": "Пользователь",
|
||||
"edit": "Редактировать",
|
||||
"serverConnectionError": "Ошибка подключения к серверу",
|
||||
"settingsSaved": "Настройки сохранены"
|
||||
}
|
||||
56
client-mobile/lib/app.dart
Normal file
56
client-mobile/lib/app.dart
Normal file
@@ -0,0 +1,56 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'core/theme/app_theme.dart';
|
||||
import 'features/auth/presentation/bloc/auth_bloc.dart';
|
||||
import 'features/auth/presentation/bloc/auth_event.dart';
|
||||
import 'features/chat/presentation/bloc/chat_bloc.dart';
|
||||
import 'features/chat/presentation/bloc/chat_event.dart';
|
||||
import 'features/settings/presentation/bloc/settings_bloc.dart';
|
||||
import 'features/settings/presentation/bloc/settings_event.dart';
|
||||
import 'features/settings/presentation/bloc/settings_state.dart';
|
||||
import 'features/settings/presentation/l10n/app_localizations.dart';
|
||||
import 'internal/di/injection_container.dart' as di;
|
||||
import 'internal/router/main_screen.dart';
|
||||
|
||||
class MessengerApp extends StatelessWidget {
|
||||
const MessengerApp({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider<SettingsBloc>(
|
||||
create: (_) => di.sl<SettingsBloc>()..add(const SettingsEvent.started()),
|
||||
),
|
||||
BlocProvider<AuthBloc>(
|
||||
create: (_) => di.sl<AuthBloc>()..add(const AuthEvent.authChecked()),
|
||||
),
|
||||
BlocProvider<ChatBloc>(
|
||||
create: (_) => di.sl<ChatBloc>()..add(const ChatEvent.started()),
|
||||
),
|
||||
],
|
||||
child: BlocBuilder<SettingsBloc, SettingsState>(
|
||||
builder: (context, settingsState) {
|
||||
final languageCode = settingsState is SettingsLoaded
|
||||
? settingsState.languageCode
|
||||
: 'ru';
|
||||
|
||||
return MaterialApp(
|
||||
title: 'Messenger',
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: AppTheme.lightTheme,
|
||||
darkTheme: AppTheme.darkTheme,
|
||||
themeMode: ThemeMode.system,
|
||||
locale: Locale(languageCode),
|
||||
supportedLocales: const [
|
||||
Locale('ru'),
|
||||
Locale('en'),
|
||||
],
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
home: const MainScreen(),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
25
client-mobile/lib/core/constants/app_constants.dart
Normal file
25
client-mobile/lib/core/constants/app_constants.dart
Normal file
@@ -0,0 +1,25 @@
|
||||
class AppConstants {
|
||||
AppConstants._();
|
||||
|
||||
// API
|
||||
static const String apiBaseUrl = 'https://api.messenger.app';
|
||||
static const int apiTimeout = 30;
|
||||
|
||||
// Storage
|
||||
static const String sharedPrefsName = 'messenger_prefs';
|
||||
static const String tokenKey = 'auth_token';
|
||||
static const String refreshTokenKey = 'refresh_token';
|
||||
static const String userIdKey = 'user_id';
|
||||
|
||||
// Pagination
|
||||
static const int pageSize = 20;
|
||||
static const int defaultPageSize = 50;
|
||||
|
||||
// Chat
|
||||
static const int maxMessageLength = 4096;
|
||||
static const int typingIndicatorTimeout = 3000;
|
||||
|
||||
// Media
|
||||
static const int maxImageSize = 10 * 1024 * 1024; // 10MB
|
||||
static const int maxVideoSize = 100 * 1024 * 1024; // 100MB
|
||||
}
|
||||
9
client-mobile/lib/core/constants/storage_keys.dart
Normal file
9
client-mobile/lib/core/constants/storage_keys.dart
Normal file
@@ -0,0 +1,9 @@
|
||||
class StorageKeys {
|
||||
StorageKeys._();
|
||||
|
||||
static const String apiUrl = 'api_url';
|
||||
static const String languageCode = 'language_code';
|
||||
static const String serverConfig = 'server_config';
|
||||
static const String authToken = 'auth_token';
|
||||
static const String refreshToken = 'refresh_token';
|
||||
}
|
||||
15
client-mobile/lib/core/errors/errors.dart
Normal file
15
client-mobile/lib/core/errors/errors.dart
Normal file
@@ -0,0 +1,15 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'errors.freezed.dart';
|
||||
|
||||
@freezed
|
||||
class AppError with _$AppError {
|
||||
const factory AppError.unknown({String? message}) = UnknownError;
|
||||
const factory AppError.network({String? message}) = NetworkError;
|
||||
const factory AppError.unauthorized({String? message}) = UnauthorizedError;
|
||||
const factory AppError.forbidden({String? message}) = ForbiddenError;
|
||||
const factory AppError.notFound({String? message}) = NotFoundError;
|
||||
const factory AppError.server({int? statusCode, String? message}) = ServerError;
|
||||
const factory AppError.database({String? message}) = DatabaseError;
|
||||
const factory AppError.validation({Map<String, String>? fieldErrors}) = ValidationError;
|
||||
}
|
||||
1488
client-mobile/lib/core/errors/errors.freezed.dart
Normal file
1488
client-mobile/lib/core/errors/errors.freezed.dart
Normal file
File diff suppressed because it is too large
Load Diff
30
client-mobile/lib/core/errors/result.dart
Normal file
30
client-mobile/lib/core/errors/result.dart
Normal file
@@ -0,0 +1,30 @@
|
||||
import 'errors.dart';
|
||||
|
||||
/// A generic class for handling success/failure results
|
||||
class Result<T> {
|
||||
final T? data;
|
||||
final AppError? error;
|
||||
|
||||
const Result.success(this.data) : error = null;
|
||||
const Result.failure(this.error) : data = null;
|
||||
|
||||
bool get isSuccess => error == null;
|
||||
bool get isFailure => error != null;
|
||||
|
||||
R when<R>({
|
||||
required R Function(T data) onSuccess,
|
||||
required R Function(AppError error) onFailure,
|
||||
}) {
|
||||
if (isSuccess) {
|
||||
return onSuccess(data as T);
|
||||
}
|
||||
return onFailure(error!);
|
||||
}
|
||||
|
||||
T getOrThrow() {
|
||||
if (isFailure) {
|
||||
throw error!;
|
||||
}
|
||||
return data as T;
|
||||
}
|
||||
}
|
||||
135
client-mobile/lib/core/network/api_client.dart
Normal file
135
client-mobile/lib/core/network/api_client.dart
Normal file
@@ -0,0 +1,135 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import '../errors/errors.dart';
|
||||
import '../errors/result.dart';
|
||||
|
||||
class ApiClient {
|
||||
final Dio _dio;
|
||||
|
||||
ApiClient(this._dio);
|
||||
|
||||
Future<Result<T>> get<T>(
|
||||
String path, {
|
||||
Map<String, dynamic>? queryParameters,
|
||||
Options? options,
|
||||
}) async {
|
||||
try {
|
||||
final response = await _dio.get<T>(
|
||||
path,
|
||||
queryParameters: queryParameters,
|
||||
options: options,
|
||||
);
|
||||
return Result.success(response.data as T);
|
||||
} on DioException catch (e) {
|
||||
return Result.failure(_handleDioError(e));
|
||||
} catch (e) {
|
||||
return Result.failure(const AppError.unknown(message: 'Unknown error occurred'));
|
||||
}
|
||||
}
|
||||
|
||||
Future<Result<T>> post<T>(
|
||||
String path, {
|
||||
dynamic data,
|
||||
Map<String, dynamic>? queryParameters,
|
||||
Options? options,
|
||||
}) async {
|
||||
try {
|
||||
final response = await _dio.post<T>(
|
||||
path,
|
||||
data: data,
|
||||
queryParameters: queryParameters,
|
||||
options: options,
|
||||
);
|
||||
return Result.success(response.data as T);
|
||||
} on DioException catch (e) {
|
||||
return Result.failure(_handleDioError(e));
|
||||
} catch (e) {
|
||||
return Result.failure(const AppError.unknown(message: 'Unknown error occurred'));
|
||||
}
|
||||
}
|
||||
|
||||
Future<Result<T>> put<T>(
|
||||
String path, {
|
||||
dynamic data,
|
||||
Map<String, dynamic>? queryParameters,
|
||||
Options? options,
|
||||
}) async {
|
||||
try {
|
||||
final response = await _dio.put<T>(
|
||||
path,
|
||||
data: data,
|
||||
queryParameters: queryParameters,
|
||||
options: options,
|
||||
);
|
||||
return Result.success(response.data as T);
|
||||
} on DioException catch (e) {
|
||||
return Result.failure(_handleDioError(e));
|
||||
} catch (e) {
|
||||
return Result.failure(const AppError.unknown(message: 'Unknown error occurred'));
|
||||
}
|
||||
}
|
||||
|
||||
Future<Result<T>> delete<T>(
|
||||
String path, {
|
||||
dynamic data,
|
||||
Map<String, dynamic>? queryParameters,
|
||||
Options? options,
|
||||
}) async {
|
||||
try {
|
||||
final response = await _dio.delete<T>(
|
||||
path,
|
||||
data: data,
|
||||
queryParameters: queryParameters,
|
||||
options: options,
|
||||
);
|
||||
return Result.success(response.data as T);
|
||||
} on DioException catch (e) {
|
||||
return Result.failure(_handleDioError(e));
|
||||
} catch (e) {
|
||||
return Result.failure(const AppError.unknown(message: 'Unknown error occurred'));
|
||||
}
|
||||
}
|
||||
|
||||
AppError _handleDioError(DioException error) {
|
||||
switch (error.type) {
|
||||
case DioExceptionType.connectionTimeout:
|
||||
case DioExceptionType.sendTimeout:
|
||||
case DioExceptionType.receiveTimeout:
|
||||
return const AppError.network(message: 'Connection timeout');
|
||||
case DioExceptionType.connectionError:
|
||||
return const AppError.network(message: 'No internet connection');
|
||||
case DioExceptionType.badResponse:
|
||||
final statusCode = error.response?.statusCode;
|
||||
switch (statusCode) {
|
||||
case 401:
|
||||
return const AppError.unauthorized();
|
||||
case 403:
|
||||
return const AppError.forbidden();
|
||||
case 404:
|
||||
return const AppError.notFound();
|
||||
case 422:
|
||||
return AppError.validation(fieldErrors: _extractValidationErrors(error.response?.data));
|
||||
case int s when s >= 500:
|
||||
return AppError.server(statusCode: statusCode, message: 'Server error');
|
||||
default:
|
||||
return AppError.server(statusCode: statusCode, message: 'Request failed');
|
||||
}
|
||||
case DioExceptionType.cancel:
|
||||
return const AppError.unknown(message: 'Request cancelled');
|
||||
default:
|
||||
return const AppError.unknown();
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, String>? _extractValidationErrors(dynamic data) {
|
||||
if (data is Map<String, dynamic> && data.containsKey('errors')) {
|
||||
final errors = data['errors'] as Map<String, dynamic>;
|
||||
return errors.map((key, value) {
|
||||
if (value is List && value.isNotEmpty) {
|
||||
return MapEntry(key, value.first.toString());
|
||||
}
|
||||
return MapEntry(key, 'Invalid');
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
134
client-mobile/lib/core/theme/app_theme.dart
Normal file
134
client-mobile/lib/core/theme/app_theme.dart
Normal file
@@ -0,0 +1,134 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class AppTheme {
|
||||
AppTheme._();
|
||||
|
||||
static const _primaryColor = Color(0xFF2481CC);
|
||||
static const _primaryContainerColor = Color(0xFFD3E4FD);
|
||||
static const _secondaryColor = Color(0xFF5F6AC4);
|
||||
static const _tertiaryColor = Color(0xFFFFD700);
|
||||
|
||||
static const _lightSurfaceColor = Color(0xFFFFFBFE);
|
||||
static const _darkSurfaceColor = Color(0xFF1C1B1F);
|
||||
|
||||
static ThemeData get lightTheme {
|
||||
return ThemeData(
|
||||
useMaterial3: true,
|
||||
brightness: Brightness.light,
|
||||
colorScheme: const ColorScheme.light(
|
||||
primary: _primaryColor,
|
||||
primaryContainer: _primaryContainerColor,
|
||||
secondary: _secondaryColor,
|
||||
tertiary: _tertiaryColor,
|
||||
surface: _lightSurfaceColor,
|
||||
onPrimary: Colors.white,
|
||||
onSecondary: Colors.white,
|
||||
onSurface: Colors.black87,
|
||||
error: Color(0xFFBA1A1A),
|
||||
),
|
||||
appBarTheme: const AppBarTheme(
|
||||
centerTitle: true,
|
||||
elevation: 0,
|
||||
backgroundColor: _primaryColor,
|
||||
foregroundColor: Colors.white,
|
||||
systemOverlayStyle: SystemUiOverlayStyle.light,
|
||||
),
|
||||
bottomNavigationBarTheme: const BottomNavigationBarThemeData(
|
||||
type: BottomNavigationBarType.fixed,
|
||||
backgroundColor: Colors.white,
|
||||
selectedItemColor: _primaryColor,
|
||||
unselectedItemColor: Colors.grey,
|
||||
elevation: 8,
|
||||
),
|
||||
cardTheme: CardThemeData(
|
||||
elevation: 2,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
),
|
||||
inputDecorationTheme: InputDecorationTheme(
|
||||
filled: true,
|
||||
fillColor: Colors.grey[100],
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 12,
|
||||
),
|
||||
),
|
||||
elevatedButtonTheme: ElevatedButtonThemeData(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: _primaryColor,
|
||||
foregroundColor: Colors.white,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static ThemeData get darkTheme {
|
||||
return ThemeData(
|
||||
useMaterial3: true,
|
||||
brightness: Brightness.dark,
|
||||
colorScheme: const ColorScheme.dark(
|
||||
primary: _primaryColor,
|
||||
primaryContainer: _primaryContainerColor,
|
||||
secondary: _secondaryColor,
|
||||
tertiary: _tertiaryColor,
|
||||
surface: _darkSurfaceColor,
|
||||
onPrimary: Colors.white,
|
||||
onSecondary: Colors.white,
|
||||
onSurface: const Color(0xFFE6E1E5),
|
||||
error: Color(0xFFFFB4AB),
|
||||
),
|
||||
appBarTheme: const AppBarTheme(
|
||||
centerTitle: true,
|
||||
elevation: 0,
|
||||
backgroundColor: Color(0xFF1F1F1F),
|
||||
foregroundColor: Colors.white,
|
||||
systemOverlayStyle: SystemUiOverlayStyle.light,
|
||||
),
|
||||
bottomNavigationBarTheme: const BottomNavigationBarThemeData(
|
||||
type: BottomNavigationBarType.fixed,
|
||||
backgroundColor: Color(0xFF1F1F1F),
|
||||
selectedItemColor: _primaryColor,
|
||||
unselectedItemColor: Colors.grey,
|
||||
elevation: 8,
|
||||
),
|
||||
cardTheme: CardThemeData(
|
||||
elevation: 2,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
),
|
||||
inputDecorationTheme: InputDecorationTheme(
|
||||
filled: true,
|
||||
fillColor: const Color(0xFF2D2D2D),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 12,
|
||||
),
|
||||
),
|
||||
elevatedButtonTheme: ElevatedButtonThemeData(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: _primaryColor,
|
||||
foregroundColor: Colors.white,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
abstract class AuthLocalDataSource {
|
||||
Future<String?> getToken();
|
||||
Future<void> saveToken(String token);
|
||||
Future<void> removeToken();
|
||||
Future<String?> getUserId();
|
||||
Future<void> saveUserId(String userId);
|
||||
Future<void> removeUserId();
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import '../../../../core/errors/result.dart';
|
||||
import '../../domain/entities/user.dart';
|
||||
|
||||
abstract class AuthRemoteDataSource {
|
||||
Future<Result<User>> login(String email, String password);
|
||||
Future<Result<User>> register(String email, String password, String name);
|
||||
Future<Result<void>> logout();
|
||||
Future<Result<User>> getCurrentUser();
|
||||
Future<Result<void>> refreshToken();
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import '../../../../core/errors/errors.dart';
|
||||
import '../../../../core/errors/result.dart';
|
||||
import '../../domain/entities/user.dart';
|
||||
import '../../domain/repositories/auth_repository.dart';
|
||||
|
||||
class AuthRepositoryImpl implements AuthRepository {
|
||||
@override
|
||||
bool get isLoggedIn => false;
|
||||
|
||||
@override
|
||||
Future<Result<User>> getCurrentUser() async {
|
||||
return const Result.failure(AppError.unauthorized(message: 'Not logged in'));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Result<User>> login(String email, String password) async {
|
||||
// TODO: Implement real login
|
||||
return Result.success(
|
||||
User(
|
||||
id: '1',
|
||||
email: email,
|
||||
name: 'Test User',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Result<void>> logout() async {
|
||||
return const Result.success(null);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Result<User>> register(String email, String password, String name) async {
|
||||
return Result.success(
|
||||
User(
|
||||
id: '1',
|
||||
email: email,
|
||||
name: name,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Result<void>> refreshToken() async {
|
||||
return const Result.success(null);
|
||||
}
|
||||
}
|
||||
19
client-mobile/lib/features/auth/domain/entities/user.dart
Normal file
19
client-mobile/lib/features/auth/domain/entities/user.dart
Normal file
@@ -0,0 +1,19 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'user.freezed.dart';
|
||||
// part 'user.g.dart';
|
||||
|
||||
@freezed
|
||||
class User with _$User {
|
||||
const factory User({
|
||||
required String id,
|
||||
required String email,
|
||||
required String name,
|
||||
String? avatarUrl,
|
||||
String? phoneNumber,
|
||||
DateTime? lastSeen,
|
||||
bool? isOnline,
|
||||
}) = _User;
|
||||
|
||||
// factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
// 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 'user.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 _$User {
|
||||
String get id => throw _privateConstructorUsedError;
|
||||
String get email => throw _privateConstructorUsedError;
|
||||
String get name => throw _privateConstructorUsedError;
|
||||
String? get avatarUrl => throw _privateConstructorUsedError;
|
||||
String? get phoneNumber => throw _privateConstructorUsedError;
|
||||
DateTime? get lastSeen => throw _privateConstructorUsedError;
|
||||
bool? get isOnline => throw _privateConstructorUsedError;
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
$UserCopyWith<User> get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $UserCopyWith<$Res> {
|
||||
factory $UserCopyWith(User value, $Res Function(User) then) =
|
||||
_$UserCopyWithImpl<$Res, User>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{String id,
|
||||
String email,
|
||||
String name,
|
||||
String? avatarUrl,
|
||||
String? phoneNumber,
|
||||
DateTime? lastSeen,
|
||||
bool? isOnline});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$UserCopyWithImpl<$Res, $Val extends User>
|
||||
implements $UserCopyWith<$Res> {
|
||||
_$UserCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? id = null,
|
||||
Object? email = null,
|
||||
Object? name = null,
|
||||
Object? avatarUrl = freezed,
|
||||
Object? phoneNumber = freezed,
|
||||
Object? lastSeen = freezed,
|
||||
Object? isOnline = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
id: null == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
email: null == email
|
||||
? _value.email
|
||||
: email // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
name: null == name
|
||||
? _value.name
|
||||
: name // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
avatarUrl: freezed == avatarUrl
|
||||
? _value.avatarUrl
|
||||
: avatarUrl // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
phoneNumber: freezed == phoneNumber
|
||||
? _value.phoneNumber
|
||||
: phoneNumber // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
lastSeen: freezed == lastSeen
|
||||
? _value.lastSeen
|
||||
: lastSeen // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,
|
||||
isOnline: freezed == isOnline
|
||||
? _value.isOnline
|
||||
: isOnline // ignore: cast_nullable_to_non_nullable
|
||||
as bool?,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$UserImplCopyWith<$Res> implements $UserCopyWith<$Res> {
|
||||
factory _$$UserImplCopyWith(
|
||||
_$UserImpl value, $Res Function(_$UserImpl) then) =
|
||||
__$$UserImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{String id,
|
||||
String email,
|
||||
String name,
|
||||
String? avatarUrl,
|
||||
String? phoneNumber,
|
||||
DateTime? lastSeen,
|
||||
bool? isOnline});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$UserImplCopyWithImpl<$Res>
|
||||
extends _$UserCopyWithImpl<$Res, _$UserImpl>
|
||||
implements _$$UserImplCopyWith<$Res> {
|
||||
__$$UserImplCopyWithImpl(_$UserImpl _value, $Res Function(_$UserImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? id = null,
|
||||
Object? email = null,
|
||||
Object? name = null,
|
||||
Object? avatarUrl = freezed,
|
||||
Object? phoneNumber = freezed,
|
||||
Object? lastSeen = freezed,
|
||||
Object? isOnline = freezed,
|
||||
}) {
|
||||
return _then(_$UserImpl(
|
||||
id: null == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
email: null == email
|
||||
? _value.email
|
||||
: email // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
name: null == name
|
||||
? _value.name
|
||||
: name // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
avatarUrl: freezed == avatarUrl
|
||||
? _value.avatarUrl
|
||||
: avatarUrl // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
phoneNumber: freezed == phoneNumber
|
||||
? _value.phoneNumber
|
||||
: phoneNumber // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
lastSeen: freezed == lastSeen
|
||||
? _value.lastSeen
|
||||
: lastSeen // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,
|
||||
isOnline: freezed == isOnline
|
||||
? _value.isOnline
|
||||
: isOnline // ignore: cast_nullable_to_non_nullable
|
||||
as bool?,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$UserImpl implements _User {
|
||||
const _$UserImpl(
|
||||
{required this.id,
|
||||
required this.email,
|
||||
required this.name,
|
||||
this.avatarUrl,
|
||||
this.phoneNumber,
|
||||
this.lastSeen,
|
||||
this.isOnline});
|
||||
|
||||
@override
|
||||
final String id;
|
||||
@override
|
||||
final String email;
|
||||
@override
|
||||
final String name;
|
||||
@override
|
||||
final String? avatarUrl;
|
||||
@override
|
||||
final String? phoneNumber;
|
||||
@override
|
||||
final DateTime? lastSeen;
|
||||
@override
|
||||
final bool? isOnline;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'User(id: $id, email: $email, name: $name, avatarUrl: $avatarUrl, phoneNumber: $phoneNumber, lastSeen: $lastSeen, isOnline: $isOnline)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$UserImpl &&
|
||||
(identical(other.id, id) || other.id == id) &&
|
||||
(identical(other.email, email) || other.email == email) &&
|
||||
(identical(other.name, name) || other.name == name) &&
|
||||
(identical(other.avatarUrl, avatarUrl) ||
|
||||
other.avatarUrl == avatarUrl) &&
|
||||
(identical(other.phoneNumber, phoneNumber) ||
|
||||
other.phoneNumber == phoneNumber) &&
|
||||
(identical(other.lastSeen, lastSeen) ||
|
||||
other.lastSeen == lastSeen) &&
|
||||
(identical(other.isOnline, isOnline) ||
|
||||
other.isOnline == isOnline));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType, id, email, name, avatarUrl, phoneNumber, lastSeen, isOnline);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$UserImplCopyWith<_$UserImpl> get copyWith =>
|
||||
__$$UserImplCopyWithImpl<_$UserImpl>(this, _$identity);
|
||||
}
|
||||
|
||||
abstract class _User implements User {
|
||||
const factory _User(
|
||||
{required final String id,
|
||||
required final String email,
|
||||
required final String name,
|
||||
final String? avatarUrl,
|
||||
final String? phoneNumber,
|
||||
final DateTime? lastSeen,
|
||||
final bool? isOnline}) = _$UserImpl;
|
||||
|
||||
@override
|
||||
String get id;
|
||||
@override
|
||||
String get email;
|
||||
@override
|
||||
String get name;
|
||||
@override
|
||||
String? get avatarUrl;
|
||||
@override
|
||||
String? get phoneNumber;
|
||||
@override
|
||||
DateTime? get lastSeen;
|
||||
@override
|
||||
bool? get isOnline;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$UserImplCopyWith<_$UserImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import '../../../../core/errors/result.dart';
|
||||
import '../entities/user.dart';
|
||||
|
||||
abstract class AuthRepository {
|
||||
Future<Result<User>> login(String email, String password);
|
||||
Future<Result<User>> register(String email, String password, String name);
|
||||
Future<Result<void>> logout();
|
||||
Future<Result<User>> getCurrentUser();
|
||||
Future<Result<void>> refreshToken();
|
||||
bool get isLoggedIn;
|
||||
}
|
||||
13
client-mobile/lib/features/auth/domain/usecases/login.dart
Normal file
13
client-mobile/lib/features/auth/domain/usecases/login.dart
Normal file
@@ -0,0 +1,13 @@
|
||||
import '../../../../core/errors/result.dart';
|
||||
import '../repositories/auth_repository.dart';
|
||||
import '../entities/user.dart';
|
||||
|
||||
class LoginUseCase {
|
||||
final AuthRepository _repository;
|
||||
|
||||
LoginUseCase(this._repository);
|
||||
|
||||
Future<Result<User>> execute(String email, String password) {
|
||||
return _repository.login(email, password);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'auth_event.dart';
|
||||
import 'auth_state.dart';
|
||||
|
||||
class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
AuthBloc() : super(const AuthState.initial()) {
|
||||
on<AuthEventStarted>(_onStarted);
|
||||
on<AuthEventLoginRequested>(_onLoginRequested);
|
||||
on<AuthEventRegisterRequested>(_onRegisterRequested);
|
||||
on<AuthEventLogoutRequested>(_onLogoutRequested);
|
||||
on<AuthEventAuthChecked>(_onAuthChecked);
|
||||
on<AuthEventEmailChanged>(_onEmailChanged);
|
||||
on<AuthEventPasswordChanged>(_onPasswordChanged);
|
||||
on<AuthEventNameChanged>(_onNameChanged);
|
||||
}
|
||||
|
||||
Future<void> _onStarted(AuthEventStarted event, emit) async {}
|
||||
|
||||
Future<void> _onLoginRequested(AuthEventLoginRequested event, emit) async {
|
||||
emit(const AuthState.loading());
|
||||
emit(const AuthState.authenticated('user_123'));
|
||||
}
|
||||
|
||||
Future<void> _onRegisterRequested(AuthEventRegisterRequested event, emit) async {
|
||||
emit(const AuthState.loading());
|
||||
}
|
||||
|
||||
Future<void> _onLogoutRequested(AuthEventLogoutRequested event, emit) async {
|
||||
emit(const AuthState.unauthenticated());
|
||||
}
|
||||
|
||||
Future<void> _onAuthChecked(AuthEventAuthChecked event, emit) async {}
|
||||
void _onEmailChanged(AuthEventEmailChanged event, emit) {}
|
||||
void _onPasswordChanged(AuthEventPasswordChanged event, emit) {}
|
||||
void _onNameChanged(AuthEventNameChanged event, emit) {}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'auth_event.freezed.dart';
|
||||
|
||||
@freezed
|
||||
class AuthEvent with _$AuthEvent {
|
||||
const factory AuthEvent.started() = AuthEventStarted;
|
||||
const factory AuthEvent.loginRequested(String email, String password) = AuthEventLoginRequested;
|
||||
const factory AuthEvent.registerRequested(String email, String password, String name) = AuthEventRegisterRequested;
|
||||
const factory AuthEvent.logoutRequested() = AuthEventLogoutRequested;
|
||||
const factory AuthEvent.authChecked() = AuthEventAuthChecked;
|
||||
const factory AuthEvent.emailChanged(String email) = AuthEventEmailChanged;
|
||||
const factory AuthEvent.passwordChanged(String password) = AuthEventPasswordChanged;
|
||||
const factory AuthEvent.nameChanged(String name) = AuthEventNameChanged;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,12 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'auth_state.freezed.dart';
|
||||
|
||||
@freezed
|
||||
class AuthState with _$AuthState {
|
||||
const factory AuthState.initial() = AuthInitial;
|
||||
const factory AuthState.loading() = AuthLoading;
|
||||
const factory AuthState.authenticated(String userId) = AuthAuthenticated;
|
||||
const factory AuthState.unauthenticated() = AuthUnauthenticated;
|
||||
const factory AuthState.error(String message) = AuthError;
|
||||
}
|
||||
@@ -0,0 +1,757 @@
|
||||
// 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 'auth_state.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 _$AuthState {
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() initial,
|
||||
required TResult Function() loading,
|
||||
required TResult Function(String userId) authenticated,
|
||||
required TResult Function() unauthenticated,
|
||||
required TResult Function(String message) error,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? initial,
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(String userId)? authenticated,
|
||||
TResult? Function()? unauthenticated,
|
||||
TResult? Function(String message)? error,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? initial,
|
||||
TResult Function()? loading,
|
||||
TResult Function(String userId)? authenticated,
|
||||
TResult Function()? unauthenticated,
|
||||
TResult Function(String message)? error,
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(AuthInitial value) initial,
|
||||
required TResult Function(AuthLoading value) loading,
|
||||
required TResult Function(AuthAuthenticated value) authenticated,
|
||||
required TResult Function(AuthUnauthenticated value) unauthenticated,
|
||||
required TResult Function(AuthError value) error,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(AuthInitial value)? initial,
|
||||
TResult? Function(AuthLoading value)? loading,
|
||||
TResult? Function(AuthAuthenticated value)? authenticated,
|
||||
TResult? Function(AuthUnauthenticated value)? unauthenticated,
|
||||
TResult? Function(AuthError value)? error,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(AuthInitial value)? initial,
|
||||
TResult Function(AuthLoading value)? loading,
|
||||
TResult Function(AuthAuthenticated value)? authenticated,
|
||||
TResult Function(AuthUnauthenticated value)? unauthenticated,
|
||||
TResult Function(AuthError value)? error,
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $AuthStateCopyWith<$Res> {
|
||||
factory $AuthStateCopyWith(AuthState value, $Res Function(AuthState) then) =
|
||||
_$AuthStateCopyWithImpl<$Res, AuthState>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$AuthStateCopyWithImpl<$Res, $Val extends AuthState>
|
||||
implements $AuthStateCopyWith<$Res> {
|
||||
_$AuthStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$AuthInitialImplCopyWith<$Res> {
|
||||
factory _$$AuthInitialImplCopyWith(
|
||||
_$AuthInitialImpl value, $Res Function(_$AuthInitialImpl) then) =
|
||||
__$$AuthInitialImplCopyWithImpl<$Res>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$AuthInitialImplCopyWithImpl<$Res>
|
||||
extends _$AuthStateCopyWithImpl<$Res, _$AuthInitialImpl>
|
||||
implements _$$AuthInitialImplCopyWith<$Res> {
|
||||
__$$AuthInitialImplCopyWithImpl(
|
||||
_$AuthInitialImpl _value, $Res Function(_$AuthInitialImpl) _then)
|
||||
: super(_value, _then);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$AuthInitialImpl implements AuthInitial {
|
||||
const _$AuthInitialImpl();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AuthState.initial()';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _$AuthInitialImpl);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => runtimeType.hashCode;
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() initial,
|
||||
required TResult Function() loading,
|
||||
required TResult Function(String userId) authenticated,
|
||||
required TResult Function() unauthenticated,
|
||||
required TResult Function(String message) error,
|
||||
}) {
|
||||
return initial();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? initial,
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(String userId)? authenticated,
|
||||
TResult? Function()? unauthenticated,
|
||||
TResult? Function(String message)? error,
|
||||
}) {
|
||||
return initial?.call();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? initial,
|
||||
TResult Function()? loading,
|
||||
TResult Function(String userId)? authenticated,
|
||||
TResult Function()? unauthenticated,
|
||||
TResult Function(String message)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (initial != null) {
|
||||
return initial();
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(AuthInitial value) initial,
|
||||
required TResult Function(AuthLoading value) loading,
|
||||
required TResult Function(AuthAuthenticated value) authenticated,
|
||||
required TResult Function(AuthUnauthenticated value) unauthenticated,
|
||||
required TResult Function(AuthError value) error,
|
||||
}) {
|
||||
return initial(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(AuthInitial value)? initial,
|
||||
TResult? Function(AuthLoading value)? loading,
|
||||
TResult? Function(AuthAuthenticated value)? authenticated,
|
||||
TResult? Function(AuthUnauthenticated value)? unauthenticated,
|
||||
TResult? Function(AuthError value)? error,
|
||||
}) {
|
||||
return initial?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(AuthInitial value)? initial,
|
||||
TResult Function(AuthLoading value)? loading,
|
||||
TResult Function(AuthAuthenticated value)? authenticated,
|
||||
TResult Function(AuthUnauthenticated value)? unauthenticated,
|
||||
TResult Function(AuthError value)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (initial != null) {
|
||||
return initial(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AuthInitial implements AuthState {
|
||||
const factory AuthInitial() = _$AuthInitialImpl;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$AuthLoadingImplCopyWith<$Res> {
|
||||
factory _$$AuthLoadingImplCopyWith(
|
||||
_$AuthLoadingImpl value, $Res Function(_$AuthLoadingImpl) then) =
|
||||
__$$AuthLoadingImplCopyWithImpl<$Res>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$AuthLoadingImplCopyWithImpl<$Res>
|
||||
extends _$AuthStateCopyWithImpl<$Res, _$AuthLoadingImpl>
|
||||
implements _$$AuthLoadingImplCopyWith<$Res> {
|
||||
__$$AuthLoadingImplCopyWithImpl(
|
||||
_$AuthLoadingImpl _value, $Res Function(_$AuthLoadingImpl) _then)
|
||||
: super(_value, _then);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$AuthLoadingImpl implements AuthLoading {
|
||||
const _$AuthLoadingImpl();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AuthState.loading()';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _$AuthLoadingImpl);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => runtimeType.hashCode;
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() initial,
|
||||
required TResult Function() loading,
|
||||
required TResult Function(String userId) authenticated,
|
||||
required TResult Function() unauthenticated,
|
||||
required TResult Function(String message) error,
|
||||
}) {
|
||||
return loading();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? initial,
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(String userId)? authenticated,
|
||||
TResult? Function()? unauthenticated,
|
||||
TResult? Function(String message)? error,
|
||||
}) {
|
||||
return loading?.call();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? initial,
|
||||
TResult Function()? loading,
|
||||
TResult Function(String userId)? authenticated,
|
||||
TResult Function()? unauthenticated,
|
||||
TResult Function(String message)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (loading != null) {
|
||||
return loading();
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(AuthInitial value) initial,
|
||||
required TResult Function(AuthLoading value) loading,
|
||||
required TResult Function(AuthAuthenticated value) authenticated,
|
||||
required TResult Function(AuthUnauthenticated value) unauthenticated,
|
||||
required TResult Function(AuthError value) error,
|
||||
}) {
|
||||
return loading(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(AuthInitial value)? initial,
|
||||
TResult? Function(AuthLoading value)? loading,
|
||||
TResult? Function(AuthAuthenticated value)? authenticated,
|
||||
TResult? Function(AuthUnauthenticated value)? unauthenticated,
|
||||
TResult? Function(AuthError value)? error,
|
||||
}) {
|
||||
return loading?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(AuthInitial value)? initial,
|
||||
TResult Function(AuthLoading value)? loading,
|
||||
TResult Function(AuthAuthenticated value)? authenticated,
|
||||
TResult Function(AuthUnauthenticated value)? unauthenticated,
|
||||
TResult Function(AuthError value)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (loading != null) {
|
||||
return loading(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AuthLoading implements AuthState {
|
||||
const factory AuthLoading() = _$AuthLoadingImpl;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$AuthAuthenticatedImplCopyWith<$Res> {
|
||||
factory _$$AuthAuthenticatedImplCopyWith(_$AuthAuthenticatedImpl value,
|
||||
$Res Function(_$AuthAuthenticatedImpl) then) =
|
||||
__$$AuthAuthenticatedImplCopyWithImpl<$Res>;
|
||||
@useResult
|
||||
$Res call({String userId});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$AuthAuthenticatedImplCopyWithImpl<$Res>
|
||||
extends _$AuthStateCopyWithImpl<$Res, _$AuthAuthenticatedImpl>
|
||||
implements _$$AuthAuthenticatedImplCopyWith<$Res> {
|
||||
__$$AuthAuthenticatedImplCopyWithImpl(_$AuthAuthenticatedImpl _value,
|
||||
$Res Function(_$AuthAuthenticatedImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? userId = null,
|
||||
}) {
|
||||
return _then(_$AuthAuthenticatedImpl(
|
||||
null == userId
|
||||
? _value.userId
|
||||
: userId // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$AuthAuthenticatedImpl implements AuthAuthenticated {
|
||||
const _$AuthAuthenticatedImpl(this.userId);
|
||||
|
||||
@override
|
||||
final String userId;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AuthState.authenticated(userId: $userId)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$AuthAuthenticatedImpl &&
|
||||
(identical(other.userId, userId) || other.userId == userId));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, userId);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$AuthAuthenticatedImplCopyWith<_$AuthAuthenticatedImpl> get copyWith =>
|
||||
__$$AuthAuthenticatedImplCopyWithImpl<_$AuthAuthenticatedImpl>(
|
||||
this, _$identity);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() initial,
|
||||
required TResult Function() loading,
|
||||
required TResult Function(String userId) authenticated,
|
||||
required TResult Function() unauthenticated,
|
||||
required TResult Function(String message) error,
|
||||
}) {
|
||||
return authenticated(userId);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? initial,
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(String userId)? authenticated,
|
||||
TResult? Function()? unauthenticated,
|
||||
TResult? Function(String message)? error,
|
||||
}) {
|
||||
return authenticated?.call(userId);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? initial,
|
||||
TResult Function()? loading,
|
||||
TResult Function(String userId)? authenticated,
|
||||
TResult Function()? unauthenticated,
|
||||
TResult Function(String message)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (authenticated != null) {
|
||||
return authenticated(userId);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(AuthInitial value) initial,
|
||||
required TResult Function(AuthLoading value) loading,
|
||||
required TResult Function(AuthAuthenticated value) authenticated,
|
||||
required TResult Function(AuthUnauthenticated value) unauthenticated,
|
||||
required TResult Function(AuthError value) error,
|
||||
}) {
|
||||
return authenticated(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(AuthInitial value)? initial,
|
||||
TResult? Function(AuthLoading value)? loading,
|
||||
TResult? Function(AuthAuthenticated value)? authenticated,
|
||||
TResult? Function(AuthUnauthenticated value)? unauthenticated,
|
||||
TResult? Function(AuthError value)? error,
|
||||
}) {
|
||||
return authenticated?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(AuthInitial value)? initial,
|
||||
TResult Function(AuthLoading value)? loading,
|
||||
TResult Function(AuthAuthenticated value)? authenticated,
|
||||
TResult Function(AuthUnauthenticated value)? unauthenticated,
|
||||
TResult Function(AuthError value)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (authenticated != null) {
|
||||
return authenticated(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AuthAuthenticated implements AuthState {
|
||||
const factory AuthAuthenticated(final String userId) =
|
||||
_$AuthAuthenticatedImpl;
|
||||
|
||||
String get userId;
|
||||
@JsonKey(ignore: true)
|
||||
_$$AuthAuthenticatedImplCopyWith<_$AuthAuthenticatedImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$AuthUnauthenticatedImplCopyWith<$Res> {
|
||||
factory _$$AuthUnauthenticatedImplCopyWith(_$AuthUnauthenticatedImpl value,
|
||||
$Res Function(_$AuthUnauthenticatedImpl) then) =
|
||||
__$$AuthUnauthenticatedImplCopyWithImpl<$Res>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$AuthUnauthenticatedImplCopyWithImpl<$Res>
|
||||
extends _$AuthStateCopyWithImpl<$Res, _$AuthUnauthenticatedImpl>
|
||||
implements _$$AuthUnauthenticatedImplCopyWith<$Res> {
|
||||
__$$AuthUnauthenticatedImplCopyWithImpl(_$AuthUnauthenticatedImpl _value,
|
||||
$Res Function(_$AuthUnauthenticatedImpl) _then)
|
||||
: super(_value, _then);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$AuthUnauthenticatedImpl implements AuthUnauthenticated {
|
||||
const _$AuthUnauthenticatedImpl();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AuthState.unauthenticated()';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$AuthUnauthenticatedImpl);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => runtimeType.hashCode;
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() initial,
|
||||
required TResult Function() loading,
|
||||
required TResult Function(String userId) authenticated,
|
||||
required TResult Function() unauthenticated,
|
||||
required TResult Function(String message) error,
|
||||
}) {
|
||||
return unauthenticated();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? initial,
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(String userId)? authenticated,
|
||||
TResult? Function()? unauthenticated,
|
||||
TResult? Function(String message)? error,
|
||||
}) {
|
||||
return unauthenticated?.call();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? initial,
|
||||
TResult Function()? loading,
|
||||
TResult Function(String userId)? authenticated,
|
||||
TResult Function()? unauthenticated,
|
||||
TResult Function(String message)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (unauthenticated != null) {
|
||||
return unauthenticated();
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(AuthInitial value) initial,
|
||||
required TResult Function(AuthLoading value) loading,
|
||||
required TResult Function(AuthAuthenticated value) authenticated,
|
||||
required TResult Function(AuthUnauthenticated value) unauthenticated,
|
||||
required TResult Function(AuthError value) error,
|
||||
}) {
|
||||
return unauthenticated(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(AuthInitial value)? initial,
|
||||
TResult? Function(AuthLoading value)? loading,
|
||||
TResult? Function(AuthAuthenticated value)? authenticated,
|
||||
TResult? Function(AuthUnauthenticated value)? unauthenticated,
|
||||
TResult? Function(AuthError value)? error,
|
||||
}) {
|
||||
return unauthenticated?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(AuthInitial value)? initial,
|
||||
TResult Function(AuthLoading value)? loading,
|
||||
TResult Function(AuthAuthenticated value)? authenticated,
|
||||
TResult Function(AuthUnauthenticated value)? unauthenticated,
|
||||
TResult Function(AuthError value)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (unauthenticated != null) {
|
||||
return unauthenticated(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AuthUnauthenticated implements AuthState {
|
||||
const factory AuthUnauthenticated() = _$AuthUnauthenticatedImpl;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$AuthErrorImplCopyWith<$Res> {
|
||||
factory _$$AuthErrorImplCopyWith(
|
||||
_$AuthErrorImpl value, $Res Function(_$AuthErrorImpl) then) =
|
||||
__$$AuthErrorImplCopyWithImpl<$Res>;
|
||||
@useResult
|
||||
$Res call({String message});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$AuthErrorImplCopyWithImpl<$Res>
|
||||
extends _$AuthStateCopyWithImpl<$Res, _$AuthErrorImpl>
|
||||
implements _$$AuthErrorImplCopyWith<$Res> {
|
||||
__$$AuthErrorImplCopyWithImpl(
|
||||
_$AuthErrorImpl _value, $Res Function(_$AuthErrorImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? message = null,
|
||||
}) {
|
||||
return _then(_$AuthErrorImpl(
|
||||
null == message
|
||||
? _value.message
|
||||
: message // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$AuthErrorImpl implements AuthError {
|
||||
const _$AuthErrorImpl(this.message);
|
||||
|
||||
@override
|
||||
final String message;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AuthState.error(message: $message)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$AuthErrorImpl &&
|
||||
(identical(other.message, message) || other.message == message));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, message);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$AuthErrorImplCopyWith<_$AuthErrorImpl> get copyWith =>
|
||||
__$$AuthErrorImplCopyWithImpl<_$AuthErrorImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() initial,
|
||||
required TResult Function() loading,
|
||||
required TResult Function(String userId) authenticated,
|
||||
required TResult Function() unauthenticated,
|
||||
required TResult Function(String message) error,
|
||||
}) {
|
||||
return error(message);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? initial,
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(String userId)? authenticated,
|
||||
TResult? Function()? unauthenticated,
|
||||
TResult? Function(String message)? error,
|
||||
}) {
|
||||
return error?.call(message);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? initial,
|
||||
TResult Function()? loading,
|
||||
TResult Function(String userId)? authenticated,
|
||||
TResult Function()? unauthenticated,
|
||||
TResult Function(String message)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (error != null) {
|
||||
return error(message);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(AuthInitial value) initial,
|
||||
required TResult Function(AuthLoading value) loading,
|
||||
required TResult Function(AuthAuthenticated value) authenticated,
|
||||
required TResult Function(AuthUnauthenticated value) unauthenticated,
|
||||
required TResult Function(AuthError value) error,
|
||||
}) {
|
||||
return error(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(AuthInitial value)? initial,
|
||||
TResult? Function(AuthLoading value)? loading,
|
||||
TResult? Function(AuthAuthenticated value)? authenticated,
|
||||
TResult? Function(AuthUnauthenticated value)? unauthenticated,
|
||||
TResult? Function(AuthError value)? error,
|
||||
}) {
|
||||
return error?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(AuthInitial value)? initial,
|
||||
TResult Function(AuthLoading value)? loading,
|
||||
TResult Function(AuthAuthenticated value)? authenticated,
|
||||
TResult Function(AuthUnauthenticated value)? unauthenticated,
|
||||
TResult Function(AuthError value)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (error != null) {
|
||||
return error(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AuthError implements AuthState {
|
||||
const factory AuthError(final String message) = _$AuthErrorImpl;
|
||||
|
||||
String get message;
|
||||
@JsonKey(ignore: true)
|
||||
_$$AuthErrorImplCopyWith<_$AuthErrorImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import '../bloc/auth_bloc.dart';
|
||||
import '../bloc/auth_event.dart';
|
||||
import '../bloc/auth_state.dart';
|
||||
|
||||
class LoginPage extends StatefulWidget {
|
||||
const LoginPage({super.key});
|
||||
|
||||
@override
|
||||
State<LoginPage> createState() => _LoginPageState();
|
||||
}
|
||||
|
||||
class _LoginPageState extends State<LoginPage> {
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
final _emailController = TextEditingController();
|
||||
final _passwordController = TextEditingController();
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_emailController.dispose();
|
||||
_passwordController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Вход'),
|
||||
),
|
||||
body: BlocListener<AuthBloc, AuthState>(
|
||||
listener: (context, state) {
|
||||
state.whenOrNull(
|
||||
authenticated: (userId) {
|
||||
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||
},
|
||||
error: (message) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(message)),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
child: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24.0),
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.chat_bubble_outline,
|
||||
size: 80,
|
||||
color: Color(0xFF2481CC),
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
TextFormField(
|
||||
controller: _emailController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Email',
|
||||
prefixIcon: Icon(Icons.email_outlined),
|
||||
),
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Введите email';
|
||||
}
|
||||
if (!value.contains('@')) {
|
||||
return 'Введите корректный email';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextFormField(
|
||||
controller: _passwordController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Пароль',
|
||||
prefixIcon: Icon(Icons.lock_outlined),
|
||||
),
|
||||
obscureText: true,
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Введите пароль';
|
||||
}
|
||||
if (value.length < 6) {
|
||||
return 'Пароль должен быть не менее 6 символов';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
BlocBuilder<AuthBloc, AuthState>(
|
||||
builder: (context, state) {
|
||||
if (state is AuthLoading) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
return ElevatedButton(
|
||||
onPressed: () {
|
||||
if (_formKey.currentState?.validate() ?? false) {
|
||||
context.read<AuthBloc>().add(
|
||||
AuthEvent.loginRequested(
|
||||
_emailController.text,
|
||||
_passwordController.text,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 12),
|
||||
child: Text('Войти', style: TextStyle(fontSize: 16)),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
// Navigate to register page
|
||||
},
|
||||
child: const Text('Нет аккаунта? Зарегистрироваться'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import '../../../../core/errors/result.dart';
|
||||
import '../../domain/entities/chat.dart';
|
||||
import '../../domain/entities/message.dart';
|
||||
|
||||
abstract class ChatLocalDataSource {
|
||||
Future<Result<List<Chat>>> getCachedChats();
|
||||
Future<Result<void>> cacheChats(List<Chat> chats);
|
||||
Future<Result<Chat>> getChatFromCache(String chatId);
|
||||
Future<Result<void>> cacheChat(Chat chat);
|
||||
Future<Result<List<Message>>> getMessagesFromCache(String chatId);
|
||||
Future<Result<void>> cacheMessages(String chatId, List<Message> messages);
|
||||
Future<Result<void>> clearCache();
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import '../../../../core/errors/result.dart';
|
||||
import '../../domain/entities/chat.dart';
|
||||
import '../../domain/entities/message.dart';
|
||||
|
||||
abstract class ChatRemoteDataSource {
|
||||
Future<Result<List<Chat>>> getChats();
|
||||
Future<Result<Chat>> getChatById(String chatId);
|
||||
Future<Result<void>> createChat(String title, List<String> participantIds);
|
||||
Future<Result<void>> sendMessage(String chatId, Message message);
|
||||
Future<Result<List<Message>>> getMessages(String chatId, {int? limit, String? lastMessageId});
|
||||
Stream<Result<Message>> listenToMessages(String chatId);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import '../../../../core/errors/errors.dart';
|
||||
import '../../../../core/errors/result.dart';
|
||||
import '../../domain/entities/chat.dart';
|
||||
import '../../domain/entities/message.dart';
|
||||
import '../../domain/repositories/chat_repository.dart';
|
||||
|
||||
class ChatRepositoryImpl implements ChatRepository {
|
||||
@override
|
||||
Future<Result<void>> createChat(String title, List<String> participantIds) async {
|
||||
return const Result.success(null);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Result<void>> deleteChat(String chatId) async {
|
||||
return const Result.success(null);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Result<Chat>> getChatById(String chatId) async {
|
||||
return const Result.failure(AppError.notFound(message: 'Chat not found'));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Result<List<Chat>>> getChats() async {
|
||||
// Return empty list for now
|
||||
return const Result.success([]);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Result<List<Message>>> getMessages(
|
||||
String chatId, {
|
||||
int? limit,
|
||||
String? lastMessageId,
|
||||
}) async {
|
||||
return const Result.success([]);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Result<void>> sendMessage(String chatId, Message message) async {
|
||||
return const Result.success(null);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Result<void>> updateChat(String chatId, String title) async {
|
||||
return const Result.success(null);
|
||||
}
|
||||
}
|
||||
21
client-mobile/lib/features/chat/domain/entities/chat.dart
Normal file
21
client-mobile/lib/features/chat/domain/entities/chat.dart
Normal file
@@ -0,0 +1,21 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'user.dart';
|
||||
import 'message.dart';
|
||||
|
||||
part 'chat.freezed.dart';
|
||||
|
||||
@freezed
|
||||
class Chat with _$Chat {
|
||||
const factory Chat({
|
||||
required String id,
|
||||
required String type,
|
||||
required String title,
|
||||
String? avatarUrl,
|
||||
List<User>? participants,
|
||||
@Default(null) Message? lastMessage,
|
||||
DateTime? lastMessageTime,
|
||||
@Default(0) int unreadCount,
|
||||
@Default(false) bool isMuted,
|
||||
@Default(false) bool isPinned,
|
||||
}) = _Chat;
|
||||
}
|
||||
@@ -0,0 +1,359 @@
|
||||
// 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 'chat.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 _$Chat {
|
||||
String get id => throw _privateConstructorUsedError;
|
||||
String get type => throw _privateConstructorUsedError;
|
||||
String get title => throw _privateConstructorUsedError;
|
||||
String? get avatarUrl => throw _privateConstructorUsedError;
|
||||
List<User>? get participants => throw _privateConstructorUsedError;
|
||||
Message? get lastMessage => throw _privateConstructorUsedError;
|
||||
DateTime? get lastMessageTime => throw _privateConstructorUsedError;
|
||||
int get unreadCount => throw _privateConstructorUsedError;
|
||||
bool get isMuted => throw _privateConstructorUsedError;
|
||||
bool get isPinned => throw _privateConstructorUsedError;
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
$ChatCopyWith<Chat> get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $ChatCopyWith<$Res> {
|
||||
factory $ChatCopyWith(Chat value, $Res Function(Chat) then) =
|
||||
_$ChatCopyWithImpl<$Res, Chat>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{String id,
|
||||
String type,
|
||||
String title,
|
||||
String? avatarUrl,
|
||||
List<User>? participants,
|
||||
Message? lastMessage,
|
||||
DateTime? lastMessageTime,
|
||||
int unreadCount,
|
||||
bool isMuted,
|
||||
bool isPinned});
|
||||
|
||||
$MessageCopyWith<$Res>? get lastMessage;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$ChatCopyWithImpl<$Res, $Val extends Chat>
|
||||
implements $ChatCopyWith<$Res> {
|
||||
_$ChatCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? id = null,
|
||||
Object? type = null,
|
||||
Object? title = null,
|
||||
Object? avatarUrl = freezed,
|
||||
Object? participants = freezed,
|
||||
Object? lastMessage = freezed,
|
||||
Object? lastMessageTime = freezed,
|
||||
Object? unreadCount = null,
|
||||
Object? isMuted = null,
|
||||
Object? isPinned = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
id: null == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
type: null == type
|
||||
? _value.type
|
||||
: type // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
title: null == title
|
||||
? _value.title
|
||||
: title // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
avatarUrl: freezed == avatarUrl
|
||||
? _value.avatarUrl
|
||||
: avatarUrl // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
participants: freezed == participants
|
||||
? _value.participants
|
||||
: participants // ignore: cast_nullable_to_non_nullable
|
||||
as List<User>?,
|
||||
lastMessage: freezed == lastMessage
|
||||
? _value.lastMessage
|
||||
: lastMessage // ignore: cast_nullable_to_non_nullable
|
||||
as Message?,
|
||||
lastMessageTime: freezed == lastMessageTime
|
||||
? _value.lastMessageTime
|
||||
: lastMessageTime // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,
|
||||
unreadCount: null == unreadCount
|
||||
? _value.unreadCount
|
||||
: unreadCount // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
isMuted: null == isMuted
|
||||
? _value.isMuted
|
||||
: isMuted // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
isPinned: null == isPinned
|
||||
? _value.isPinned
|
||||
: isPinned // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
) as $Val);
|
||||
}
|
||||
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$MessageCopyWith<$Res>? get lastMessage {
|
||||
if (_value.lastMessage == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $MessageCopyWith<$Res>(_value.lastMessage!, (value) {
|
||||
return _then(_value.copyWith(lastMessage: value) as $Val);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$ChatImplCopyWith<$Res> implements $ChatCopyWith<$Res> {
|
||||
factory _$$ChatImplCopyWith(
|
||||
_$ChatImpl value, $Res Function(_$ChatImpl) then) =
|
||||
__$$ChatImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{String id,
|
||||
String type,
|
||||
String title,
|
||||
String? avatarUrl,
|
||||
List<User>? participants,
|
||||
Message? lastMessage,
|
||||
DateTime? lastMessageTime,
|
||||
int unreadCount,
|
||||
bool isMuted,
|
||||
bool isPinned});
|
||||
|
||||
@override
|
||||
$MessageCopyWith<$Res>? get lastMessage;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$ChatImplCopyWithImpl<$Res>
|
||||
extends _$ChatCopyWithImpl<$Res, _$ChatImpl>
|
||||
implements _$$ChatImplCopyWith<$Res> {
|
||||
__$$ChatImplCopyWithImpl(_$ChatImpl _value, $Res Function(_$ChatImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? id = null,
|
||||
Object? type = null,
|
||||
Object? title = null,
|
||||
Object? avatarUrl = freezed,
|
||||
Object? participants = freezed,
|
||||
Object? lastMessage = freezed,
|
||||
Object? lastMessageTime = freezed,
|
||||
Object? unreadCount = null,
|
||||
Object? isMuted = null,
|
||||
Object? isPinned = null,
|
||||
}) {
|
||||
return _then(_$ChatImpl(
|
||||
id: null == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
type: null == type
|
||||
? _value.type
|
||||
: type // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
title: null == title
|
||||
? _value.title
|
||||
: title // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
avatarUrl: freezed == avatarUrl
|
||||
? _value.avatarUrl
|
||||
: avatarUrl // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
participants: freezed == participants
|
||||
? _value._participants
|
||||
: participants // ignore: cast_nullable_to_non_nullable
|
||||
as List<User>?,
|
||||
lastMessage: freezed == lastMessage
|
||||
? _value.lastMessage
|
||||
: lastMessage // ignore: cast_nullable_to_non_nullable
|
||||
as Message?,
|
||||
lastMessageTime: freezed == lastMessageTime
|
||||
? _value.lastMessageTime
|
||||
: lastMessageTime // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,
|
||||
unreadCount: null == unreadCount
|
||||
? _value.unreadCount
|
||||
: unreadCount // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
isMuted: null == isMuted
|
||||
? _value.isMuted
|
||||
: isMuted // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
isPinned: null == isPinned
|
||||
? _value.isPinned
|
||||
: isPinned // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$ChatImpl implements _Chat {
|
||||
const _$ChatImpl(
|
||||
{required this.id,
|
||||
required this.type,
|
||||
required this.title,
|
||||
this.avatarUrl,
|
||||
final List<User>? participants,
|
||||
this.lastMessage = null,
|
||||
this.lastMessageTime,
|
||||
this.unreadCount = 0,
|
||||
this.isMuted = false,
|
||||
this.isPinned = false})
|
||||
: _participants = participants;
|
||||
|
||||
@override
|
||||
final String id;
|
||||
@override
|
||||
final String type;
|
||||
@override
|
||||
final String title;
|
||||
@override
|
||||
final String? avatarUrl;
|
||||
final List<User>? _participants;
|
||||
@override
|
||||
List<User>? get participants {
|
||||
final value = _participants;
|
||||
if (value == null) return null;
|
||||
if (_participants is EqualUnmodifiableListView) return _participants;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(value);
|
||||
}
|
||||
|
||||
@override
|
||||
@JsonKey()
|
||||
final Message? lastMessage;
|
||||
@override
|
||||
final DateTime? lastMessageTime;
|
||||
@override
|
||||
@JsonKey()
|
||||
final int unreadCount;
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool isMuted;
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool isPinned;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Chat(id: $id, type: $type, title: $title, avatarUrl: $avatarUrl, participants: $participants, lastMessage: $lastMessage, lastMessageTime: $lastMessageTime, unreadCount: $unreadCount, isMuted: $isMuted, isPinned: $isPinned)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$ChatImpl &&
|
||||
(identical(other.id, id) || other.id == id) &&
|
||||
(identical(other.type, type) || other.type == type) &&
|
||||
(identical(other.title, title) || other.title == title) &&
|
||||
(identical(other.avatarUrl, avatarUrl) ||
|
||||
other.avatarUrl == avatarUrl) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._participants, _participants) &&
|
||||
(identical(other.lastMessage, lastMessage) ||
|
||||
other.lastMessage == lastMessage) &&
|
||||
(identical(other.lastMessageTime, lastMessageTime) ||
|
||||
other.lastMessageTime == lastMessageTime) &&
|
||||
(identical(other.unreadCount, unreadCount) ||
|
||||
other.unreadCount == unreadCount) &&
|
||||
(identical(other.isMuted, isMuted) || other.isMuted == isMuted) &&
|
||||
(identical(other.isPinned, isPinned) ||
|
||||
other.isPinned == isPinned));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
id,
|
||||
type,
|
||||
title,
|
||||
avatarUrl,
|
||||
const DeepCollectionEquality().hash(_participants),
|
||||
lastMessage,
|
||||
lastMessageTime,
|
||||
unreadCount,
|
||||
isMuted,
|
||||
isPinned);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$ChatImplCopyWith<_$ChatImpl> get copyWith =>
|
||||
__$$ChatImplCopyWithImpl<_$ChatImpl>(this, _$identity);
|
||||
}
|
||||
|
||||
abstract class _Chat implements Chat {
|
||||
const factory _Chat(
|
||||
{required final String id,
|
||||
required final String type,
|
||||
required final String title,
|
||||
final String? avatarUrl,
|
||||
final List<User>? participants,
|
||||
final Message? lastMessage,
|
||||
final DateTime? lastMessageTime,
|
||||
final int unreadCount,
|
||||
final bool isMuted,
|
||||
final bool isPinned}) = _$ChatImpl;
|
||||
|
||||
@override
|
||||
String get id;
|
||||
@override
|
||||
String get type;
|
||||
@override
|
||||
String get title;
|
||||
@override
|
||||
String? get avatarUrl;
|
||||
@override
|
||||
List<User>? get participants;
|
||||
@override
|
||||
Message? get lastMessage;
|
||||
@override
|
||||
DateTime? get lastMessageTime;
|
||||
@override
|
||||
int get unreadCount;
|
||||
@override
|
||||
bool get isMuted;
|
||||
@override
|
||||
bool get isPinned;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$ChatImplCopyWith<_$ChatImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
21
client-mobile/lib/features/chat/domain/entities/message.dart
Normal file
21
client-mobile/lib/features/chat/domain/entities/message.dart
Normal file
@@ -0,0 +1,21 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'message.freezed.dart';
|
||||
// part 'message.g.dart';
|
||||
|
||||
@freezed
|
||||
class Message with _$Message {
|
||||
const factory Message({
|
||||
required String id,
|
||||
required String chatId,
|
||||
required String senderId,
|
||||
required String content,
|
||||
required String messageType, // 'text', 'image', 'video', 'audio', 'file'
|
||||
DateTime? createdAt,
|
||||
DateTime? updatedAt,
|
||||
bool? isRead,
|
||||
Map<String, dynamic>? media,
|
||||
}) = _Message;
|
||||
|
||||
// factory Message.fromJson(Map<String, dynamic> json) => _$MessageFromJson(json);
|
||||
}
|
||||
@@ -0,0 +1,317 @@
|
||||
// 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 'message.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 _$Message {
|
||||
String get id => throw _privateConstructorUsedError;
|
||||
String get chatId => throw _privateConstructorUsedError;
|
||||
String get senderId => throw _privateConstructorUsedError;
|
||||
String get content => throw _privateConstructorUsedError;
|
||||
String get messageType =>
|
||||
throw _privateConstructorUsedError; // 'text', 'image', 'video', 'audio', 'file'
|
||||
DateTime? get createdAt => throw _privateConstructorUsedError;
|
||||
DateTime? get updatedAt => throw _privateConstructorUsedError;
|
||||
bool? get isRead => throw _privateConstructorUsedError;
|
||||
Map<String, dynamic>? get media => throw _privateConstructorUsedError;
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
$MessageCopyWith<Message> get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $MessageCopyWith<$Res> {
|
||||
factory $MessageCopyWith(Message value, $Res Function(Message) then) =
|
||||
_$MessageCopyWithImpl<$Res, Message>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{String id,
|
||||
String chatId,
|
||||
String senderId,
|
||||
String content,
|
||||
String messageType,
|
||||
DateTime? createdAt,
|
||||
DateTime? updatedAt,
|
||||
bool? isRead,
|
||||
Map<String, dynamic>? media});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$MessageCopyWithImpl<$Res, $Val extends Message>
|
||||
implements $MessageCopyWith<$Res> {
|
||||
_$MessageCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? id = null,
|
||||
Object? chatId = null,
|
||||
Object? senderId = null,
|
||||
Object? content = null,
|
||||
Object? messageType = null,
|
||||
Object? createdAt = freezed,
|
||||
Object? updatedAt = freezed,
|
||||
Object? isRead = freezed,
|
||||
Object? media = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
id: null == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
chatId: null == chatId
|
||||
? _value.chatId
|
||||
: chatId // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
senderId: null == senderId
|
||||
? _value.senderId
|
||||
: senderId // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
content: null == content
|
||||
? _value.content
|
||||
: content // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
messageType: null == messageType
|
||||
? _value.messageType
|
||||
: messageType // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
createdAt: freezed == createdAt
|
||||
? _value.createdAt
|
||||
: createdAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,
|
||||
updatedAt: freezed == updatedAt
|
||||
? _value.updatedAt
|
||||
: updatedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,
|
||||
isRead: freezed == isRead
|
||||
? _value.isRead
|
||||
: isRead // ignore: cast_nullable_to_non_nullable
|
||||
as bool?,
|
||||
media: freezed == media
|
||||
? _value.media
|
||||
: media // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, dynamic>?,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$MessageImplCopyWith<$Res> implements $MessageCopyWith<$Res> {
|
||||
factory _$$MessageImplCopyWith(
|
||||
_$MessageImpl value, $Res Function(_$MessageImpl) then) =
|
||||
__$$MessageImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{String id,
|
||||
String chatId,
|
||||
String senderId,
|
||||
String content,
|
||||
String messageType,
|
||||
DateTime? createdAt,
|
||||
DateTime? updatedAt,
|
||||
bool? isRead,
|
||||
Map<String, dynamic>? media});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$MessageImplCopyWithImpl<$Res>
|
||||
extends _$MessageCopyWithImpl<$Res, _$MessageImpl>
|
||||
implements _$$MessageImplCopyWith<$Res> {
|
||||
__$$MessageImplCopyWithImpl(
|
||||
_$MessageImpl _value, $Res Function(_$MessageImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? id = null,
|
||||
Object? chatId = null,
|
||||
Object? senderId = null,
|
||||
Object? content = null,
|
||||
Object? messageType = null,
|
||||
Object? createdAt = freezed,
|
||||
Object? updatedAt = freezed,
|
||||
Object? isRead = freezed,
|
||||
Object? media = freezed,
|
||||
}) {
|
||||
return _then(_$MessageImpl(
|
||||
id: null == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
chatId: null == chatId
|
||||
? _value.chatId
|
||||
: chatId // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
senderId: null == senderId
|
||||
? _value.senderId
|
||||
: senderId // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
content: null == content
|
||||
? _value.content
|
||||
: content // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
messageType: null == messageType
|
||||
? _value.messageType
|
||||
: messageType // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
createdAt: freezed == createdAt
|
||||
? _value.createdAt
|
||||
: createdAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,
|
||||
updatedAt: freezed == updatedAt
|
||||
? _value.updatedAt
|
||||
: updatedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,
|
||||
isRead: freezed == isRead
|
||||
? _value.isRead
|
||||
: isRead // ignore: cast_nullable_to_non_nullable
|
||||
as bool?,
|
||||
media: freezed == media
|
||||
? _value._media
|
||||
: media // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, dynamic>?,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$MessageImpl implements _Message {
|
||||
const _$MessageImpl(
|
||||
{required this.id,
|
||||
required this.chatId,
|
||||
required this.senderId,
|
||||
required this.content,
|
||||
required this.messageType,
|
||||
this.createdAt,
|
||||
this.updatedAt,
|
||||
this.isRead,
|
||||
final Map<String, dynamic>? media})
|
||||
: _media = media;
|
||||
|
||||
@override
|
||||
final String id;
|
||||
@override
|
||||
final String chatId;
|
||||
@override
|
||||
final String senderId;
|
||||
@override
|
||||
final String content;
|
||||
@override
|
||||
final String messageType;
|
||||
// 'text', 'image', 'video', 'audio', 'file'
|
||||
@override
|
||||
final DateTime? createdAt;
|
||||
@override
|
||||
final DateTime? updatedAt;
|
||||
@override
|
||||
final bool? isRead;
|
||||
final Map<String, dynamic>? _media;
|
||||
@override
|
||||
Map<String, dynamic>? get media {
|
||||
final value = _media;
|
||||
if (value == null) return null;
|
||||
if (_media is EqualUnmodifiableMapView) return _media;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(value);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Message(id: $id, chatId: $chatId, senderId: $senderId, content: $content, messageType: $messageType, createdAt: $createdAt, updatedAt: $updatedAt, isRead: $isRead, media: $media)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$MessageImpl &&
|
||||
(identical(other.id, id) || other.id == id) &&
|
||||
(identical(other.chatId, chatId) || other.chatId == chatId) &&
|
||||
(identical(other.senderId, senderId) ||
|
||||
other.senderId == senderId) &&
|
||||
(identical(other.content, content) || other.content == content) &&
|
||||
(identical(other.messageType, messageType) ||
|
||||
other.messageType == messageType) &&
|
||||
(identical(other.createdAt, createdAt) ||
|
||||
other.createdAt == createdAt) &&
|
||||
(identical(other.updatedAt, updatedAt) ||
|
||||
other.updatedAt == updatedAt) &&
|
||||
(identical(other.isRead, isRead) || other.isRead == isRead) &&
|
||||
const DeepCollectionEquality().equals(other._media, _media));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
id,
|
||||
chatId,
|
||||
senderId,
|
||||
content,
|
||||
messageType,
|
||||
createdAt,
|
||||
updatedAt,
|
||||
isRead,
|
||||
const DeepCollectionEquality().hash(_media));
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$MessageImplCopyWith<_$MessageImpl> get copyWith =>
|
||||
__$$MessageImplCopyWithImpl<_$MessageImpl>(this, _$identity);
|
||||
}
|
||||
|
||||
abstract class _Message implements Message {
|
||||
const factory _Message(
|
||||
{required final String id,
|
||||
required final String chatId,
|
||||
required final String senderId,
|
||||
required final String content,
|
||||
required final String messageType,
|
||||
final DateTime? createdAt,
|
||||
final DateTime? updatedAt,
|
||||
final bool? isRead,
|
||||
final Map<String, dynamic>? media}) = _$MessageImpl;
|
||||
|
||||
@override
|
||||
String get id;
|
||||
@override
|
||||
String get chatId;
|
||||
@override
|
||||
String get senderId;
|
||||
@override
|
||||
String get content;
|
||||
@override
|
||||
String get messageType;
|
||||
@override // 'text', 'image', 'video', 'audio', 'file'
|
||||
DateTime? get createdAt;
|
||||
@override
|
||||
DateTime? get updatedAt;
|
||||
@override
|
||||
bool? get isRead;
|
||||
@override
|
||||
Map<String, dynamic>? get media;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$MessageImplCopyWith<_$MessageImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
18
client-mobile/lib/features/chat/domain/entities/user.dart
Normal file
18
client-mobile/lib/features/chat/domain/entities/user.dart
Normal file
@@ -0,0 +1,18 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'user.freezed.dart';
|
||||
// part 'user.g.dart';
|
||||
|
||||
@freezed
|
||||
class User with _$User {
|
||||
const factory User({
|
||||
required String id,
|
||||
required String name,
|
||||
String? avatarUrl,
|
||||
String? role, // 'admin', 'member'
|
||||
bool? isOnline,
|
||||
DateTime? lastSeen,
|
||||
}) = _User;
|
||||
|
||||
// factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
// 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 'user.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 _$User {
|
||||
String get id => throw _privateConstructorUsedError;
|
||||
String get name => throw _privateConstructorUsedError;
|
||||
String? get avatarUrl => throw _privateConstructorUsedError;
|
||||
String? get role => throw _privateConstructorUsedError; // 'admin', 'member'
|
||||
bool? get isOnline => throw _privateConstructorUsedError;
|
||||
DateTime? get lastSeen => throw _privateConstructorUsedError;
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
$UserCopyWith<User> get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $UserCopyWith<$Res> {
|
||||
factory $UserCopyWith(User value, $Res Function(User) then) =
|
||||
_$UserCopyWithImpl<$Res, User>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{String id,
|
||||
String name,
|
||||
String? avatarUrl,
|
||||
String? role,
|
||||
bool? isOnline,
|
||||
DateTime? lastSeen});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$UserCopyWithImpl<$Res, $Val extends User>
|
||||
implements $UserCopyWith<$Res> {
|
||||
_$UserCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? id = null,
|
||||
Object? name = null,
|
||||
Object? avatarUrl = freezed,
|
||||
Object? role = freezed,
|
||||
Object? isOnline = freezed,
|
||||
Object? lastSeen = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
id: null == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
name: null == name
|
||||
? _value.name
|
||||
: name // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
avatarUrl: freezed == avatarUrl
|
||||
? _value.avatarUrl
|
||||
: avatarUrl // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
role: freezed == role
|
||||
? _value.role
|
||||
: role // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
isOnline: freezed == isOnline
|
||||
? _value.isOnline
|
||||
: isOnline // ignore: cast_nullable_to_non_nullable
|
||||
as bool?,
|
||||
lastSeen: freezed == lastSeen
|
||||
? _value.lastSeen
|
||||
: lastSeen // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$UserImplCopyWith<$Res> implements $UserCopyWith<$Res> {
|
||||
factory _$$UserImplCopyWith(
|
||||
_$UserImpl value, $Res Function(_$UserImpl) then) =
|
||||
__$$UserImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{String id,
|
||||
String name,
|
||||
String? avatarUrl,
|
||||
String? role,
|
||||
bool? isOnline,
|
||||
DateTime? lastSeen});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$UserImplCopyWithImpl<$Res>
|
||||
extends _$UserCopyWithImpl<$Res, _$UserImpl>
|
||||
implements _$$UserImplCopyWith<$Res> {
|
||||
__$$UserImplCopyWithImpl(_$UserImpl _value, $Res Function(_$UserImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? id = null,
|
||||
Object? name = null,
|
||||
Object? avatarUrl = freezed,
|
||||
Object? role = freezed,
|
||||
Object? isOnline = freezed,
|
||||
Object? lastSeen = freezed,
|
||||
}) {
|
||||
return _then(_$UserImpl(
|
||||
id: null == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
name: null == name
|
||||
? _value.name
|
||||
: name // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
avatarUrl: freezed == avatarUrl
|
||||
? _value.avatarUrl
|
||||
: avatarUrl // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
role: freezed == role
|
||||
? _value.role
|
||||
: role // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
isOnline: freezed == isOnline
|
||||
? _value.isOnline
|
||||
: isOnline // ignore: cast_nullable_to_non_nullable
|
||||
as bool?,
|
||||
lastSeen: freezed == lastSeen
|
||||
? _value.lastSeen
|
||||
: lastSeen // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$UserImpl implements _User {
|
||||
const _$UserImpl(
|
||||
{required this.id,
|
||||
required this.name,
|
||||
this.avatarUrl,
|
||||
this.role,
|
||||
this.isOnline,
|
||||
this.lastSeen});
|
||||
|
||||
@override
|
||||
final String id;
|
||||
@override
|
||||
final String name;
|
||||
@override
|
||||
final String? avatarUrl;
|
||||
@override
|
||||
final String? role;
|
||||
// 'admin', 'member'
|
||||
@override
|
||||
final bool? isOnline;
|
||||
@override
|
||||
final DateTime? lastSeen;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'User(id: $id, name: $name, avatarUrl: $avatarUrl, role: $role, isOnline: $isOnline, lastSeen: $lastSeen)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$UserImpl &&
|
||||
(identical(other.id, id) || other.id == id) &&
|
||||
(identical(other.name, name) || other.name == name) &&
|
||||
(identical(other.avatarUrl, avatarUrl) ||
|
||||
other.avatarUrl == avatarUrl) &&
|
||||
(identical(other.role, role) || other.role == role) &&
|
||||
(identical(other.isOnline, isOnline) ||
|
||||
other.isOnline == isOnline) &&
|
||||
(identical(other.lastSeen, lastSeen) ||
|
||||
other.lastSeen == lastSeen));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(runtimeType, id, name, avatarUrl, role, isOnline, lastSeen);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$UserImplCopyWith<_$UserImpl> get copyWith =>
|
||||
__$$UserImplCopyWithImpl<_$UserImpl>(this, _$identity);
|
||||
}
|
||||
|
||||
abstract class _User implements User {
|
||||
const factory _User(
|
||||
{required final String id,
|
||||
required final String name,
|
||||
final String? avatarUrl,
|
||||
final String? role,
|
||||
final bool? isOnline,
|
||||
final DateTime? lastSeen}) = _$UserImpl;
|
||||
|
||||
@override
|
||||
String get id;
|
||||
@override
|
||||
String get name;
|
||||
@override
|
||||
String? get avatarUrl;
|
||||
@override
|
||||
String? get role;
|
||||
@override // 'admin', 'member'
|
||||
bool? get isOnline;
|
||||
@override
|
||||
DateTime? get lastSeen;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$UserImplCopyWith<_$UserImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import '../../../../core/errors/result.dart';
|
||||
import '../entities/chat.dart';
|
||||
import '../entities/message.dart';
|
||||
|
||||
abstract class ChatRepository {
|
||||
Future<Result<List<Chat>>> getChats();
|
||||
Future<Result<Chat>> getChatById(String chatId);
|
||||
Future<Result<void>> createChat(String title, List<String> participantIds);
|
||||
Future<Result<void>> sendMessage(String chatId, Message message);
|
||||
Future<Result<List<Message>>> getMessages(String chatId, {int? limit, String? lastMessageId});
|
||||
Future<Result<void>> deleteChat(String chatId);
|
||||
Future<Result<void>> updateChat(String chatId, String title);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import '../../../../core/errors/result.dart';
|
||||
import '../repositories/chat_repository.dart';
|
||||
import '../entities/chat.dart';
|
||||
|
||||
class GetChatsUseCase {
|
||||
final ChatRepository _repository;
|
||||
|
||||
GetChatsUseCase(this._repository);
|
||||
|
||||
Future<Result<List<Chat>>> execute() {
|
||||
return _repository.getChats();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'chat_event.dart';
|
||||
import 'chat_state.dart';
|
||||
|
||||
class ChatBloc extends Bloc<ChatEvent, ChatState> {
|
||||
ChatBloc() : super(const ChatState.initial()) {
|
||||
on<ChatEventStarted>(_onStarted);
|
||||
on<ChatEventChatsLoaded>(_onChatsLoaded);
|
||||
on<ChatEventChatSelected>(_onChatSelected);
|
||||
on<ChatEventMessagesRequested>(_onMessagesRequested);
|
||||
on<ChatEventMessageSent>(_onMessageSent);
|
||||
}
|
||||
|
||||
Future<void> _onStarted(ChatEventStarted event, emit) async {
|
||||
emit(const ChatState.loading());
|
||||
emit(const ChatState.chatsLoaded([]));
|
||||
}
|
||||
|
||||
Future<void> _onChatsLoaded(ChatEventChatsLoaded event, emit) async {}
|
||||
Future<void> _onChatSelected(ChatEventChatSelected event, emit) async {}
|
||||
Future<void> _onMessagesRequested(ChatEventMessagesRequested event, emit) async {}
|
||||
Future<void> _onMessageSent(ChatEventMessageSent event, emit) async {}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'chat_event.freezed.dart';
|
||||
|
||||
@freezed
|
||||
class ChatEvent with _$ChatEvent {
|
||||
const factory ChatEvent.started() = ChatEventStarted;
|
||||
const factory ChatEvent.chatsLoaded() = ChatEventChatsLoaded;
|
||||
const factory ChatEvent.chatSelected(String chatId) = ChatEventChatSelected;
|
||||
const factory ChatEvent.messagesRequested(String chatId, {String? lastMessageId}) = ChatEventMessagesRequested;
|
||||
const factory ChatEvent.messageSent(String chatId, String content) = ChatEventMessageSent;
|
||||
const factory ChatEvent.messageRead(String chatId, String messageId) = ChatEventMessageRead;
|
||||
const factory ChatEvent.chatCreated(String title, List<String> participantIds) = ChatEventChatCreated;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,14 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'chat_state.freezed.dart';
|
||||
|
||||
@freezed
|
||||
class ChatState with _$ChatState {
|
||||
const factory ChatState.initial() = ChatInitial;
|
||||
const factory ChatState.loading() = ChatLoading;
|
||||
const factory ChatState.chatsLoaded(List<dynamic> chats) = _ChatsLoaded;
|
||||
const factory ChatState.chatSelected(String chat, List<dynamic> messages) = _ChatSelected;
|
||||
const factory ChatState.messagesLoaded(List<dynamic> messages) = _MessagesLoaded;
|
||||
const factory ChatState.messageSent() = _MessageSent;
|
||||
const factory ChatState.error(String message) = ChatError;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,105 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ChatDetailPage extends StatefulWidget {
|
||||
final String chatId;
|
||||
final String chatTitle;
|
||||
|
||||
const ChatDetailPage({
|
||||
super.key,
|
||||
required this.chatId,
|
||||
required this.chatTitle,
|
||||
});
|
||||
|
||||
@override
|
||||
State<ChatDetailPage> createState() => _ChatDetailPageState();
|
||||
}
|
||||
|
||||
class _ChatDetailPageState extends State<ChatDetailPage> {
|
||||
final _messageController = TextEditingController();
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_messageController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _sendMessage() {
|
||||
if (_messageController.text.trim().isEmpty) return;
|
||||
_messageController.clear();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(widget.chatTitle),
|
||||
),
|
||||
body: const Center(child: Text('Chat Detail')),
|
||||
bottomNavigationBar: _MessageInput(
|
||||
controller: _messageController,
|
||||
onSend: _sendMessage,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _MessageInput extends StatelessWidget {
|
||||
final TextEditingController controller;
|
||||
final VoidCallback onSend;
|
||||
|
||||
const _MessageInput({
|
||||
required this.controller,
|
||||
required this.onSend,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, -2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.attach_file),
|
||||
onPressed: () {},
|
||||
),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: controller,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Сообщение',
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
filled: true,
|
||||
fillColor: Colors.grey[200],
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 8,
|
||||
),
|
||||
),
|
||||
maxLines: null,
|
||||
onSubmitted: (_) => onSend(),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.send),
|
||||
color: Theme.of(context).primaryColor,
|
||||
onPressed: onSend,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import '../bloc/chat_bloc.dart';
|
||||
import '../bloc/chat_state.dart';
|
||||
|
||||
class ChatsPage extends StatelessWidget {
|
||||
const ChatsPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<ChatBloc, ChatState>(
|
||||
builder: (context, state) {
|
||||
return state.when(
|
||||
initial: () => const Center(child: CircularProgressIndicator()),
|
||||
loading: () => const Center(child: CircularProgressIndicator()),
|
||||
chatsLoaded: (_) => const Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(Icons.chat_bubble_outline, size: 64, color: Colors.grey),
|
||||
SizedBox(height: 16),
|
||||
Text('У вас пока нет чатов'),
|
||||
],
|
||||
),
|
||||
),
|
||||
chatSelected: (_, __) => const Center(child: Text('Chat selected')),
|
||||
messagesLoaded: (_) => const Center(child: Text('Messages loaded')),
|
||||
messageSent: () => const Center(child: Text('Message sent')),
|
||||
error: (message) => Center(child: Text('Ошибка: $message')),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'profile.freezed.dart';
|
||||
// part 'profile.g.dart';
|
||||
|
||||
@freezed
|
||||
class Profile with _$Profile {
|
||||
const factory Profile({
|
||||
required String id,
|
||||
required String userId,
|
||||
String? bio,
|
||||
String? avatarUrl,
|
||||
String? phoneNumber,
|
||||
String? email,
|
||||
DateTime? lastSeen,
|
||||
bool? isOnline,
|
||||
String? status,
|
||||
}) = _Profile;
|
||||
|
||||
// factory Profile.fromJson(Map<String, dynamic> json) => _$ProfileFromJson(json);
|
||||
}
|
||||
@@ -0,0 +1,298 @@
|
||||
// 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 'profile.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 _$Profile {
|
||||
String get id => throw _privateConstructorUsedError;
|
||||
String get userId => throw _privateConstructorUsedError;
|
||||
String? get bio => throw _privateConstructorUsedError;
|
||||
String? get avatarUrl => throw _privateConstructorUsedError;
|
||||
String? get phoneNumber => throw _privateConstructorUsedError;
|
||||
String? get email => throw _privateConstructorUsedError;
|
||||
DateTime? get lastSeen => throw _privateConstructorUsedError;
|
||||
bool? get isOnline => throw _privateConstructorUsedError;
|
||||
String? get status => throw _privateConstructorUsedError;
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
$ProfileCopyWith<Profile> get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $ProfileCopyWith<$Res> {
|
||||
factory $ProfileCopyWith(Profile value, $Res Function(Profile) then) =
|
||||
_$ProfileCopyWithImpl<$Res, Profile>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{String id,
|
||||
String userId,
|
||||
String? bio,
|
||||
String? avatarUrl,
|
||||
String? phoneNumber,
|
||||
String? email,
|
||||
DateTime? lastSeen,
|
||||
bool? isOnline,
|
||||
String? status});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$ProfileCopyWithImpl<$Res, $Val extends Profile>
|
||||
implements $ProfileCopyWith<$Res> {
|
||||
_$ProfileCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? id = null,
|
||||
Object? userId = null,
|
||||
Object? bio = freezed,
|
||||
Object? avatarUrl = freezed,
|
||||
Object? phoneNumber = freezed,
|
||||
Object? email = freezed,
|
||||
Object? lastSeen = freezed,
|
||||
Object? isOnline = freezed,
|
||||
Object? status = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
id: null == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
userId: null == userId
|
||||
? _value.userId
|
||||
: userId // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
bio: freezed == bio
|
||||
? _value.bio
|
||||
: bio // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
avatarUrl: freezed == avatarUrl
|
||||
? _value.avatarUrl
|
||||
: avatarUrl // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
phoneNumber: freezed == phoneNumber
|
||||
? _value.phoneNumber
|
||||
: phoneNumber // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
email: freezed == email
|
||||
? _value.email
|
||||
: email // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
lastSeen: freezed == lastSeen
|
||||
? _value.lastSeen
|
||||
: lastSeen // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,
|
||||
isOnline: freezed == isOnline
|
||||
? _value.isOnline
|
||||
: isOnline // ignore: cast_nullable_to_non_nullable
|
||||
as bool?,
|
||||
status: freezed == status
|
||||
? _value.status
|
||||
: status // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$ProfileImplCopyWith<$Res> implements $ProfileCopyWith<$Res> {
|
||||
factory _$$ProfileImplCopyWith(
|
||||
_$ProfileImpl value, $Res Function(_$ProfileImpl) then) =
|
||||
__$$ProfileImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{String id,
|
||||
String userId,
|
||||
String? bio,
|
||||
String? avatarUrl,
|
||||
String? phoneNumber,
|
||||
String? email,
|
||||
DateTime? lastSeen,
|
||||
bool? isOnline,
|
||||
String? status});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$ProfileImplCopyWithImpl<$Res>
|
||||
extends _$ProfileCopyWithImpl<$Res, _$ProfileImpl>
|
||||
implements _$$ProfileImplCopyWith<$Res> {
|
||||
__$$ProfileImplCopyWithImpl(
|
||||
_$ProfileImpl _value, $Res Function(_$ProfileImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? id = null,
|
||||
Object? userId = null,
|
||||
Object? bio = freezed,
|
||||
Object? avatarUrl = freezed,
|
||||
Object? phoneNumber = freezed,
|
||||
Object? email = freezed,
|
||||
Object? lastSeen = freezed,
|
||||
Object? isOnline = freezed,
|
||||
Object? status = freezed,
|
||||
}) {
|
||||
return _then(_$ProfileImpl(
|
||||
id: null == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
userId: null == userId
|
||||
? _value.userId
|
||||
: userId // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
bio: freezed == bio
|
||||
? _value.bio
|
||||
: bio // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
avatarUrl: freezed == avatarUrl
|
||||
? _value.avatarUrl
|
||||
: avatarUrl // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
phoneNumber: freezed == phoneNumber
|
||||
? _value.phoneNumber
|
||||
: phoneNumber // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
email: freezed == email
|
||||
? _value.email
|
||||
: email // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
lastSeen: freezed == lastSeen
|
||||
? _value.lastSeen
|
||||
: lastSeen // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,
|
||||
isOnline: freezed == isOnline
|
||||
? _value.isOnline
|
||||
: isOnline // ignore: cast_nullable_to_non_nullable
|
||||
as bool?,
|
||||
status: freezed == status
|
||||
? _value.status
|
||||
: status // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$ProfileImpl implements _Profile {
|
||||
const _$ProfileImpl(
|
||||
{required this.id,
|
||||
required this.userId,
|
||||
this.bio,
|
||||
this.avatarUrl,
|
||||
this.phoneNumber,
|
||||
this.email,
|
||||
this.lastSeen,
|
||||
this.isOnline,
|
||||
this.status});
|
||||
|
||||
@override
|
||||
final String id;
|
||||
@override
|
||||
final String userId;
|
||||
@override
|
||||
final String? bio;
|
||||
@override
|
||||
final String? avatarUrl;
|
||||
@override
|
||||
final String? phoneNumber;
|
||||
@override
|
||||
final String? email;
|
||||
@override
|
||||
final DateTime? lastSeen;
|
||||
@override
|
||||
final bool? isOnline;
|
||||
@override
|
||||
final String? status;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Profile(id: $id, userId: $userId, bio: $bio, avatarUrl: $avatarUrl, phoneNumber: $phoneNumber, email: $email, lastSeen: $lastSeen, isOnline: $isOnline, status: $status)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$ProfileImpl &&
|
||||
(identical(other.id, id) || other.id == id) &&
|
||||
(identical(other.userId, userId) || other.userId == userId) &&
|
||||
(identical(other.bio, bio) || other.bio == bio) &&
|
||||
(identical(other.avatarUrl, avatarUrl) ||
|
||||
other.avatarUrl == avatarUrl) &&
|
||||
(identical(other.phoneNumber, phoneNumber) ||
|
||||
other.phoneNumber == phoneNumber) &&
|
||||
(identical(other.email, email) || other.email == email) &&
|
||||
(identical(other.lastSeen, lastSeen) ||
|
||||
other.lastSeen == lastSeen) &&
|
||||
(identical(other.isOnline, isOnline) ||
|
||||
other.isOnline == isOnline) &&
|
||||
(identical(other.status, status) || other.status == status));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, id, userId, bio, avatarUrl,
|
||||
phoneNumber, email, lastSeen, isOnline, status);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$ProfileImplCopyWith<_$ProfileImpl> get copyWith =>
|
||||
__$$ProfileImplCopyWithImpl<_$ProfileImpl>(this, _$identity);
|
||||
}
|
||||
|
||||
abstract class _Profile implements Profile {
|
||||
const factory _Profile(
|
||||
{required final String id,
|
||||
required final String userId,
|
||||
final String? bio,
|
||||
final String? avatarUrl,
|
||||
final String? phoneNumber,
|
||||
final String? email,
|
||||
final DateTime? lastSeen,
|
||||
final bool? isOnline,
|
||||
final String? status}) = _$ProfileImpl;
|
||||
|
||||
@override
|
||||
String get id;
|
||||
@override
|
||||
String get userId;
|
||||
@override
|
||||
String? get bio;
|
||||
@override
|
||||
String? get avatarUrl;
|
||||
@override
|
||||
String? get phoneNumber;
|
||||
@override
|
||||
String? get email;
|
||||
@override
|
||||
DateTime? get lastSeen;
|
||||
@override
|
||||
bool? get isOnline;
|
||||
@override
|
||||
String? get status;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$ProfileImplCopyWith<_$ProfileImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import '../../../../core/errors/result.dart';
|
||||
import '../entities/profile.dart';
|
||||
|
||||
abstract class ProfileRepository {
|
||||
Future<Result<Profile>> getProfile(String userId);
|
||||
Future<Result<Profile>> updateProfile(Map<String, dynamic> data);
|
||||
Future<Result<void>> uploadAvatar(String imagePath);
|
||||
Future<Result<void>> updateStatus(String status);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import '../../../../core/errors/result.dart';
|
||||
import '../repositories/profile_repository.dart';
|
||||
import '../entities/profile.dart';
|
||||
|
||||
class GetProfileUseCase {
|
||||
final ProfileRepository _repository;
|
||||
|
||||
GetProfileUseCase(this._repository);
|
||||
|
||||
Future<Result<Profile>> execute(String userId) {
|
||||
return _repository.getProfile(userId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import 'dart:convert';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import '../../../../core/constants/storage_keys.dart';
|
||||
import '../../domain/entities/server_config.dart';
|
||||
|
||||
abstract class SettingsLocalDataSource {
|
||||
Future<String?> getApiUrl();
|
||||
Future<void> saveApiUrl(String url);
|
||||
Future<String?> getLanguageCode();
|
||||
Future<void> saveLanguageCode(String code);
|
||||
Future<ServerConfig?> getServerConfig();
|
||||
Future<void> saveServerConfig(ServerConfig config);
|
||||
}
|
||||
|
||||
class SettingsLocalDataSourceImpl implements SettingsLocalDataSource {
|
||||
final SharedPreferences _prefs;
|
||||
|
||||
SettingsLocalDataSourceImpl(this._prefs);
|
||||
|
||||
@override
|
||||
Future<String?> getApiUrl() async {
|
||||
return _prefs.getString(StorageKeys.apiUrl);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> saveApiUrl(String url) async {
|
||||
await _prefs.setString(StorageKeys.apiUrl, url);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String?> getLanguageCode() async {
|
||||
return _prefs.getString(StorageKeys.languageCode);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> saveLanguageCode(String code) async {
|
||||
await _prefs.setString(StorageKeys.languageCode, code);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ServerConfig?> getServerConfig() async {
|
||||
final jsonString = _prefs.getString(StorageKeys.serverConfig);
|
||||
if (jsonString == null) return null;
|
||||
try {
|
||||
final json = jsonDecode(jsonString) as Map<String, dynamic>;
|
||||
return ServerConfig.fromJson(json);
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> saveServerConfig(ServerConfig config) async {
|
||||
final jsonString = jsonEncode(config.toJson());
|
||||
await _prefs.setString(StorageKeys.serverConfig, jsonString);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import '../../../../core/errors/errors.dart';
|
||||
import '../../../../core/errors/result.dart';
|
||||
import '../../domain/entities/server_config.dart';
|
||||
|
||||
abstract class SettingsRemoteDataSource {
|
||||
Future<Result<ServerConfig>> getServerConfig();
|
||||
}
|
||||
|
||||
class SettingsRemoteDataSourceImpl implements SettingsRemoteDataSource {
|
||||
final Dio _dio;
|
||||
|
||||
SettingsRemoteDataSourceImpl(this._dio);
|
||||
|
||||
@override
|
||||
Future<Result<ServerConfig>> getServerConfig() async {
|
||||
try {
|
||||
final response = await _dio.get('/api/config');
|
||||
if (response.statusCode == 200) {
|
||||
final config = ServerConfig.fromJson(response.data as Map<String, dynamic>);
|
||||
return Result.success(config);
|
||||
}
|
||||
return Result.failure(AppError.server(statusCode: 500, message: 'Failed to load config'));
|
||||
} on DioException catch (e) {
|
||||
return Result.failure(AppError.network(message: e.message));
|
||||
} catch (e) {
|
||||
return Result.failure(const AppError.unknown(message: 'Unknown error'));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
import '../../../../core/errors/errors.dart';
|
||||
import '../../../../core/errors/result.dart';
|
||||
import '../../domain/entities/server_config.dart';
|
||||
import '../../domain/repositories/settings_repository.dart';
|
||||
import '../datasources/settings_local_datasource.dart';
|
||||
import '../datasources/settings_remote_datasource.dart';
|
||||
|
||||
class SettingsRepositoryImpl implements SettingsRepository {
|
||||
final SettingsLocalDataSource _local;
|
||||
final SettingsRemoteDataSource _remote;
|
||||
|
||||
SettingsRepositoryImpl(this._local, this._remote);
|
||||
|
||||
@override
|
||||
Future<String?> getApiUrl() => _local.getApiUrl();
|
||||
|
||||
@override
|
||||
Future<Result<void>> saveApiUrl(String url) async {
|
||||
try {
|
||||
await _local.saveApiUrl(url);
|
||||
return const Result.success(null);
|
||||
} catch (e) {
|
||||
return const Result.failure(AppError.unknown(message: 'Failed to save API URL'));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String?> getLanguageCode() => _local.getLanguageCode();
|
||||
|
||||
@override
|
||||
Future<Result<void>> saveLanguageCode(String code) async {
|
||||
try {
|
||||
await _local.saveLanguageCode(code);
|
||||
return const Result.success(null);
|
||||
} catch (e) {
|
||||
return const Result.failure(AppError.unknown(message: 'Failed to save language'));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Result<ServerConfig>> getServerConfig() async {
|
||||
final local = await _local.getServerConfig();
|
||||
if (local != null) {
|
||||
return Result.success(local);
|
||||
}
|
||||
return refreshServerConfig();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Result<ServerConfig>> refreshServerConfig() async {
|
||||
final result = await _remote.getServerConfig();
|
||||
result.when(
|
||||
onSuccess: (config) async => await _local.saveServerConfig(config),
|
||||
onFailure: (_) {},
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Result<bool>> getNotificationsEnabled() async {
|
||||
return const Result.success(true);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Result<void>> setNotificationsEnabled(bool enabled) async {
|
||||
return const Result.success(null);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Result<bool>> getDarkModeEnabled() async {
|
||||
return const Result.success(false);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Result<void>> setDarkModeEnabled(bool enabled) async {
|
||||
return const Result.success(null);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Result<void>> clearAllData() async {
|
||||
return const Result.success(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'server_config.freezed.dart';
|
||||
part 'server_config.g.dart';
|
||||
|
||||
@freezed
|
||||
class ServerConfig with _$ServerConfig {
|
||||
const factory ServerConfig({
|
||||
required SystemConfig system,
|
||||
required StoriesConfig stories,
|
||||
required ChatsModuleConfig chats,
|
||||
required MessagesConfig messages,
|
||||
required WebRtcConfig webRtc,
|
||||
required KlipyConfig klipy,
|
||||
required ImportConfig import,
|
||||
required FederationConfig federation,
|
||||
}) = _ServerConfig;
|
||||
|
||||
factory ServerConfig.fromJson(Map<String, dynamic> json) =>
|
||||
_$ServerConfigFromJson(json);
|
||||
}
|
||||
|
||||
@Freezed(toJson: true)
|
||||
class SystemConfig with _$SystemConfig {
|
||||
const factory SystemConfig({
|
||||
required String domainUrl,
|
||||
required bool enableRegistration,
|
||||
}) = _SystemConfig;
|
||||
|
||||
factory SystemConfig.fromJson(Map<String, dynamic> json) =>
|
||||
_$SystemConfigFromJson(json);
|
||||
}
|
||||
|
||||
@Freezed(toJson: true)
|
||||
class StoriesConfig with _$StoriesConfig {
|
||||
const factory StoriesConfig({
|
||||
required bool enabled,
|
||||
required int maxStoriesPerPeriod,
|
||||
required int storyLifetimeHours,
|
||||
required bool textStoriesEnabled,
|
||||
required int textStoryDurationSeconds,
|
||||
required int mediaStoryMaxDurationSeconds,
|
||||
required int maxMediaSizeBytes,
|
||||
}) = _StoriesConfig;
|
||||
|
||||
factory StoriesConfig.fromJson(Map<String, dynamic> json) =>
|
||||
_$StoriesConfigFromJson(json);
|
||||
}
|
||||
|
||||
@Freezed(toJson: true)
|
||||
class ChatsModuleConfig with _$ChatsModuleConfig {
|
||||
const factory ChatsModuleConfig({
|
||||
required bool supportGroups,
|
||||
required int maxGroupParticipants,
|
||||
required bool allowChatToGroupConversion,
|
||||
required bool enableFolders,
|
||||
}) = _ChatsModuleConfig;
|
||||
|
||||
factory ChatsModuleConfig.fromJson(Map<String, dynamic> json) =>
|
||||
_$ChatsModuleConfigFromJson(json);
|
||||
}
|
||||
|
||||
@Freezed(toJson: true)
|
||||
class MessagesConfig with _$MessagesConfig {
|
||||
const factory MessagesConfig({
|
||||
required int dailyMessageLimitPerUser,
|
||||
required int chatMessageLimit,
|
||||
required bool allowMedia,
|
||||
required int maxMediaSizeBytes,
|
||||
required List<String> allowedMediaTypes,
|
||||
required bool allowVoiceMessages,
|
||||
required bool allowForwarding,
|
||||
required bool allowReactions,
|
||||
required bool allowReplies,
|
||||
required bool allowQuoting,
|
||||
required bool allowMessageDeletion,
|
||||
required bool forbidCopying,
|
||||
required bool allowLinks,
|
||||
required bool allowPolls,
|
||||
required bool allowPinning,
|
||||
}) = _MessagesConfig;
|
||||
|
||||
factory MessagesConfig.fromJson(Map<String, dynamic> json) =>
|
||||
_$MessagesConfigFromJson(json);
|
||||
}
|
||||
|
||||
@Freezed(toJson: true)
|
||||
class WebRtcConfig with _$WebRtcConfig {
|
||||
const factory WebRtcConfig({
|
||||
required bool enabled,
|
||||
required bool enableVoiceCalls,
|
||||
required bool enableVideoCalls,
|
||||
required bool enableScreenSharing,
|
||||
required String turnHost,
|
||||
required int turnPort,
|
||||
}) = _WebRtcConfig;
|
||||
|
||||
factory WebRtcConfig.fromJson(Map<String, dynamic> json) =>
|
||||
_$WebRtcConfigFromJson(json);
|
||||
}
|
||||
|
||||
@Freezed(toJson: true)
|
||||
class KlipyConfig with _$KlipyConfig {
|
||||
const factory KlipyConfig({
|
||||
required bool enabled,
|
||||
required String appName,
|
||||
}) = _KlipyConfig;
|
||||
|
||||
factory KlipyConfig.fromJson(Map<String, dynamic> json) =>
|
||||
_$KlipyConfigFromJson(json);
|
||||
}
|
||||
|
||||
@Freezed(toJson: true)
|
||||
class ImportConfig with _$ImportConfig {
|
||||
const factory ImportConfig({
|
||||
required bool enabled,
|
||||
}) = _ImportConfig;
|
||||
|
||||
factory ImportConfig.fromJson(Map<String, dynamic> json) =>
|
||||
_$ImportConfigFromJson(json);
|
||||
}
|
||||
|
||||
@Freezed(toJson: true)
|
||||
class FederationConfig with _$FederationConfig {
|
||||
const factory FederationConfig({
|
||||
required bool enabled,
|
||||
required String serverDescription,
|
||||
required List<FederationDomainConfig> allowedDomains,
|
||||
}) = _FederationConfig;
|
||||
|
||||
factory FederationConfig.fromJson(Map<String, dynamic> json) =>
|
||||
_$FederationConfigFromJson(json);
|
||||
}
|
||||
|
||||
@Freezed(toJson: true)
|
||||
class FederationDomainConfig with _$FederationDomainConfig {
|
||||
const factory FederationDomainConfig({
|
||||
required String domain,
|
||||
required bool enabled,
|
||||
}) = _FederationDomainConfig;
|
||||
|
||||
factory FederationDomainConfig.fromJson(Map<String, dynamic> json) =>
|
||||
_$FederationDomainConfigFromJson(json);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,204 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'server_config.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$ServerConfigImpl _$$ServerConfigImplFromJson(Map<String, dynamic> json) =>
|
||||
_$ServerConfigImpl(
|
||||
system: SystemConfig.fromJson(json['system'] as Map<String, dynamic>),
|
||||
stories: StoriesConfig.fromJson(json['stories'] as Map<String, dynamic>),
|
||||
chats: ChatsModuleConfig.fromJson(json['chats'] as Map<String, dynamic>),
|
||||
messages:
|
||||
MessagesConfig.fromJson(json['messages'] as Map<String, dynamic>),
|
||||
webRtc: WebRtcConfig.fromJson(json['webRtc'] as Map<String, dynamic>),
|
||||
klipy: KlipyConfig.fromJson(json['klipy'] as Map<String, dynamic>),
|
||||
import: ImportConfig.fromJson(json['import'] as Map<String, dynamic>),
|
||||
federation:
|
||||
FederationConfig.fromJson(json['federation'] as Map<String, dynamic>),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$ServerConfigImplToJson(_$ServerConfigImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'system': instance.system,
|
||||
'stories': instance.stories,
|
||||
'chats': instance.chats,
|
||||
'messages': instance.messages,
|
||||
'webRtc': instance.webRtc,
|
||||
'klipy': instance.klipy,
|
||||
'import': instance.import,
|
||||
'federation': instance.federation,
|
||||
};
|
||||
|
||||
_$SystemConfigImpl _$$SystemConfigImplFromJson(Map<String, dynamic> json) =>
|
||||
_$SystemConfigImpl(
|
||||
domainUrl: json['domainUrl'] as String,
|
||||
enableRegistration: json['enableRegistration'] as bool,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$SystemConfigImplToJson(_$SystemConfigImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'domainUrl': instance.domainUrl,
|
||||
'enableRegistration': instance.enableRegistration,
|
||||
};
|
||||
|
||||
_$StoriesConfigImpl _$$StoriesConfigImplFromJson(Map<String, dynamic> json) =>
|
||||
_$StoriesConfigImpl(
|
||||
enabled: json['enabled'] as bool,
|
||||
maxStoriesPerPeriod: (json['maxStoriesPerPeriod'] as num).toInt(),
|
||||
storyLifetimeHours: (json['storyLifetimeHours'] as num).toInt(),
|
||||
textStoriesEnabled: json['textStoriesEnabled'] as bool,
|
||||
textStoryDurationSeconds:
|
||||
(json['textStoryDurationSeconds'] as num).toInt(),
|
||||
mediaStoryMaxDurationSeconds:
|
||||
(json['mediaStoryMaxDurationSeconds'] as num).toInt(),
|
||||
maxMediaSizeBytes: (json['maxMediaSizeBytes'] as num).toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$StoriesConfigImplToJson(_$StoriesConfigImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'enabled': instance.enabled,
|
||||
'maxStoriesPerPeriod': instance.maxStoriesPerPeriod,
|
||||
'storyLifetimeHours': instance.storyLifetimeHours,
|
||||
'textStoriesEnabled': instance.textStoriesEnabled,
|
||||
'textStoryDurationSeconds': instance.textStoryDurationSeconds,
|
||||
'mediaStoryMaxDurationSeconds': instance.mediaStoryMaxDurationSeconds,
|
||||
'maxMediaSizeBytes': instance.maxMediaSizeBytes,
|
||||
};
|
||||
|
||||
_$ChatsModuleConfigImpl _$$ChatsModuleConfigImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$ChatsModuleConfigImpl(
|
||||
supportGroups: json['supportGroups'] as bool,
|
||||
maxGroupParticipants: (json['maxGroupParticipants'] as num).toInt(),
|
||||
allowChatToGroupConversion: json['allowChatToGroupConversion'] as bool,
|
||||
enableFolders: json['enableFolders'] as bool,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$ChatsModuleConfigImplToJson(
|
||||
_$ChatsModuleConfigImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'supportGroups': instance.supportGroups,
|
||||
'maxGroupParticipants': instance.maxGroupParticipants,
|
||||
'allowChatToGroupConversion': instance.allowChatToGroupConversion,
|
||||
'enableFolders': instance.enableFolders,
|
||||
};
|
||||
|
||||
_$MessagesConfigImpl _$$MessagesConfigImplFromJson(Map<String, dynamic> json) =>
|
||||
_$MessagesConfigImpl(
|
||||
dailyMessageLimitPerUser:
|
||||
(json['dailyMessageLimitPerUser'] as num).toInt(),
|
||||
chatMessageLimit: (json['chatMessageLimit'] as num).toInt(),
|
||||
allowMedia: json['allowMedia'] as bool,
|
||||
maxMediaSizeBytes: (json['maxMediaSizeBytes'] as num).toInt(),
|
||||
allowedMediaTypes: (json['allowedMediaTypes'] as List<dynamic>)
|
||||
.map((e) => e as String)
|
||||
.toList(),
|
||||
allowVoiceMessages: json['allowVoiceMessages'] as bool,
|
||||
allowForwarding: json['allowForwarding'] as bool,
|
||||
allowReactions: json['allowReactions'] as bool,
|
||||
allowReplies: json['allowReplies'] as bool,
|
||||
allowQuoting: json['allowQuoting'] as bool,
|
||||
allowMessageDeletion: json['allowMessageDeletion'] as bool,
|
||||
forbidCopying: json['forbidCopying'] as bool,
|
||||
allowLinks: json['allowLinks'] as bool,
|
||||
allowPolls: json['allowPolls'] as bool,
|
||||
allowPinning: json['allowPinning'] as bool,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$MessagesConfigImplToJson(
|
||||
_$MessagesConfigImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'dailyMessageLimitPerUser': instance.dailyMessageLimitPerUser,
|
||||
'chatMessageLimit': instance.chatMessageLimit,
|
||||
'allowMedia': instance.allowMedia,
|
||||
'maxMediaSizeBytes': instance.maxMediaSizeBytes,
|
||||
'allowedMediaTypes': instance.allowedMediaTypes,
|
||||
'allowVoiceMessages': instance.allowVoiceMessages,
|
||||
'allowForwarding': instance.allowForwarding,
|
||||
'allowReactions': instance.allowReactions,
|
||||
'allowReplies': instance.allowReplies,
|
||||
'allowQuoting': instance.allowQuoting,
|
||||
'allowMessageDeletion': instance.allowMessageDeletion,
|
||||
'forbidCopying': instance.forbidCopying,
|
||||
'allowLinks': instance.allowLinks,
|
||||
'allowPolls': instance.allowPolls,
|
||||
'allowPinning': instance.allowPinning,
|
||||
};
|
||||
|
||||
_$WebRtcConfigImpl _$$WebRtcConfigImplFromJson(Map<String, dynamic> json) =>
|
||||
_$WebRtcConfigImpl(
|
||||
enabled: json['enabled'] as bool,
|
||||
enableVoiceCalls: json['enableVoiceCalls'] as bool,
|
||||
enableVideoCalls: json['enableVideoCalls'] as bool,
|
||||
enableScreenSharing: json['enableScreenSharing'] as bool,
|
||||
turnHost: json['turnHost'] as String,
|
||||
turnPort: (json['turnPort'] as num).toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$WebRtcConfigImplToJson(_$WebRtcConfigImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'enabled': instance.enabled,
|
||||
'enableVoiceCalls': instance.enableVoiceCalls,
|
||||
'enableVideoCalls': instance.enableVideoCalls,
|
||||
'enableScreenSharing': instance.enableScreenSharing,
|
||||
'turnHost': instance.turnHost,
|
||||
'turnPort': instance.turnPort,
|
||||
};
|
||||
|
||||
_$KlipyConfigImpl _$$KlipyConfigImplFromJson(Map<String, dynamic> json) =>
|
||||
_$KlipyConfigImpl(
|
||||
enabled: json['enabled'] as bool,
|
||||
appName: json['appName'] as String,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$KlipyConfigImplToJson(_$KlipyConfigImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'enabled': instance.enabled,
|
||||
'appName': instance.appName,
|
||||
};
|
||||
|
||||
_$ImportConfigImpl _$$ImportConfigImplFromJson(Map<String, dynamic> json) =>
|
||||
_$ImportConfigImpl(
|
||||
enabled: json['enabled'] as bool,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$ImportConfigImplToJson(_$ImportConfigImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'enabled': instance.enabled,
|
||||
};
|
||||
|
||||
_$FederationConfigImpl _$$FederationConfigImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$FederationConfigImpl(
|
||||
enabled: json['enabled'] as bool,
|
||||
serverDescription: json['serverDescription'] as String,
|
||||
allowedDomains: (json['allowedDomains'] as List<dynamic>)
|
||||
.map(
|
||||
(e) => FederationDomainConfig.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$FederationConfigImplToJson(
|
||||
_$FederationConfigImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'enabled': instance.enabled,
|
||||
'serverDescription': instance.serverDescription,
|
||||
'allowedDomains': instance.allowedDomains,
|
||||
};
|
||||
|
||||
_$FederationDomainConfigImpl _$$FederationDomainConfigImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$FederationDomainConfigImpl(
|
||||
domain: json['domain'] as String,
|
||||
enabled: json['enabled'] as bool,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$FederationDomainConfigImplToJson(
|
||||
_$FederationDomainConfigImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'domain': instance.domain,
|
||||
'enabled': instance.enabled,
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'settings.freezed.dart';
|
||||
// part 'settings.g.dart';
|
||||
|
||||
@freezed
|
||||
class AppSettings with _$AppSettings {
|
||||
const factory AppSettings({
|
||||
required bool notificationsEnabled,
|
||||
required bool darkModeEnabled,
|
||||
required String language,
|
||||
bool? soundEnabled,
|
||||
bool? vibrationEnabled,
|
||||
String? themeColor,
|
||||
}) = _AppSettings;
|
||||
|
||||
// factory AppSettings.fromJson(Map<String, dynamic> json) => _$AppSettingsFromJson(json);
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
// 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.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 _$AppSettings {
|
||||
bool get notificationsEnabled => throw _privateConstructorUsedError;
|
||||
bool get darkModeEnabled => throw _privateConstructorUsedError;
|
||||
String get language => throw _privateConstructorUsedError;
|
||||
bool? get soundEnabled => throw _privateConstructorUsedError;
|
||||
bool? get vibrationEnabled => throw _privateConstructorUsedError;
|
||||
String? get themeColor => throw _privateConstructorUsedError;
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
$AppSettingsCopyWith<AppSettings> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $AppSettingsCopyWith<$Res> {
|
||||
factory $AppSettingsCopyWith(
|
||||
AppSettings value, $Res Function(AppSettings) then) =
|
||||
_$AppSettingsCopyWithImpl<$Res, AppSettings>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{bool notificationsEnabled,
|
||||
bool darkModeEnabled,
|
||||
String language,
|
||||
bool? soundEnabled,
|
||||
bool? vibrationEnabled,
|
||||
String? themeColor});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$AppSettingsCopyWithImpl<$Res, $Val extends AppSettings>
|
||||
implements $AppSettingsCopyWith<$Res> {
|
||||
_$AppSettingsCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? notificationsEnabled = null,
|
||||
Object? darkModeEnabled = null,
|
||||
Object? language = null,
|
||||
Object? soundEnabled = freezed,
|
||||
Object? vibrationEnabled = freezed,
|
||||
Object? themeColor = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
notificationsEnabled: null == notificationsEnabled
|
||||
? _value.notificationsEnabled
|
||||
: notificationsEnabled // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
darkModeEnabled: null == darkModeEnabled
|
||||
? _value.darkModeEnabled
|
||||
: darkModeEnabled // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
language: null == language
|
||||
? _value.language
|
||||
: language // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
soundEnabled: freezed == soundEnabled
|
||||
? _value.soundEnabled
|
||||
: soundEnabled // ignore: cast_nullable_to_non_nullable
|
||||
as bool?,
|
||||
vibrationEnabled: freezed == vibrationEnabled
|
||||
? _value.vibrationEnabled
|
||||
: vibrationEnabled // ignore: cast_nullable_to_non_nullable
|
||||
as bool?,
|
||||
themeColor: freezed == themeColor
|
||||
? _value.themeColor
|
||||
: themeColor // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$AppSettingsImplCopyWith<$Res>
|
||||
implements $AppSettingsCopyWith<$Res> {
|
||||
factory _$$AppSettingsImplCopyWith(
|
||||
_$AppSettingsImpl value, $Res Function(_$AppSettingsImpl) then) =
|
||||
__$$AppSettingsImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{bool notificationsEnabled,
|
||||
bool darkModeEnabled,
|
||||
String language,
|
||||
bool? soundEnabled,
|
||||
bool? vibrationEnabled,
|
||||
String? themeColor});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$AppSettingsImplCopyWithImpl<$Res>
|
||||
extends _$AppSettingsCopyWithImpl<$Res, _$AppSettingsImpl>
|
||||
implements _$$AppSettingsImplCopyWith<$Res> {
|
||||
__$$AppSettingsImplCopyWithImpl(
|
||||
_$AppSettingsImpl _value, $Res Function(_$AppSettingsImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? notificationsEnabled = null,
|
||||
Object? darkModeEnabled = null,
|
||||
Object? language = null,
|
||||
Object? soundEnabled = freezed,
|
||||
Object? vibrationEnabled = freezed,
|
||||
Object? themeColor = freezed,
|
||||
}) {
|
||||
return _then(_$AppSettingsImpl(
|
||||
notificationsEnabled: null == notificationsEnabled
|
||||
? _value.notificationsEnabled
|
||||
: notificationsEnabled // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
darkModeEnabled: null == darkModeEnabled
|
||||
? _value.darkModeEnabled
|
||||
: darkModeEnabled // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
language: null == language
|
||||
? _value.language
|
||||
: language // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
soundEnabled: freezed == soundEnabled
|
||||
? _value.soundEnabled
|
||||
: soundEnabled // ignore: cast_nullable_to_non_nullable
|
||||
as bool?,
|
||||
vibrationEnabled: freezed == vibrationEnabled
|
||||
? _value.vibrationEnabled
|
||||
: vibrationEnabled // ignore: cast_nullable_to_non_nullable
|
||||
as bool?,
|
||||
themeColor: freezed == themeColor
|
||||
? _value.themeColor
|
||||
: themeColor // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$AppSettingsImpl implements _AppSettings {
|
||||
const _$AppSettingsImpl(
|
||||
{required this.notificationsEnabled,
|
||||
required this.darkModeEnabled,
|
||||
required this.language,
|
||||
this.soundEnabled,
|
||||
this.vibrationEnabled,
|
||||
this.themeColor});
|
||||
|
||||
@override
|
||||
final bool notificationsEnabled;
|
||||
@override
|
||||
final bool darkModeEnabled;
|
||||
@override
|
||||
final String language;
|
||||
@override
|
||||
final bool? soundEnabled;
|
||||
@override
|
||||
final bool? vibrationEnabled;
|
||||
@override
|
||||
final String? themeColor;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AppSettings(notificationsEnabled: $notificationsEnabled, darkModeEnabled: $darkModeEnabled, language: $language, soundEnabled: $soundEnabled, vibrationEnabled: $vibrationEnabled, themeColor: $themeColor)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$AppSettingsImpl &&
|
||||
(identical(other.notificationsEnabled, notificationsEnabled) ||
|
||||
other.notificationsEnabled == notificationsEnabled) &&
|
||||
(identical(other.darkModeEnabled, darkModeEnabled) ||
|
||||
other.darkModeEnabled == darkModeEnabled) &&
|
||||
(identical(other.language, language) ||
|
||||
other.language == language) &&
|
||||
(identical(other.soundEnabled, soundEnabled) ||
|
||||
other.soundEnabled == soundEnabled) &&
|
||||
(identical(other.vibrationEnabled, vibrationEnabled) ||
|
||||
other.vibrationEnabled == vibrationEnabled) &&
|
||||
(identical(other.themeColor, themeColor) ||
|
||||
other.themeColor == themeColor));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, notificationsEnabled,
|
||||
darkModeEnabled, language, soundEnabled, vibrationEnabled, themeColor);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$AppSettingsImplCopyWith<_$AppSettingsImpl> get copyWith =>
|
||||
__$$AppSettingsImplCopyWithImpl<_$AppSettingsImpl>(this, _$identity);
|
||||
}
|
||||
|
||||
abstract class _AppSettings implements AppSettings {
|
||||
const factory _AppSettings(
|
||||
{required final bool notificationsEnabled,
|
||||
required final bool darkModeEnabled,
|
||||
required final String language,
|
||||
final bool? soundEnabled,
|
||||
final bool? vibrationEnabled,
|
||||
final String? themeColor}) = _$AppSettingsImpl;
|
||||
|
||||
@override
|
||||
bool get notificationsEnabled;
|
||||
@override
|
||||
bool get darkModeEnabled;
|
||||
@override
|
||||
String get language;
|
||||
@override
|
||||
bool? get soundEnabled;
|
||||
@override
|
||||
bool? get vibrationEnabled;
|
||||
@override
|
||||
String? get themeColor;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$AppSettingsImplCopyWith<_$AppSettingsImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import '../../../../core/errors/result.dart';
|
||||
import '../entities/server_config.dart';
|
||||
|
||||
abstract class SettingsRepository {
|
||||
Future<String?> getApiUrl();
|
||||
Future<Result<void>> saveApiUrl(String url);
|
||||
Future<String?> getLanguageCode();
|
||||
Future<Result<void>> saveLanguageCode(String code);
|
||||
Future<Result<ServerConfig>> getServerConfig();
|
||||
Future<Result<void>> refreshServerConfig();
|
||||
Future<Result<bool>> getNotificationsEnabled();
|
||||
Future<Result<void>> setNotificationsEnabled(bool enabled);
|
||||
Future<Result<bool>> getDarkModeEnabled();
|
||||
Future<Result<void>> setDarkModeEnabled(bool enabled);
|
||||
Future<Result<void>> clearAllData();
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import '../../../../core/errors/result.dart';
|
||||
import '../repositories/settings_repository.dart';
|
||||
|
||||
class GetSettingsUseCase {
|
||||
final SettingsRepository _repository;
|
||||
|
||||
GetSettingsUseCase(this._repository);
|
||||
|
||||
Future<Result<String?>> execute() async {
|
||||
final language = await _repository.getLanguageCode();
|
||||
return Result.success(language);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import '../../domain/repositories/settings_repository.dart';
|
||||
import 'settings_event.dart';
|
||||
import 'settings_state.dart';
|
||||
|
||||
class SettingsBloc extends Bloc<SettingsEvent, SettingsState> {
|
||||
final SettingsRepository _repository;
|
||||
|
||||
SettingsBloc(this._repository) : super(const SettingsState.initial()) {
|
||||
on<SettingsStarted>(_onStarted);
|
||||
on<SettingsConfigRequested>(_onConfigRequested);
|
||||
on<SettingsApiUrlChanged>(_onApiUrlChanged);
|
||||
on<SettingsApiUrlSaved>(_onApiUrlSaved);
|
||||
on<SettingsLanguageChanged>(_onLanguageChanged);
|
||||
on<SettingsRefreshConfig>(_onRefreshConfig);
|
||||
}
|
||||
|
||||
Future<void> _onStarted(SettingsStarted event, emit) async {
|
||||
emit(const SettingsState.loading());
|
||||
|
||||
final apiUrl = await _repository.getApiUrl() ?? '';
|
||||
final languageCode = await _repository.getLanguageCode() ?? 'ru';
|
||||
final configResult = await _repository.getServerConfig();
|
||||
|
||||
configResult.when(
|
||||
onSuccess: (config) {
|
||||
emit(SettingsState.loaded(
|
||||
apiUrl: apiUrl,
|
||||
serverConfig: config,
|
||||
languageCode: languageCode,
|
||||
));
|
||||
},
|
||||
onFailure: (error) {
|
||||
emit(SettingsState.loaded(
|
||||
apiUrl: apiUrl,
|
||||
serverConfig: null,
|
||||
languageCode: languageCode,
|
||||
error: 'Failed to load server config',
|
||||
));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onConfigRequested(SettingsConfigRequested event, emit) async {
|
||||
if (state is! SettingsLoaded) return;
|
||||
final currentState = state as SettingsLoaded;
|
||||
|
||||
emit(const SettingsState.loading());
|
||||
final configResult = await _repository.getServerConfig();
|
||||
|
||||
configResult.when(
|
||||
onSuccess: (config) {
|
||||
emit(SettingsState.loaded(
|
||||
apiUrl: currentState.apiUrl,
|
||||
serverConfig: config,
|
||||
languageCode: currentState.languageCode,
|
||||
));
|
||||
},
|
||||
onFailure: (error) {
|
||||
emit(SettingsState.loaded(
|
||||
apiUrl: currentState.apiUrl,
|
||||
serverConfig: null,
|
||||
languageCode: currentState.languageCode,
|
||||
error: 'Failed to refresh config',
|
||||
));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void _onApiUrlChanged(SettingsApiUrlChanged event, emit) {
|
||||
if (state is! SettingsLoaded) return;
|
||||
final currentState = state as SettingsLoaded;
|
||||
emit(SettingsState.loaded(
|
||||
apiUrl: event.url,
|
||||
serverConfig: currentState.serverConfig,
|
||||
languageCode: currentState.languageCode,
|
||||
));
|
||||
}
|
||||
|
||||
Future<void> _onApiUrlSaved(SettingsApiUrlSaved event, emit) async {
|
||||
if (state is! SettingsLoaded) return;
|
||||
final currentState = state as SettingsLoaded;
|
||||
|
||||
await _repository.saveApiUrl(event.url);
|
||||
|
||||
emit(SettingsState.loaded(
|
||||
apiUrl: event.url,
|
||||
serverConfig: currentState.serverConfig,
|
||||
languageCode: currentState.languageCode,
|
||||
));
|
||||
}
|
||||
|
||||
Future<void> _onLanguageChanged(SettingsLanguageChanged event, emit) async {
|
||||
if (state is! SettingsLoaded) return;
|
||||
final currentState = state as SettingsLoaded;
|
||||
|
||||
await _repository.saveLanguageCode(event.code);
|
||||
|
||||
emit(SettingsState.loaded(
|
||||
apiUrl: currentState.apiUrl,
|
||||
serverConfig: currentState.serverConfig,
|
||||
languageCode: event.code,
|
||||
));
|
||||
}
|
||||
|
||||
Future<void> _onRefreshConfig(SettingsRefreshConfig event, emit) async {
|
||||
add(const SettingsConfigRequested());
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'settings_event.freezed.dart';
|
||||
|
||||
@freezed
|
||||
class SettingsEvent with _$SettingsEvent {
|
||||
const factory SettingsEvent.started() = SettingsStarted;
|
||||
const factory SettingsEvent.configRequested() = SettingsConfigRequested;
|
||||
const factory SettingsEvent.apiUrlChanged(String url) = SettingsApiUrlChanged;
|
||||
const factory SettingsEvent.apiUrlSaved(String url) = SettingsApiUrlSaved;
|
||||
const factory SettingsEvent.languageChanged(String code) = SettingsLanguageChanged;
|
||||
const factory SettingsEvent.refreshConfig() = SettingsRefreshConfig;
|
||||
}
|
||||
@@ -0,0 +1,962 @@
|
||||
// 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_event.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 _$SettingsEvent {
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() started,
|
||||
required TResult Function() configRequested,
|
||||
required TResult Function(String url) apiUrlChanged,
|
||||
required TResult Function(String url) apiUrlSaved,
|
||||
required TResult Function(String code) languageChanged,
|
||||
required TResult Function() refreshConfig,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? started,
|
||||
TResult? Function()? configRequested,
|
||||
TResult? Function(String url)? apiUrlChanged,
|
||||
TResult? Function(String url)? apiUrlSaved,
|
||||
TResult? Function(String code)? languageChanged,
|
||||
TResult? Function()? refreshConfig,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? started,
|
||||
TResult Function()? configRequested,
|
||||
TResult Function(String url)? apiUrlChanged,
|
||||
TResult Function(String url)? apiUrlSaved,
|
||||
TResult Function(String code)? languageChanged,
|
||||
TResult Function()? refreshConfig,
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(SettingsStarted value) started,
|
||||
required TResult Function(SettingsConfigRequested value) configRequested,
|
||||
required TResult Function(SettingsApiUrlChanged value) apiUrlChanged,
|
||||
required TResult Function(SettingsApiUrlSaved value) apiUrlSaved,
|
||||
required TResult Function(SettingsLanguageChanged value) languageChanged,
|
||||
required TResult Function(SettingsRefreshConfig value) refreshConfig,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(SettingsStarted value)? started,
|
||||
TResult? Function(SettingsConfigRequested value)? configRequested,
|
||||
TResult? Function(SettingsApiUrlChanged value)? apiUrlChanged,
|
||||
TResult? Function(SettingsApiUrlSaved value)? apiUrlSaved,
|
||||
TResult? Function(SettingsLanguageChanged value)? languageChanged,
|
||||
TResult? Function(SettingsRefreshConfig value)? refreshConfig,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(SettingsStarted value)? started,
|
||||
TResult Function(SettingsConfigRequested value)? configRequested,
|
||||
TResult Function(SettingsApiUrlChanged value)? apiUrlChanged,
|
||||
TResult Function(SettingsApiUrlSaved value)? apiUrlSaved,
|
||||
TResult Function(SettingsLanguageChanged value)? languageChanged,
|
||||
TResult Function(SettingsRefreshConfig value)? refreshConfig,
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $SettingsEventCopyWith<$Res> {
|
||||
factory $SettingsEventCopyWith(
|
||||
SettingsEvent value, $Res Function(SettingsEvent) then) =
|
||||
_$SettingsEventCopyWithImpl<$Res, SettingsEvent>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$SettingsEventCopyWithImpl<$Res, $Val extends SettingsEvent>
|
||||
implements $SettingsEventCopyWith<$Res> {
|
||||
_$SettingsEventCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$SettingsStartedImplCopyWith<$Res> {
|
||||
factory _$$SettingsStartedImplCopyWith(_$SettingsStartedImpl value,
|
||||
$Res Function(_$SettingsStartedImpl) then) =
|
||||
__$$SettingsStartedImplCopyWithImpl<$Res>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$SettingsStartedImplCopyWithImpl<$Res>
|
||||
extends _$SettingsEventCopyWithImpl<$Res, _$SettingsStartedImpl>
|
||||
implements _$$SettingsStartedImplCopyWith<$Res> {
|
||||
__$$SettingsStartedImplCopyWithImpl(
|
||||
_$SettingsStartedImpl _value, $Res Function(_$SettingsStartedImpl) _then)
|
||||
: super(_value, _then);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$SettingsStartedImpl implements SettingsStarted {
|
||||
const _$SettingsStartedImpl();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SettingsEvent.started()';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _$SettingsStartedImpl);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => runtimeType.hashCode;
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() started,
|
||||
required TResult Function() configRequested,
|
||||
required TResult Function(String url) apiUrlChanged,
|
||||
required TResult Function(String url) apiUrlSaved,
|
||||
required TResult Function(String code) languageChanged,
|
||||
required TResult Function() refreshConfig,
|
||||
}) {
|
||||
return started();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? started,
|
||||
TResult? Function()? configRequested,
|
||||
TResult? Function(String url)? apiUrlChanged,
|
||||
TResult? Function(String url)? apiUrlSaved,
|
||||
TResult? Function(String code)? languageChanged,
|
||||
TResult? Function()? refreshConfig,
|
||||
}) {
|
||||
return started?.call();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? started,
|
||||
TResult Function()? configRequested,
|
||||
TResult Function(String url)? apiUrlChanged,
|
||||
TResult Function(String url)? apiUrlSaved,
|
||||
TResult Function(String code)? languageChanged,
|
||||
TResult Function()? refreshConfig,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (started != null) {
|
||||
return started();
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(SettingsStarted value) started,
|
||||
required TResult Function(SettingsConfigRequested value) configRequested,
|
||||
required TResult Function(SettingsApiUrlChanged value) apiUrlChanged,
|
||||
required TResult Function(SettingsApiUrlSaved value) apiUrlSaved,
|
||||
required TResult Function(SettingsLanguageChanged value) languageChanged,
|
||||
required TResult Function(SettingsRefreshConfig value) refreshConfig,
|
||||
}) {
|
||||
return started(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(SettingsStarted value)? started,
|
||||
TResult? Function(SettingsConfigRequested value)? configRequested,
|
||||
TResult? Function(SettingsApiUrlChanged value)? apiUrlChanged,
|
||||
TResult? Function(SettingsApiUrlSaved value)? apiUrlSaved,
|
||||
TResult? Function(SettingsLanguageChanged value)? languageChanged,
|
||||
TResult? Function(SettingsRefreshConfig value)? refreshConfig,
|
||||
}) {
|
||||
return started?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(SettingsStarted value)? started,
|
||||
TResult Function(SettingsConfigRequested value)? configRequested,
|
||||
TResult Function(SettingsApiUrlChanged value)? apiUrlChanged,
|
||||
TResult Function(SettingsApiUrlSaved value)? apiUrlSaved,
|
||||
TResult Function(SettingsLanguageChanged value)? languageChanged,
|
||||
TResult Function(SettingsRefreshConfig value)? refreshConfig,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (started != null) {
|
||||
return started(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class SettingsStarted implements SettingsEvent {
|
||||
const factory SettingsStarted() = _$SettingsStartedImpl;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$SettingsConfigRequestedImplCopyWith<$Res> {
|
||||
factory _$$SettingsConfigRequestedImplCopyWith(
|
||||
_$SettingsConfigRequestedImpl value,
|
||||
$Res Function(_$SettingsConfigRequestedImpl) then) =
|
||||
__$$SettingsConfigRequestedImplCopyWithImpl<$Res>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$SettingsConfigRequestedImplCopyWithImpl<$Res>
|
||||
extends _$SettingsEventCopyWithImpl<$Res, _$SettingsConfigRequestedImpl>
|
||||
implements _$$SettingsConfigRequestedImplCopyWith<$Res> {
|
||||
__$$SettingsConfigRequestedImplCopyWithImpl(
|
||||
_$SettingsConfigRequestedImpl _value,
|
||||
$Res Function(_$SettingsConfigRequestedImpl) _then)
|
||||
: super(_value, _then);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$SettingsConfigRequestedImpl implements SettingsConfigRequested {
|
||||
const _$SettingsConfigRequestedImpl();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SettingsEvent.configRequested()';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$SettingsConfigRequestedImpl);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => runtimeType.hashCode;
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() started,
|
||||
required TResult Function() configRequested,
|
||||
required TResult Function(String url) apiUrlChanged,
|
||||
required TResult Function(String url) apiUrlSaved,
|
||||
required TResult Function(String code) languageChanged,
|
||||
required TResult Function() refreshConfig,
|
||||
}) {
|
||||
return configRequested();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? started,
|
||||
TResult? Function()? configRequested,
|
||||
TResult? Function(String url)? apiUrlChanged,
|
||||
TResult? Function(String url)? apiUrlSaved,
|
||||
TResult? Function(String code)? languageChanged,
|
||||
TResult? Function()? refreshConfig,
|
||||
}) {
|
||||
return configRequested?.call();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? started,
|
||||
TResult Function()? configRequested,
|
||||
TResult Function(String url)? apiUrlChanged,
|
||||
TResult Function(String url)? apiUrlSaved,
|
||||
TResult Function(String code)? languageChanged,
|
||||
TResult Function()? refreshConfig,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (configRequested != null) {
|
||||
return configRequested();
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(SettingsStarted value) started,
|
||||
required TResult Function(SettingsConfigRequested value) configRequested,
|
||||
required TResult Function(SettingsApiUrlChanged value) apiUrlChanged,
|
||||
required TResult Function(SettingsApiUrlSaved value) apiUrlSaved,
|
||||
required TResult Function(SettingsLanguageChanged value) languageChanged,
|
||||
required TResult Function(SettingsRefreshConfig value) refreshConfig,
|
||||
}) {
|
||||
return configRequested(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(SettingsStarted value)? started,
|
||||
TResult? Function(SettingsConfigRequested value)? configRequested,
|
||||
TResult? Function(SettingsApiUrlChanged value)? apiUrlChanged,
|
||||
TResult? Function(SettingsApiUrlSaved value)? apiUrlSaved,
|
||||
TResult? Function(SettingsLanguageChanged value)? languageChanged,
|
||||
TResult? Function(SettingsRefreshConfig value)? refreshConfig,
|
||||
}) {
|
||||
return configRequested?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(SettingsStarted value)? started,
|
||||
TResult Function(SettingsConfigRequested value)? configRequested,
|
||||
TResult Function(SettingsApiUrlChanged value)? apiUrlChanged,
|
||||
TResult Function(SettingsApiUrlSaved value)? apiUrlSaved,
|
||||
TResult Function(SettingsLanguageChanged value)? languageChanged,
|
||||
TResult Function(SettingsRefreshConfig value)? refreshConfig,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (configRequested != null) {
|
||||
return configRequested(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class SettingsConfigRequested implements SettingsEvent {
|
||||
const factory SettingsConfigRequested() = _$SettingsConfigRequestedImpl;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$SettingsApiUrlChangedImplCopyWith<$Res> {
|
||||
factory _$$SettingsApiUrlChangedImplCopyWith(
|
||||
_$SettingsApiUrlChangedImpl value,
|
||||
$Res Function(_$SettingsApiUrlChangedImpl) then) =
|
||||
__$$SettingsApiUrlChangedImplCopyWithImpl<$Res>;
|
||||
@useResult
|
||||
$Res call({String url});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$SettingsApiUrlChangedImplCopyWithImpl<$Res>
|
||||
extends _$SettingsEventCopyWithImpl<$Res, _$SettingsApiUrlChangedImpl>
|
||||
implements _$$SettingsApiUrlChangedImplCopyWith<$Res> {
|
||||
__$$SettingsApiUrlChangedImplCopyWithImpl(_$SettingsApiUrlChangedImpl _value,
|
||||
$Res Function(_$SettingsApiUrlChangedImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? url = null,
|
||||
}) {
|
||||
return _then(_$SettingsApiUrlChangedImpl(
|
||||
null == url
|
||||
? _value.url
|
||||
: url // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$SettingsApiUrlChangedImpl implements SettingsApiUrlChanged {
|
||||
const _$SettingsApiUrlChangedImpl(this.url);
|
||||
|
||||
@override
|
||||
final String url;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SettingsEvent.apiUrlChanged(url: $url)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$SettingsApiUrlChangedImpl &&
|
||||
(identical(other.url, url) || other.url == url));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, url);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$SettingsApiUrlChangedImplCopyWith<_$SettingsApiUrlChangedImpl>
|
||||
get copyWith => __$$SettingsApiUrlChangedImplCopyWithImpl<
|
||||
_$SettingsApiUrlChangedImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() started,
|
||||
required TResult Function() configRequested,
|
||||
required TResult Function(String url) apiUrlChanged,
|
||||
required TResult Function(String url) apiUrlSaved,
|
||||
required TResult Function(String code) languageChanged,
|
||||
required TResult Function() refreshConfig,
|
||||
}) {
|
||||
return apiUrlChanged(url);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? started,
|
||||
TResult? Function()? configRequested,
|
||||
TResult? Function(String url)? apiUrlChanged,
|
||||
TResult? Function(String url)? apiUrlSaved,
|
||||
TResult? Function(String code)? languageChanged,
|
||||
TResult? Function()? refreshConfig,
|
||||
}) {
|
||||
return apiUrlChanged?.call(url);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? started,
|
||||
TResult Function()? configRequested,
|
||||
TResult Function(String url)? apiUrlChanged,
|
||||
TResult Function(String url)? apiUrlSaved,
|
||||
TResult Function(String code)? languageChanged,
|
||||
TResult Function()? refreshConfig,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (apiUrlChanged != null) {
|
||||
return apiUrlChanged(url);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(SettingsStarted value) started,
|
||||
required TResult Function(SettingsConfigRequested value) configRequested,
|
||||
required TResult Function(SettingsApiUrlChanged value) apiUrlChanged,
|
||||
required TResult Function(SettingsApiUrlSaved value) apiUrlSaved,
|
||||
required TResult Function(SettingsLanguageChanged value) languageChanged,
|
||||
required TResult Function(SettingsRefreshConfig value) refreshConfig,
|
||||
}) {
|
||||
return apiUrlChanged(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(SettingsStarted value)? started,
|
||||
TResult? Function(SettingsConfigRequested value)? configRequested,
|
||||
TResult? Function(SettingsApiUrlChanged value)? apiUrlChanged,
|
||||
TResult? Function(SettingsApiUrlSaved value)? apiUrlSaved,
|
||||
TResult? Function(SettingsLanguageChanged value)? languageChanged,
|
||||
TResult? Function(SettingsRefreshConfig value)? refreshConfig,
|
||||
}) {
|
||||
return apiUrlChanged?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(SettingsStarted value)? started,
|
||||
TResult Function(SettingsConfigRequested value)? configRequested,
|
||||
TResult Function(SettingsApiUrlChanged value)? apiUrlChanged,
|
||||
TResult Function(SettingsApiUrlSaved value)? apiUrlSaved,
|
||||
TResult Function(SettingsLanguageChanged value)? languageChanged,
|
||||
TResult Function(SettingsRefreshConfig value)? refreshConfig,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (apiUrlChanged != null) {
|
||||
return apiUrlChanged(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class SettingsApiUrlChanged implements SettingsEvent {
|
||||
const factory SettingsApiUrlChanged(final String url) =
|
||||
_$SettingsApiUrlChangedImpl;
|
||||
|
||||
String get url;
|
||||
@JsonKey(ignore: true)
|
||||
_$$SettingsApiUrlChangedImplCopyWith<_$SettingsApiUrlChangedImpl>
|
||||
get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$SettingsApiUrlSavedImplCopyWith<$Res> {
|
||||
factory _$$SettingsApiUrlSavedImplCopyWith(_$SettingsApiUrlSavedImpl value,
|
||||
$Res Function(_$SettingsApiUrlSavedImpl) then) =
|
||||
__$$SettingsApiUrlSavedImplCopyWithImpl<$Res>;
|
||||
@useResult
|
||||
$Res call({String url});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$SettingsApiUrlSavedImplCopyWithImpl<$Res>
|
||||
extends _$SettingsEventCopyWithImpl<$Res, _$SettingsApiUrlSavedImpl>
|
||||
implements _$$SettingsApiUrlSavedImplCopyWith<$Res> {
|
||||
__$$SettingsApiUrlSavedImplCopyWithImpl(_$SettingsApiUrlSavedImpl _value,
|
||||
$Res Function(_$SettingsApiUrlSavedImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? url = null,
|
||||
}) {
|
||||
return _then(_$SettingsApiUrlSavedImpl(
|
||||
null == url
|
||||
? _value.url
|
||||
: url // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$SettingsApiUrlSavedImpl implements SettingsApiUrlSaved {
|
||||
const _$SettingsApiUrlSavedImpl(this.url);
|
||||
|
||||
@override
|
||||
final String url;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SettingsEvent.apiUrlSaved(url: $url)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$SettingsApiUrlSavedImpl &&
|
||||
(identical(other.url, url) || other.url == url));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, url);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$SettingsApiUrlSavedImplCopyWith<_$SettingsApiUrlSavedImpl> get copyWith =>
|
||||
__$$SettingsApiUrlSavedImplCopyWithImpl<_$SettingsApiUrlSavedImpl>(
|
||||
this, _$identity);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() started,
|
||||
required TResult Function() configRequested,
|
||||
required TResult Function(String url) apiUrlChanged,
|
||||
required TResult Function(String url) apiUrlSaved,
|
||||
required TResult Function(String code) languageChanged,
|
||||
required TResult Function() refreshConfig,
|
||||
}) {
|
||||
return apiUrlSaved(url);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? started,
|
||||
TResult? Function()? configRequested,
|
||||
TResult? Function(String url)? apiUrlChanged,
|
||||
TResult? Function(String url)? apiUrlSaved,
|
||||
TResult? Function(String code)? languageChanged,
|
||||
TResult? Function()? refreshConfig,
|
||||
}) {
|
||||
return apiUrlSaved?.call(url);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? started,
|
||||
TResult Function()? configRequested,
|
||||
TResult Function(String url)? apiUrlChanged,
|
||||
TResult Function(String url)? apiUrlSaved,
|
||||
TResult Function(String code)? languageChanged,
|
||||
TResult Function()? refreshConfig,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (apiUrlSaved != null) {
|
||||
return apiUrlSaved(url);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(SettingsStarted value) started,
|
||||
required TResult Function(SettingsConfigRequested value) configRequested,
|
||||
required TResult Function(SettingsApiUrlChanged value) apiUrlChanged,
|
||||
required TResult Function(SettingsApiUrlSaved value) apiUrlSaved,
|
||||
required TResult Function(SettingsLanguageChanged value) languageChanged,
|
||||
required TResult Function(SettingsRefreshConfig value) refreshConfig,
|
||||
}) {
|
||||
return apiUrlSaved(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(SettingsStarted value)? started,
|
||||
TResult? Function(SettingsConfigRequested value)? configRequested,
|
||||
TResult? Function(SettingsApiUrlChanged value)? apiUrlChanged,
|
||||
TResult? Function(SettingsApiUrlSaved value)? apiUrlSaved,
|
||||
TResult? Function(SettingsLanguageChanged value)? languageChanged,
|
||||
TResult? Function(SettingsRefreshConfig value)? refreshConfig,
|
||||
}) {
|
||||
return apiUrlSaved?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(SettingsStarted value)? started,
|
||||
TResult Function(SettingsConfigRequested value)? configRequested,
|
||||
TResult Function(SettingsApiUrlChanged value)? apiUrlChanged,
|
||||
TResult Function(SettingsApiUrlSaved value)? apiUrlSaved,
|
||||
TResult Function(SettingsLanguageChanged value)? languageChanged,
|
||||
TResult Function(SettingsRefreshConfig value)? refreshConfig,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (apiUrlSaved != null) {
|
||||
return apiUrlSaved(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class SettingsApiUrlSaved implements SettingsEvent {
|
||||
const factory SettingsApiUrlSaved(final String url) =
|
||||
_$SettingsApiUrlSavedImpl;
|
||||
|
||||
String get url;
|
||||
@JsonKey(ignore: true)
|
||||
_$$SettingsApiUrlSavedImplCopyWith<_$SettingsApiUrlSavedImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$SettingsLanguageChangedImplCopyWith<$Res> {
|
||||
factory _$$SettingsLanguageChangedImplCopyWith(
|
||||
_$SettingsLanguageChangedImpl value,
|
||||
$Res Function(_$SettingsLanguageChangedImpl) then) =
|
||||
__$$SettingsLanguageChangedImplCopyWithImpl<$Res>;
|
||||
@useResult
|
||||
$Res call({String code});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$SettingsLanguageChangedImplCopyWithImpl<$Res>
|
||||
extends _$SettingsEventCopyWithImpl<$Res, _$SettingsLanguageChangedImpl>
|
||||
implements _$$SettingsLanguageChangedImplCopyWith<$Res> {
|
||||
__$$SettingsLanguageChangedImplCopyWithImpl(
|
||||
_$SettingsLanguageChangedImpl _value,
|
||||
$Res Function(_$SettingsLanguageChangedImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? code = null,
|
||||
}) {
|
||||
return _then(_$SettingsLanguageChangedImpl(
|
||||
null == code
|
||||
? _value.code
|
||||
: code // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$SettingsLanguageChangedImpl implements SettingsLanguageChanged {
|
||||
const _$SettingsLanguageChangedImpl(this.code);
|
||||
|
||||
@override
|
||||
final String code;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SettingsEvent.languageChanged(code: $code)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$SettingsLanguageChangedImpl &&
|
||||
(identical(other.code, code) || other.code == code));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, code);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$SettingsLanguageChangedImplCopyWith<_$SettingsLanguageChangedImpl>
|
||||
get copyWith => __$$SettingsLanguageChangedImplCopyWithImpl<
|
||||
_$SettingsLanguageChangedImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() started,
|
||||
required TResult Function() configRequested,
|
||||
required TResult Function(String url) apiUrlChanged,
|
||||
required TResult Function(String url) apiUrlSaved,
|
||||
required TResult Function(String code) languageChanged,
|
||||
required TResult Function() refreshConfig,
|
||||
}) {
|
||||
return languageChanged(code);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? started,
|
||||
TResult? Function()? configRequested,
|
||||
TResult? Function(String url)? apiUrlChanged,
|
||||
TResult? Function(String url)? apiUrlSaved,
|
||||
TResult? Function(String code)? languageChanged,
|
||||
TResult? Function()? refreshConfig,
|
||||
}) {
|
||||
return languageChanged?.call(code);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? started,
|
||||
TResult Function()? configRequested,
|
||||
TResult Function(String url)? apiUrlChanged,
|
||||
TResult Function(String url)? apiUrlSaved,
|
||||
TResult Function(String code)? languageChanged,
|
||||
TResult Function()? refreshConfig,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (languageChanged != null) {
|
||||
return languageChanged(code);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(SettingsStarted value) started,
|
||||
required TResult Function(SettingsConfigRequested value) configRequested,
|
||||
required TResult Function(SettingsApiUrlChanged value) apiUrlChanged,
|
||||
required TResult Function(SettingsApiUrlSaved value) apiUrlSaved,
|
||||
required TResult Function(SettingsLanguageChanged value) languageChanged,
|
||||
required TResult Function(SettingsRefreshConfig value) refreshConfig,
|
||||
}) {
|
||||
return languageChanged(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(SettingsStarted value)? started,
|
||||
TResult? Function(SettingsConfigRequested value)? configRequested,
|
||||
TResult? Function(SettingsApiUrlChanged value)? apiUrlChanged,
|
||||
TResult? Function(SettingsApiUrlSaved value)? apiUrlSaved,
|
||||
TResult? Function(SettingsLanguageChanged value)? languageChanged,
|
||||
TResult? Function(SettingsRefreshConfig value)? refreshConfig,
|
||||
}) {
|
||||
return languageChanged?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(SettingsStarted value)? started,
|
||||
TResult Function(SettingsConfigRequested value)? configRequested,
|
||||
TResult Function(SettingsApiUrlChanged value)? apiUrlChanged,
|
||||
TResult Function(SettingsApiUrlSaved value)? apiUrlSaved,
|
||||
TResult Function(SettingsLanguageChanged value)? languageChanged,
|
||||
TResult Function(SettingsRefreshConfig value)? refreshConfig,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (languageChanged != null) {
|
||||
return languageChanged(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class SettingsLanguageChanged implements SettingsEvent {
|
||||
const factory SettingsLanguageChanged(final String code) =
|
||||
_$SettingsLanguageChangedImpl;
|
||||
|
||||
String get code;
|
||||
@JsonKey(ignore: true)
|
||||
_$$SettingsLanguageChangedImplCopyWith<_$SettingsLanguageChangedImpl>
|
||||
get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$SettingsRefreshConfigImplCopyWith<$Res> {
|
||||
factory _$$SettingsRefreshConfigImplCopyWith(
|
||||
_$SettingsRefreshConfigImpl value,
|
||||
$Res Function(_$SettingsRefreshConfigImpl) then) =
|
||||
__$$SettingsRefreshConfigImplCopyWithImpl<$Res>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$SettingsRefreshConfigImplCopyWithImpl<$Res>
|
||||
extends _$SettingsEventCopyWithImpl<$Res, _$SettingsRefreshConfigImpl>
|
||||
implements _$$SettingsRefreshConfigImplCopyWith<$Res> {
|
||||
__$$SettingsRefreshConfigImplCopyWithImpl(_$SettingsRefreshConfigImpl _value,
|
||||
$Res Function(_$SettingsRefreshConfigImpl) _then)
|
||||
: super(_value, _then);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$SettingsRefreshConfigImpl implements SettingsRefreshConfig {
|
||||
const _$SettingsRefreshConfigImpl();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SettingsEvent.refreshConfig()';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$SettingsRefreshConfigImpl);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => runtimeType.hashCode;
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() started,
|
||||
required TResult Function() configRequested,
|
||||
required TResult Function(String url) apiUrlChanged,
|
||||
required TResult Function(String url) apiUrlSaved,
|
||||
required TResult Function(String code) languageChanged,
|
||||
required TResult Function() refreshConfig,
|
||||
}) {
|
||||
return refreshConfig();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? started,
|
||||
TResult? Function()? configRequested,
|
||||
TResult? Function(String url)? apiUrlChanged,
|
||||
TResult? Function(String url)? apiUrlSaved,
|
||||
TResult? Function(String code)? languageChanged,
|
||||
TResult? Function()? refreshConfig,
|
||||
}) {
|
||||
return refreshConfig?.call();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? started,
|
||||
TResult Function()? configRequested,
|
||||
TResult Function(String url)? apiUrlChanged,
|
||||
TResult Function(String url)? apiUrlSaved,
|
||||
TResult Function(String code)? languageChanged,
|
||||
TResult Function()? refreshConfig,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (refreshConfig != null) {
|
||||
return refreshConfig();
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(SettingsStarted value) started,
|
||||
required TResult Function(SettingsConfigRequested value) configRequested,
|
||||
required TResult Function(SettingsApiUrlChanged value) apiUrlChanged,
|
||||
required TResult Function(SettingsApiUrlSaved value) apiUrlSaved,
|
||||
required TResult Function(SettingsLanguageChanged value) languageChanged,
|
||||
required TResult Function(SettingsRefreshConfig value) refreshConfig,
|
||||
}) {
|
||||
return refreshConfig(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(SettingsStarted value)? started,
|
||||
TResult? Function(SettingsConfigRequested value)? configRequested,
|
||||
TResult? Function(SettingsApiUrlChanged value)? apiUrlChanged,
|
||||
TResult? Function(SettingsApiUrlSaved value)? apiUrlSaved,
|
||||
TResult? Function(SettingsLanguageChanged value)? languageChanged,
|
||||
TResult? Function(SettingsRefreshConfig value)? refreshConfig,
|
||||
}) {
|
||||
return refreshConfig?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(SettingsStarted value)? started,
|
||||
TResult Function(SettingsConfigRequested value)? configRequested,
|
||||
TResult Function(SettingsApiUrlChanged value)? apiUrlChanged,
|
||||
TResult Function(SettingsApiUrlSaved value)? apiUrlSaved,
|
||||
TResult Function(SettingsLanguageChanged value)? languageChanged,
|
||||
TResult Function(SettingsRefreshConfig value)? refreshConfig,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (refreshConfig != null) {
|
||||
return refreshConfig(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class SettingsRefreshConfig implements SettingsEvent {
|
||||
const factory SettingsRefreshConfig() = _$SettingsRefreshConfigImpl;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import '../../domain/entities/server_config.dart';
|
||||
|
||||
part 'settings_state.freezed.dart';
|
||||
|
||||
@freezed
|
||||
class SettingsState with _$SettingsState {
|
||||
const factory SettingsState.initial() = SettingsInitial;
|
||||
const factory SettingsState.loading() = SettingsLoading;
|
||||
const factory SettingsState.loaded({
|
||||
required String apiUrl,
|
||||
required ServerConfig? serverConfig,
|
||||
required String languageCode,
|
||||
String? error,
|
||||
}) = SettingsLoaded;
|
||||
const factory SettingsState.error(String message) = SettingsError;
|
||||
}
|
||||
@@ -0,0 +1,692 @@
|
||||
// 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_state.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() loading,
|
||||
required TResult Function(String apiUrl, ServerConfig? serverConfig,
|
||||
String languageCode, String? error)
|
||||
loaded,
|
||||
required TResult Function(String message) error,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? initial,
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(String apiUrl, ServerConfig? serverConfig,
|
||||
String languageCode, String? error)?
|
||||
loaded,
|
||||
TResult? Function(String message)? error,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? initial,
|
||||
TResult Function()? loading,
|
||||
TResult Function(String apiUrl, ServerConfig? serverConfig,
|
||||
String languageCode, String? error)?
|
||||
loaded,
|
||||
TResult Function(String message)? error,
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(SettingsInitial value) initial,
|
||||
required TResult Function(SettingsLoading value) loading,
|
||||
required TResult Function(SettingsLoaded value) loaded,
|
||||
required TResult Function(SettingsError value) error,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(SettingsInitial value)? initial,
|
||||
TResult? Function(SettingsLoading value)? loading,
|
||||
TResult? Function(SettingsLoaded value)? loaded,
|
||||
TResult? Function(SettingsError value)? error,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(SettingsInitial value)? initial,
|
||||
TResult Function(SettingsLoading value)? loading,
|
||||
TResult Function(SettingsLoaded value)? loaded,
|
||||
TResult Function(SettingsError value)? error,
|
||||
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;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$SettingsInitialImplCopyWith<$Res> {
|
||||
factory _$$SettingsInitialImplCopyWith(_$SettingsInitialImpl value,
|
||||
$Res Function(_$SettingsInitialImpl) then) =
|
||||
__$$SettingsInitialImplCopyWithImpl<$Res>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$SettingsInitialImplCopyWithImpl<$Res>
|
||||
extends _$SettingsStateCopyWithImpl<$Res, _$SettingsInitialImpl>
|
||||
implements _$$SettingsInitialImplCopyWith<$Res> {
|
||||
__$$SettingsInitialImplCopyWithImpl(
|
||||
_$SettingsInitialImpl _value, $Res Function(_$SettingsInitialImpl) _then)
|
||||
: super(_value, _then);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$SettingsInitialImpl implements SettingsInitial {
|
||||
const _$SettingsInitialImpl();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SettingsState.initial()';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _$SettingsInitialImpl);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => runtimeType.hashCode;
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() initial,
|
||||
required TResult Function() loading,
|
||||
required TResult Function(String apiUrl, ServerConfig? serverConfig,
|
||||
String languageCode, String? error)
|
||||
loaded,
|
||||
required TResult Function(String message) error,
|
||||
}) {
|
||||
return initial();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? initial,
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(String apiUrl, ServerConfig? serverConfig,
|
||||
String languageCode, String? error)?
|
||||
loaded,
|
||||
TResult? Function(String message)? error,
|
||||
}) {
|
||||
return initial?.call();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? initial,
|
||||
TResult Function()? loading,
|
||||
TResult Function(String apiUrl, ServerConfig? serverConfig,
|
||||
String languageCode, String? error)?
|
||||
loaded,
|
||||
TResult Function(String message)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (initial != null) {
|
||||
return initial();
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(SettingsInitial value) initial,
|
||||
required TResult Function(SettingsLoading value) loading,
|
||||
required TResult Function(SettingsLoaded value) loaded,
|
||||
required TResult Function(SettingsError value) error,
|
||||
}) {
|
||||
return initial(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(SettingsInitial value)? initial,
|
||||
TResult? Function(SettingsLoading value)? loading,
|
||||
TResult? Function(SettingsLoaded value)? loaded,
|
||||
TResult? Function(SettingsError value)? error,
|
||||
}) {
|
||||
return initial?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(SettingsInitial value)? initial,
|
||||
TResult Function(SettingsLoading value)? loading,
|
||||
TResult Function(SettingsLoaded value)? loaded,
|
||||
TResult Function(SettingsError value)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (initial != null) {
|
||||
return initial(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class SettingsInitial implements SettingsState {
|
||||
const factory SettingsInitial() = _$SettingsInitialImpl;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$SettingsLoadingImplCopyWith<$Res> {
|
||||
factory _$$SettingsLoadingImplCopyWith(_$SettingsLoadingImpl value,
|
||||
$Res Function(_$SettingsLoadingImpl) then) =
|
||||
__$$SettingsLoadingImplCopyWithImpl<$Res>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$SettingsLoadingImplCopyWithImpl<$Res>
|
||||
extends _$SettingsStateCopyWithImpl<$Res, _$SettingsLoadingImpl>
|
||||
implements _$$SettingsLoadingImplCopyWith<$Res> {
|
||||
__$$SettingsLoadingImplCopyWithImpl(
|
||||
_$SettingsLoadingImpl _value, $Res Function(_$SettingsLoadingImpl) _then)
|
||||
: super(_value, _then);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$SettingsLoadingImpl implements SettingsLoading {
|
||||
const _$SettingsLoadingImpl();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SettingsState.loading()';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _$SettingsLoadingImpl);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => runtimeType.hashCode;
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() initial,
|
||||
required TResult Function() loading,
|
||||
required TResult Function(String apiUrl, ServerConfig? serverConfig,
|
||||
String languageCode, String? error)
|
||||
loaded,
|
||||
required TResult Function(String message) error,
|
||||
}) {
|
||||
return loading();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? initial,
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(String apiUrl, ServerConfig? serverConfig,
|
||||
String languageCode, String? error)?
|
||||
loaded,
|
||||
TResult? Function(String message)? error,
|
||||
}) {
|
||||
return loading?.call();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? initial,
|
||||
TResult Function()? loading,
|
||||
TResult Function(String apiUrl, ServerConfig? serverConfig,
|
||||
String languageCode, String? error)?
|
||||
loaded,
|
||||
TResult Function(String message)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (loading != null) {
|
||||
return loading();
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(SettingsInitial value) initial,
|
||||
required TResult Function(SettingsLoading value) loading,
|
||||
required TResult Function(SettingsLoaded value) loaded,
|
||||
required TResult Function(SettingsError value) error,
|
||||
}) {
|
||||
return loading(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(SettingsInitial value)? initial,
|
||||
TResult? Function(SettingsLoading value)? loading,
|
||||
TResult? Function(SettingsLoaded value)? loaded,
|
||||
TResult? Function(SettingsError value)? error,
|
||||
}) {
|
||||
return loading?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(SettingsInitial value)? initial,
|
||||
TResult Function(SettingsLoading value)? loading,
|
||||
TResult Function(SettingsLoaded value)? loaded,
|
||||
TResult Function(SettingsError value)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (loading != null) {
|
||||
return loading(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class SettingsLoading implements SettingsState {
|
||||
const factory SettingsLoading() = _$SettingsLoadingImpl;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$SettingsLoadedImplCopyWith<$Res> {
|
||||
factory _$$SettingsLoadedImplCopyWith(_$SettingsLoadedImpl value,
|
||||
$Res Function(_$SettingsLoadedImpl) then) =
|
||||
__$$SettingsLoadedImplCopyWithImpl<$Res>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{String apiUrl,
|
||||
ServerConfig? serverConfig,
|
||||
String languageCode,
|
||||
String? error});
|
||||
|
||||
$ServerConfigCopyWith<$Res>? get serverConfig;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$SettingsLoadedImplCopyWithImpl<$Res>
|
||||
extends _$SettingsStateCopyWithImpl<$Res, _$SettingsLoadedImpl>
|
||||
implements _$$SettingsLoadedImplCopyWith<$Res> {
|
||||
__$$SettingsLoadedImplCopyWithImpl(
|
||||
_$SettingsLoadedImpl _value, $Res Function(_$SettingsLoadedImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? apiUrl = null,
|
||||
Object? serverConfig = freezed,
|
||||
Object? languageCode = null,
|
||||
Object? error = freezed,
|
||||
}) {
|
||||
return _then(_$SettingsLoadedImpl(
|
||||
apiUrl: null == apiUrl
|
||||
? _value.apiUrl
|
||||
: apiUrl // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
serverConfig: freezed == serverConfig
|
||||
? _value.serverConfig
|
||||
: serverConfig // ignore: cast_nullable_to_non_nullable
|
||||
as ServerConfig?,
|
||||
languageCode: null == languageCode
|
||||
? _value.languageCode
|
||||
: languageCode // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
error: freezed == error
|
||||
? _value.error
|
||||
: error // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$ServerConfigCopyWith<$Res>? get serverConfig {
|
||||
if (_value.serverConfig == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $ServerConfigCopyWith<$Res>(_value.serverConfig!, (value) {
|
||||
return _then(_value.copyWith(serverConfig: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$SettingsLoadedImpl implements SettingsLoaded {
|
||||
const _$SettingsLoadedImpl(
|
||||
{required this.apiUrl,
|
||||
required this.serverConfig,
|
||||
required this.languageCode,
|
||||
this.error});
|
||||
|
||||
@override
|
||||
final String apiUrl;
|
||||
@override
|
||||
final ServerConfig? serverConfig;
|
||||
@override
|
||||
final String languageCode;
|
||||
@override
|
||||
final String? error;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SettingsState.loaded(apiUrl: $apiUrl, serverConfig: $serverConfig, languageCode: $languageCode, error: $error)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$SettingsLoadedImpl &&
|
||||
(identical(other.apiUrl, apiUrl) || other.apiUrl == apiUrl) &&
|
||||
(identical(other.serverConfig, serverConfig) ||
|
||||
other.serverConfig == serverConfig) &&
|
||||
(identical(other.languageCode, languageCode) ||
|
||||
other.languageCode == languageCode) &&
|
||||
(identical(other.error, error) || other.error == error));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(runtimeType, apiUrl, serverConfig, languageCode, error);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$SettingsLoadedImplCopyWith<_$SettingsLoadedImpl> get copyWith =>
|
||||
__$$SettingsLoadedImplCopyWithImpl<_$SettingsLoadedImpl>(
|
||||
this, _$identity);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() initial,
|
||||
required TResult Function() loading,
|
||||
required TResult Function(String apiUrl, ServerConfig? serverConfig,
|
||||
String languageCode, String? error)
|
||||
loaded,
|
||||
required TResult Function(String message) error,
|
||||
}) {
|
||||
return loaded(apiUrl, serverConfig, languageCode, this.error);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? initial,
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(String apiUrl, ServerConfig? serverConfig,
|
||||
String languageCode, String? error)?
|
||||
loaded,
|
||||
TResult? Function(String message)? error,
|
||||
}) {
|
||||
return loaded?.call(apiUrl, serverConfig, languageCode, this.error);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? initial,
|
||||
TResult Function()? loading,
|
||||
TResult Function(String apiUrl, ServerConfig? serverConfig,
|
||||
String languageCode, String? error)?
|
||||
loaded,
|
||||
TResult Function(String message)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (loaded != null) {
|
||||
return loaded(apiUrl, serverConfig, languageCode, this.error);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(SettingsInitial value) initial,
|
||||
required TResult Function(SettingsLoading value) loading,
|
||||
required TResult Function(SettingsLoaded value) loaded,
|
||||
required TResult Function(SettingsError value) error,
|
||||
}) {
|
||||
return loaded(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(SettingsInitial value)? initial,
|
||||
TResult? Function(SettingsLoading value)? loading,
|
||||
TResult? Function(SettingsLoaded value)? loaded,
|
||||
TResult? Function(SettingsError value)? error,
|
||||
}) {
|
||||
return loaded?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(SettingsInitial value)? initial,
|
||||
TResult Function(SettingsLoading value)? loading,
|
||||
TResult Function(SettingsLoaded value)? loaded,
|
||||
TResult Function(SettingsError value)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (loaded != null) {
|
||||
return loaded(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class SettingsLoaded implements SettingsState {
|
||||
const factory SettingsLoaded(
|
||||
{required final String apiUrl,
|
||||
required final ServerConfig? serverConfig,
|
||||
required final String languageCode,
|
||||
final String? error}) = _$SettingsLoadedImpl;
|
||||
|
||||
String get apiUrl;
|
||||
ServerConfig? get serverConfig;
|
||||
String get languageCode;
|
||||
String? get error;
|
||||
@JsonKey(ignore: true)
|
||||
_$$SettingsLoadedImplCopyWith<_$SettingsLoadedImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$SettingsErrorImplCopyWith<$Res> {
|
||||
factory _$$SettingsErrorImplCopyWith(
|
||||
_$SettingsErrorImpl value, $Res Function(_$SettingsErrorImpl) then) =
|
||||
__$$SettingsErrorImplCopyWithImpl<$Res>;
|
||||
@useResult
|
||||
$Res call({String message});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$SettingsErrorImplCopyWithImpl<$Res>
|
||||
extends _$SettingsStateCopyWithImpl<$Res, _$SettingsErrorImpl>
|
||||
implements _$$SettingsErrorImplCopyWith<$Res> {
|
||||
__$$SettingsErrorImplCopyWithImpl(
|
||||
_$SettingsErrorImpl _value, $Res Function(_$SettingsErrorImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? message = null,
|
||||
}) {
|
||||
return _then(_$SettingsErrorImpl(
|
||||
null == message
|
||||
? _value.message
|
||||
: message // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$SettingsErrorImpl implements SettingsError {
|
||||
const _$SettingsErrorImpl(this.message);
|
||||
|
||||
@override
|
||||
final String message;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SettingsState.error(message: $message)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$SettingsErrorImpl &&
|
||||
(identical(other.message, message) || other.message == message));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, message);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$SettingsErrorImplCopyWith<_$SettingsErrorImpl> get copyWith =>
|
||||
__$$SettingsErrorImplCopyWithImpl<_$SettingsErrorImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() initial,
|
||||
required TResult Function() loading,
|
||||
required TResult Function(String apiUrl, ServerConfig? serverConfig,
|
||||
String languageCode, String? error)
|
||||
loaded,
|
||||
required TResult Function(String message) error,
|
||||
}) {
|
||||
return error(message);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? initial,
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(String apiUrl, ServerConfig? serverConfig,
|
||||
String languageCode, String? error)?
|
||||
loaded,
|
||||
TResult? Function(String message)? error,
|
||||
}) {
|
||||
return error?.call(message);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? initial,
|
||||
TResult Function()? loading,
|
||||
TResult Function(String apiUrl, ServerConfig? serverConfig,
|
||||
String languageCode, String? error)?
|
||||
loaded,
|
||||
TResult Function(String message)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (error != null) {
|
||||
return error(message);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(SettingsInitial value) initial,
|
||||
required TResult Function(SettingsLoading value) loading,
|
||||
required TResult Function(SettingsLoaded value) loaded,
|
||||
required TResult Function(SettingsError value) error,
|
||||
}) {
|
||||
return error(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(SettingsInitial value)? initial,
|
||||
TResult? Function(SettingsLoading value)? loading,
|
||||
TResult? Function(SettingsLoaded value)? loaded,
|
||||
TResult? Function(SettingsError value)? error,
|
||||
}) {
|
||||
return error?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(SettingsInitial value)? initial,
|
||||
TResult Function(SettingsLoading value)? loading,
|
||||
TResult Function(SettingsLoaded value)? loaded,
|
||||
TResult Function(SettingsError value)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (error != null) {
|
||||
return error(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class SettingsError implements SettingsState {
|
||||
const factory SettingsError(final String message) = _$SettingsErrorImpl;
|
||||
|
||||
String get message;
|
||||
@JsonKey(ignore: true)
|
||||
_$$SettingsErrorImplCopyWith<_$SettingsErrorImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -0,0 +1,417 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:intl/intl.dart' as intl;
|
||||
|
||||
import 'app_localizations_en.dart';
|
||||
import 'app_localizations_ru.dart';
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
|
||||
/// Callers can lookup localized strings with an instance of AppLocalizations
|
||||
/// returned by `AppLocalizations.of(context)`.
|
||||
///
|
||||
/// Applications need to include `AppLocalizations.delegate()` in their app's
|
||||
/// `localizationDelegates` list, and the locales they support in the app's
|
||||
/// `supportedLocales` list. For example:
|
||||
///
|
||||
/// ```dart
|
||||
/// import 'l10n/app_localizations.dart';
|
||||
///
|
||||
/// return MaterialApp(
|
||||
/// localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
/// supportedLocales: AppLocalizations.supportedLocales,
|
||||
/// home: MyApplicationHome(),
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// ## Update pubspec.yaml
|
||||
///
|
||||
/// Please make sure to update your pubspec.yaml to include the following
|
||||
/// packages:
|
||||
///
|
||||
/// ```yaml
|
||||
/// dependencies:
|
||||
/// # Internationalization support.
|
||||
/// flutter_localizations:
|
||||
/// sdk: flutter
|
||||
/// intl: any # Use the pinned version from flutter_localizations
|
||||
///
|
||||
/// # Rest of dependencies
|
||||
/// ```
|
||||
///
|
||||
/// ## iOS Applications
|
||||
///
|
||||
/// iOS applications define key application metadata, including supported
|
||||
/// locales, in an Info.plist file that is built into the application bundle.
|
||||
/// To configure the locales supported by your app, you’ll need to edit this
|
||||
/// file.
|
||||
///
|
||||
/// First, open your project’s ios/Runner.xcworkspace Xcode workspace file.
|
||||
/// Then, in the Project Navigator, open the Info.plist file under the Runner
|
||||
/// project’s Runner folder.
|
||||
///
|
||||
/// Next, select the Information Property List item, select Add Item from the
|
||||
/// Editor menu, then select Localizations from the pop-up menu.
|
||||
///
|
||||
/// Select and expand the newly-created Localizations item then, for each
|
||||
/// locale your application supports, add a new item and select the locale
|
||||
/// you wish to add from the pop-up menu in the Value field. This list should
|
||||
/// be consistent with the languages listed in the AppLocalizations.supportedLocales
|
||||
/// property.
|
||||
abstract class AppLocalizations {
|
||||
AppLocalizations(String locale) : localeName = intl.Intl.canonicalizedLocale(locale.toString());
|
||||
|
||||
final String localeName;
|
||||
|
||||
static AppLocalizations? of(BuildContext context) {
|
||||
return Localizations.of<AppLocalizations>(context, AppLocalizations);
|
||||
}
|
||||
|
||||
static const LocalizationsDelegate<AppLocalizations> delegate = _AppLocalizationsDelegate();
|
||||
|
||||
/// A list of this localizations delegate along with the default localizations
|
||||
/// delegates.
|
||||
///
|
||||
/// Returns a list of localizations delegates containing this delegate along with
|
||||
/// GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate,
|
||||
/// and GlobalWidgetsLocalizations.delegate.
|
||||
///
|
||||
/// Additional delegates can be added by appending to this list in
|
||||
/// MaterialApp. This list does not have to be used at all if a custom list
|
||||
/// of delegates is preferred or required.
|
||||
static const List<LocalizationsDelegate<dynamic>> localizationsDelegates = <LocalizationsDelegate<dynamic>>[
|
||||
delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
];
|
||||
|
||||
/// A list of this localizations delegate's supported locales.
|
||||
static const List<Locale> supportedLocales = <Locale>[
|
||||
Locale('en'),
|
||||
Locale('ru')
|
||||
];
|
||||
|
||||
/// No description provided for @appTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Messenger'**
|
||||
String get appTitle;
|
||||
|
||||
/// No description provided for @chats.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Chats'**
|
||||
String get chats;
|
||||
|
||||
/// No description provided for @contacts.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Contacts'**
|
||||
String get contacts;
|
||||
|
||||
/// No description provided for @settings.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Settings'**
|
||||
String get settings;
|
||||
|
||||
/// No description provided for @login.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Login'**
|
||||
String get login;
|
||||
|
||||
/// No description provided for @email.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Email'**
|
||||
String get email;
|
||||
|
||||
/// No description provided for @password.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Password'**
|
||||
String get password;
|
||||
|
||||
/// No description provided for @name.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Name'**
|
||||
String get name;
|
||||
|
||||
/// No description provided for @loginButton.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Sign In'**
|
||||
String get loginButton;
|
||||
|
||||
/// No description provided for @register.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Register'**
|
||||
String get register;
|
||||
|
||||
/// No description provided for @noAccount.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'No account? Sign up'**
|
||||
String get noAccount;
|
||||
|
||||
/// No description provided for @logout.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Sign Out'**
|
||||
String get logout;
|
||||
|
||||
/// No description provided for @serverSettings.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Server Settings'**
|
||||
String get serverSettings;
|
||||
|
||||
/// No description provided for @apiUrl.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'API URL'**
|
||||
String get apiUrl;
|
||||
|
||||
/// No description provided for @apiUrlHint.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'https://api.example.com'**
|
||||
String get apiUrlHint;
|
||||
|
||||
/// No description provided for @save.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Save'**
|
||||
String get save;
|
||||
|
||||
/// No description provided for @serverConfig.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Server Configuration'**
|
||||
String get serverConfig;
|
||||
|
||||
/// No description provided for @system.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'System'**
|
||||
String get system;
|
||||
|
||||
/// No description provided for @stories.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Stories'**
|
||||
String get stories;
|
||||
|
||||
/// No description provided for @chatsModule.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Chats'**
|
||||
String get chatsModule;
|
||||
|
||||
/// No description provided for @messages.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Messages'**
|
||||
String get messages;
|
||||
|
||||
/// No description provided for @calls.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Calls'**
|
||||
String get calls;
|
||||
|
||||
/// No description provided for @klipy.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Klipy'**
|
||||
String get klipy;
|
||||
|
||||
/// No description provided for @import.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Import'**
|
||||
String get import;
|
||||
|
||||
/// No description provided for @federation.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Federation'**
|
||||
String get federation;
|
||||
|
||||
/// No description provided for @domainUrl.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Domain'**
|
||||
String get domainUrl;
|
||||
|
||||
/// No description provided for @enableRegistration.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Registration Enabled'**
|
||||
String get enableRegistration;
|
||||
|
||||
/// No description provided for @enabled.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Enabled'**
|
||||
String get enabled;
|
||||
|
||||
/// No description provided for @disabled.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Disabled'**
|
||||
String get disabled;
|
||||
|
||||
/// No description provided for @language.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Language'**
|
||||
String get language;
|
||||
|
||||
/// No description provided for @russian.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Русский'**
|
||||
String get russian;
|
||||
|
||||
/// No description provided for @english.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'English'**
|
||||
String get english;
|
||||
|
||||
/// No description provided for @notifications.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Notifications'**
|
||||
String get notifications;
|
||||
|
||||
/// No description provided for @privacy.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Privacy'**
|
||||
String get privacy;
|
||||
|
||||
/// No description provided for @soundsAndVibration.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Sounds & Vibration'**
|
||||
String get soundsAndVibration;
|
||||
|
||||
/// No description provided for @dataAndStorage.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Data & Storage'**
|
||||
String get dataAndStorage;
|
||||
|
||||
/// No description provided for @aboutApp.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'About App'**
|
||||
String get aboutApp;
|
||||
|
||||
/// No description provided for @help.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Help'**
|
||||
String get help;
|
||||
|
||||
/// No description provided for @version.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Version'**
|
||||
String get version;
|
||||
|
||||
/// No description provided for @loading.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Loading...'**
|
||||
String get loading;
|
||||
|
||||
/// No description provided for @error.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Error'**
|
||||
String get error;
|
||||
|
||||
/// No description provided for @retry.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Retry'**
|
||||
String get retry;
|
||||
|
||||
/// No description provided for @noChats.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'No chats yet'**
|
||||
String get noChats;
|
||||
|
||||
/// No description provided for @inDevelopment.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'In development'**
|
||||
String get inDevelopment;
|
||||
|
||||
/// No description provided for @user.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'User'**
|
||||
String get user;
|
||||
|
||||
/// No description provided for @edit.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Edit'**
|
||||
String get edit;
|
||||
|
||||
/// No description provided for @serverConnectionError.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Server connection error'**
|
||||
String get serverConnectionError;
|
||||
|
||||
/// No description provided for @settingsSaved.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Settings saved'**
|
||||
String get settingsSaved;
|
||||
}
|
||||
|
||||
class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
|
||||
const _AppLocalizationsDelegate();
|
||||
|
||||
@override
|
||||
Future<AppLocalizations> load(Locale locale) {
|
||||
return SynchronousFuture<AppLocalizations>(lookupAppLocalizations(locale));
|
||||
}
|
||||
|
||||
@override
|
||||
bool isSupported(Locale locale) => <String>['en', 'ru'].contains(locale.languageCode);
|
||||
|
||||
@override
|
||||
bool shouldReload(_AppLocalizationsDelegate old) => false;
|
||||
}
|
||||
|
||||
AppLocalizations lookupAppLocalizations(Locale locale) {
|
||||
|
||||
|
||||
// Lookup logic when only language code is specified.
|
||||
switch (locale.languageCode) {
|
||||
case 'en': return AppLocalizationsEn();
|
||||
case 'ru': return AppLocalizationsRu();
|
||||
}
|
||||
|
||||
throw FlutterError(
|
||||
'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely '
|
||||
'an issue with the localizations generation tool. Please file an issue '
|
||||
'on GitHub with a reproducible sample app and the gen-l10n configuration '
|
||||
'that was used.'
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
// ignore: unused_import
|
||||
import 'package:intl/intl.dart' as intl;
|
||||
import 'app_localizations.dart';
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
|
||||
/// The translations for English (`en`).
|
||||
class AppLocalizationsEn extends AppLocalizations {
|
||||
AppLocalizationsEn([String locale = 'en']) : super(locale);
|
||||
|
||||
@override
|
||||
String get appTitle => 'Messenger';
|
||||
|
||||
@override
|
||||
String get chats => 'Chats';
|
||||
|
||||
@override
|
||||
String get contacts => 'Contacts';
|
||||
|
||||
@override
|
||||
String get settings => 'Settings';
|
||||
|
||||
@override
|
||||
String get login => 'Login';
|
||||
|
||||
@override
|
||||
String get email => 'Email';
|
||||
|
||||
@override
|
||||
String get password => 'Password';
|
||||
|
||||
@override
|
||||
String get name => 'Name';
|
||||
|
||||
@override
|
||||
String get loginButton => 'Sign In';
|
||||
|
||||
@override
|
||||
String get register => 'Register';
|
||||
|
||||
@override
|
||||
String get noAccount => 'No account? Sign up';
|
||||
|
||||
@override
|
||||
String get logout => 'Sign Out';
|
||||
|
||||
@override
|
||||
String get serverSettings => 'Server Settings';
|
||||
|
||||
@override
|
||||
String get apiUrl => 'API URL';
|
||||
|
||||
@override
|
||||
String get apiUrlHint => 'https://api.example.com';
|
||||
|
||||
@override
|
||||
String get save => 'Save';
|
||||
|
||||
@override
|
||||
String get serverConfig => 'Server Configuration';
|
||||
|
||||
@override
|
||||
String get system => 'System';
|
||||
|
||||
@override
|
||||
String get stories => 'Stories';
|
||||
|
||||
@override
|
||||
String get chatsModule => 'Chats';
|
||||
|
||||
@override
|
||||
String get messages => 'Messages';
|
||||
|
||||
@override
|
||||
String get calls => 'Calls';
|
||||
|
||||
@override
|
||||
String get klipy => 'Klipy';
|
||||
|
||||
@override
|
||||
String get import => 'Import';
|
||||
|
||||
@override
|
||||
String get federation => 'Federation';
|
||||
|
||||
@override
|
||||
String get domainUrl => 'Domain';
|
||||
|
||||
@override
|
||||
String get enableRegistration => 'Registration Enabled';
|
||||
|
||||
@override
|
||||
String get enabled => 'Enabled';
|
||||
|
||||
@override
|
||||
String get disabled => 'Disabled';
|
||||
|
||||
@override
|
||||
String get language => 'Language';
|
||||
|
||||
@override
|
||||
String get russian => 'Русский';
|
||||
|
||||
@override
|
||||
String get english => 'English';
|
||||
|
||||
@override
|
||||
String get notifications => 'Notifications';
|
||||
|
||||
@override
|
||||
String get privacy => 'Privacy';
|
||||
|
||||
@override
|
||||
String get soundsAndVibration => 'Sounds & Vibration';
|
||||
|
||||
@override
|
||||
String get dataAndStorage => 'Data & Storage';
|
||||
|
||||
@override
|
||||
String get aboutApp => 'About App';
|
||||
|
||||
@override
|
||||
String get help => 'Help';
|
||||
|
||||
@override
|
||||
String get version => 'Version';
|
||||
|
||||
@override
|
||||
String get loading => 'Loading...';
|
||||
|
||||
@override
|
||||
String get error => 'Error';
|
||||
|
||||
@override
|
||||
String get retry => 'Retry';
|
||||
|
||||
@override
|
||||
String get noChats => 'No chats yet';
|
||||
|
||||
@override
|
||||
String get inDevelopment => 'In development';
|
||||
|
||||
@override
|
||||
String get user => 'User';
|
||||
|
||||
@override
|
||||
String get edit => 'Edit';
|
||||
|
||||
@override
|
||||
String get serverConnectionError => 'Server connection error';
|
||||
|
||||
@override
|
||||
String get settingsSaved => 'Settings saved';
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
// ignore: unused_import
|
||||
import 'package:intl/intl.dart' as intl;
|
||||
import 'app_localizations.dart';
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
|
||||
/// The translations for Russian (`ru`).
|
||||
class AppLocalizationsRu extends AppLocalizations {
|
||||
AppLocalizationsRu([String locale = 'ru']) : super(locale);
|
||||
|
||||
@override
|
||||
String get appTitle => 'Мессенджер';
|
||||
|
||||
@override
|
||||
String get chats => 'Чаты';
|
||||
|
||||
@override
|
||||
String get contacts => 'Контакты';
|
||||
|
||||
@override
|
||||
String get settings => 'Настройки';
|
||||
|
||||
@override
|
||||
String get login => 'Вход';
|
||||
|
||||
@override
|
||||
String get email => 'Email';
|
||||
|
||||
@override
|
||||
String get password => 'Пароль';
|
||||
|
||||
@override
|
||||
String get name => 'Имя';
|
||||
|
||||
@override
|
||||
String get loginButton => 'Войти';
|
||||
|
||||
@override
|
||||
String get register => 'Зарегистрироваться';
|
||||
|
||||
@override
|
||||
String get noAccount => 'Нет аккаунта? Зарегистрироваться';
|
||||
|
||||
@override
|
||||
String get logout => 'Выйти из аккаунта';
|
||||
|
||||
@override
|
||||
String get serverSettings => 'Настройки сервера';
|
||||
|
||||
@override
|
||||
String get apiUrl => 'Адрес API';
|
||||
|
||||
@override
|
||||
String get apiUrlHint => 'https://api.example.com';
|
||||
|
||||
@override
|
||||
String get save => 'Сохранить';
|
||||
|
||||
@override
|
||||
String get serverConfig => 'Конфигурация сервера';
|
||||
|
||||
@override
|
||||
String get system => 'Система';
|
||||
|
||||
@override
|
||||
String get stories => 'Истории';
|
||||
|
||||
@override
|
||||
String get chatsModule => 'Чаты';
|
||||
|
||||
@override
|
||||
String get messages => 'Сообщения';
|
||||
|
||||
@override
|
||||
String get calls => 'Звонки';
|
||||
|
||||
@override
|
||||
String get klipy => 'Клипы';
|
||||
|
||||
@override
|
||||
String get import => 'Импорт';
|
||||
|
||||
@override
|
||||
String get federation => 'Федерация';
|
||||
|
||||
@override
|
||||
String get domainUrl => 'Домен';
|
||||
|
||||
@override
|
||||
String get enableRegistration => 'Регистрация включена';
|
||||
|
||||
@override
|
||||
String get enabled => 'Включено';
|
||||
|
||||
@override
|
||||
String get disabled => 'Отключено';
|
||||
|
||||
@override
|
||||
String get language => 'Язык';
|
||||
|
||||
@override
|
||||
String get russian => 'Русский';
|
||||
|
||||
@override
|
||||
String get english => 'English';
|
||||
|
||||
@override
|
||||
String get notifications => 'Уведомления';
|
||||
|
||||
@override
|
||||
String get privacy => 'Конфиденциальность';
|
||||
|
||||
@override
|
||||
String get soundsAndVibration => 'Звуки и вибрация';
|
||||
|
||||
@override
|
||||
String get dataAndStorage => 'Данные и память';
|
||||
|
||||
@override
|
||||
String get aboutApp => 'О приложении';
|
||||
|
||||
@override
|
||||
String get help => 'Помощь';
|
||||
|
||||
@override
|
||||
String get version => 'Версия';
|
||||
|
||||
@override
|
||||
String get loading => 'Загрузка...';
|
||||
|
||||
@override
|
||||
String get error => 'Ошибка';
|
||||
|
||||
@override
|
||||
String get retry => 'Повторить';
|
||||
|
||||
@override
|
||||
String get noChats => 'У вас пока нет чатов';
|
||||
|
||||
@override
|
||||
String get inDevelopment => 'Функция в разработке';
|
||||
|
||||
@override
|
||||
String get user => 'Пользователь';
|
||||
|
||||
@override
|
||||
String get edit => 'Редактировать';
|
||||
|
||||
@override
|
||||
String get serverConnectionError => 'Ошибка подключения к серверу';
|
||||
|
||||
@override
|
||||
String get settingsSaved => 'Настройки сохранены';
|
||||
}
|
||||
@@ -0,0 +1,424 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import '../l10n/app_localizations.dart';
|
||||
import '../../domain/entities/server_config.dart';
|
||||
import '../bloc/settings_bloc.dart';
|
||||
import '../bloc/settings_event.dart';
|
||||
import '../bloc/settings_state.dart';
|
||||
|
||||
class SettingsPage extends StatelessWidget {
|
||||
const SettingsPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<SettingsBloc, SettingsState>(
|
||||
builder: (context, state) {
|
||||
return state.when(
|
||||
initial: () => const Center(child: CircularProgressIndicator()),
|
||||
loading: () => const Center(child: CircularProgressIndicator()),
|
||||
loaded: (apiUrl, serverConfig, languageCode, error) => _SettingsContent(
|
||||
apiUrl: apiUrl,
|
||||
serverConfig: serverConfig,
|
||||
languageCode: languageCode,
|
||||
error: error,
|
||||
),
|
||||
error: (message) => Center(child: Text(message)),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _SettingsContent extends StatelessWidget {
|
||||
final String apiUrl;
|
||||
final ServerConfig? serverConfig;
|
||||
final String languageCode;
|
||||
final String? error;
|
||||
|
||||
const _SettingsContent({
|
||||
required this.apiUrl,
|
||||
required this.serverConfig,
|
||||
required this.languageCode,
|
||||
this.error,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
|
||||
return ListView(
|
||||
children: [
|
||||
_SectionHeader(title: l10n.serverSettings),
|
||||
_ApiUrlTile(
|
||||
apiUrl: apiUrl,
|
||||
onSave: (url) {
|
||||
context.read<SettingsBloc>().add(SettingsApiUrlSaved(url));
|
||||
},
|
||||
),
|
||||
const Divider(),
|
||||
|
||||
_SectionHeader(title: l10n.language),
|
||||
_LanguageTile(
|
||||
currentCode: languageCode,
|
||||
onChanged: (code) {
|
||||
context.read<SettingsBloc>().add(SettingsLanguageChanged(code));
|
||||
},
|
||||
),
|
||||
const Divider(),
|
||||
|
||||
if (serverConfig != null) ...[
|
||||
_SectionHeader(title: l10n.serverConfig),
|
||||
_ConfigModuleCard(
|
||||
title: l10n.system,
|
||||
icon: Icons.computer,
|
||||
children: [
|
||||
_ConfigItem(label: l10n.domainUrl, value: serverConfig!.system.domainUrl),
|
||||
_ConfigItem(label: l10n.enableRegistration, value: serverConfig!.system.enableRegistration ? l10n.enabled : l10n.disabled),
|
||||
],
|
||||
),
|
||||
_ConfigModuleCard(
|
||||
title: l10n.messages,
|
||||
icon: Icons.message,
|
||||
children: [
|
||||
_ConfigItem(label: l10n.enabled, value: serverConfig!.messages.allowMedia ? l10n.enabled : l10n.disabled),
|
||||
_ConfigItem(label: 'Max media size', value: '${(serverConfig!.messages.maxMediaSizeBytes / 1024 / 1024).toStringAsFixed(1)} MB'),
|
||||
],
|
||||
),
|
||||
_ConfigModuleCard(
|
||||
title: l10n.calls,
|
||||
icon: Icons.call,
|
||||
children: [
|
||||
_ConfigItem(label: l10n.enabled, value: serverConfig!.webRtc.enabled ? l10n.enabled : l10n.disabled),
|
||||
_ConfigItem(label: 'Voice calls', value: serverConfig!.webRtc.enableVoiceCalls ? l10n.enabled : l10n.disabled),
|
||||
_ConfigItem(label: 'Video calls', value: serverConfig!.webRtc.enableVideoCalls ? l10n.enabled : l10n.disabled),
|
||||
],
|
||||
),
|
||||
_ConfigModuleCard(
|
||||
title: l10n.stories,
|
||||
icon: Icons.auto_stories,
|
||||
children: [
|
||||
_ConfigItem(label: l10n.enabled, value: serverConfig!.stories.enabled ? l10n.enabled : l10n.disabled),
|
||||
_ConfigItem(label: 'Lifetime', value: '${serverConfig!.stories.storyLifetimeHours}h'),
|
||||
],
|
||||
),
|
||||
_ConfigModuleCard(
|
||||
title: l10n.chatsModule,
|
||||
icon: Icons.chat_bubble,
|
||||
children: [
|
||||
_ConfigItem(label: 'Groups', value: serverConfig!.chats.supportGroups ? l10n.enabled : l10n.disabled),
|
||||
_ConfigItem(label: 'Max participants', value: '${serverConfig!.chats.maxGroupParticipants}'),
|
||||
],
|
||||
),
|
||||
if (serverConfig!.federation.enabled)
|
||||
_ConfigModuleCard(
|
||||
title: l10n.federation,
|
||||
icon: Icons.public,
|
||||
children: [
|
||||
_ConfigItem(label: 'Description', value: serverConfig!.federation.serverDescription),
|
||||
],
|
||||
),
|
||||
const Divider(),
|
||||
],
|
||||
|
||||
if (serverConfig == null)
|
||||
ListTile(
|
||||
leading: const Icon(Icons.refresh),
|
||||
title: Text(l10n.retry),
|
||||
onTap: () {
|
||||
context.read<SettingsBloc>().add(const SettingsRefreshConfig());
|
||||
},
|
||||
),
|
||||
|
||||
_SectionHeader(title: l10n.settings),
|
||||
_SettingsTile(
|
||||
icon: Icons.notifications_outlined,
|
||||
title: l10n.notifications,
|
||||
onTap: () {},
|
||||
),
|
||||
_SettingsTile(
|
||||
icon: Icons.security,
|
||||
title: l10n.privacy,
|
||||
onTap: () {},
|
||||
),
|
||||
_SettingsTile(
|
||||
icon: Icons.volume_up,
|
||||
title: l10n.soundsAndVibration,
|
||||
onTap: () {},
|
||||
),
|
||||
_SettingsTile(
|
||||
icon: Icons.storage,
|
||||
title: l10n.dataAndStorage,
|
||||
onTap: () {},
|
||||
),
|
||||
const Divider(),
|
||||
|
||||
_SettingsTile(
|
||||
icon: Icons.info_outline,
|
||||
title: l10n.aboutApp,
|
||||
subtitle: '${l10n.version} 1.0.0',
|
||||
onTap: () {},
|
||||
),
|
||||
_SettingsTile(
|
||||
icon: Icons.help_outline,
|
||||
title: l10n.help,
|
||||
onTap: () {},
|
||||
),
|
||||
const Divider(),
|
||||
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: OutlinedButton(
|
||||
onPressed: () {},
|
||||
style: OutlinedButton.styleFrom(
|
||||
foregroundColor: Colors.red,
|
||||
side: const BorderSide(color: Colors.red),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
child: Text(l10n.logout),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _SectionHeader extends StatelessWidget {
|
||||
final String title;
|
||||
|
||||
const _SectionHeader({required this.title});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 16, 16, 8),
|
||||
child: Text(
|
||||
title.toUpperCase(),
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
letterSpacing: 0.5,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ApiUrlTile extends StatefulWidget {
|
||||
final String apiUrl;
|
||||
final ValueChanged<String> onSave;
|
||||
|
||||
const _ApiUrlTile({
|
||||
required this.apiUrl,
|
||||
required this.onSave,
|
||||
});
|
||||
|
||||
@override
|
||||
State<_ApiUrlTile> createState() => _ApiUrlTileState();
|
||||
}
|
||||
|
||||
class _ApiUrlTileState extends State<_ApiUrlTile> {
|
||||
late final TextEditingController _controller;
|
||||
bool _isEditing = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = TextEditingController(text: widget.apiUrl);
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant _ApiUrlTile oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (oldWidget.apiUrl != widget.apiUrl) {
|
||||
_controller.text = widget.apiUrl;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
|
||||
if (_isEditing) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: _controller,
|
||||
decoration: InputDecoration(
|
||||
labelText: l10n.apiUrl,
|
||||
hintText: l10n.apiUrlHint,
|
||||
border: const OutlineInputBorder(),
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||
),
|
||||
keyboardType: TextInputType.url,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.check, color: Colors.green),
|
||||
onPressed: () {
|
||||
widget.onSave(_controller.text.trim());
|
||||
setState(() => _isEditing = false);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.close, color: Colors.red),
|
||||
onPressed: () {
|
||||
_controller.text = widget.apiUrl;
|
||||
setState(() => _isEditing = false);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return ListTile(
|
||||
leading: const Icon(Icons.link),
|
||||
title: Text(l10n.apiUrl),
|
||||
subtitle: Text(
|
||||
widget.apiUrl.isEmpty ? l10n.apiUrlHint : widget.apiUrl,
|
||||
style: TextStyle(
|
||||
color: widget.apiUrl.isEmpty ? Colors.grey : null,
|
||||
),
|
||||
),
|
||||
trailing: const Icon(Icons.edit),
|
||||
onTap: () => setState(() => _isEditing = true),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _LanguageTile extends StatelessWidget {
|
||||
final String currentCode;
|
||||
final ValueChanged<String> onChanged;
|
||||
|
||||
const _LanguageTile({
|
||||
required this.currentCode,
|
||||
required this.onChanged,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
|
||||
return ListTile(
|
||||
leading: const Icon(Icons.language),
|
||||
title: Text(l10n.language),
|
||||
subtitle: Text(currentCode == 'ru' ? l10n.russian : l10n.english),
|
||||
trailing: DropdownButton<String>(
|
||||
value: currentCode,
|
||||
underline: const SizedBox(),
|
||||
items: [
|
||||
DropdownMenuItem(value: 'ru', child: Text(l10n.russian)),
|
||||
DropdownMenuItem(value: 'en', child: Text(l10n.english)),
|
||||
],
|
||||
onChanged: (value) {
|
||||
if (value != null) onChanged(value);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ConfigModuleCard extends StatelessWidget {
|
||||
final String title;
|
||||
final IconData icon;
|
||||
final List<Widget> children;
|
||||
|
||||
const _ConfigModuleCard({
|
||||
required this.title,
|
||||
required this.icon,
|
||||
required this.children,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Card(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
||||
child: ExpansionTile(
|
||||
leading: Icon(icon, color: Theme.of(context).colorScheme.primary),
|
||||
title: Text(title),
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 12),
|
||||
child: Column(
|
||||
children: children,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ConfigItem extends StatelessWidget {
|
||||
final String label;
|
||||
final String value;
|
||||
|
||||
const _ConfigItem({
|
||||
required this.label,
|
||||
required this.value,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
color: Colors.grey[600],
|
||||
fontSize: 13,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
value,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 13,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _SettingsTile extends StatelessWidget {
|
||||
final IconData icon;
|
||||
final String title;
|
||||
final String? subtitle;
|
||||
final VoidCallback onTap;
|
||||
|
||||
const _SettingsTile({
|
||||
required this.icon,
|
||||
required this.title,
|
||||
this.subtitle,
|
||||
required this.onTap,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListTile(
|
||||
leading: Icon(icon),
|
||||
title: Text(title),
|
||||
subtitle: subtitle != null ? Text(subtitle!) : null,
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
onTap: onTap,
|
||||
);
|
||||
}
|
||||
}
|
||||
53
client-mobile/lib/internal/di/injection_container.dart
Normal file
53
client-mobile/lib/internal/di/injection_container.dart
Normal file
@@ -0,0 +1,53 @@
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../../core/network/api_client.dart';
|
||||
import '../../features/auth/presentation/bloc/auth_bloc.dart';
|
||||
import '../../features/chat/presentation/bloc/chat_bloc.dart';
|
||||
import '../../features/settings/data/datasources/settings_local_datasource.dart';
|
||||
import '../../features/settings/data/datasources/settings_remote_datasource.dart';
|
||||
import '../../features/settings/data/repositories/settings_repository_impl.dart';
|
||||
import '../../features/settings/domain/repositories/settings_repository.dart';
|
||||
import '../../features/settings/presentation/bloc/settings_bloc.dart';
|
||||
|
||||
final sl = GetIt.instance;
|
||||
|
||||
Future<void> initDependencies() async {
|
||||
// Core - SharedPreferences
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
sl.registerLazySingleton<SharedPreferences>(() => prefs);
|
||||
|
||||
// Core - Settings Local DataSource
|
||||
sl.registerLazySingleton<SettingsLocalDataSource>(
|
||||
() => SettingsLocalDataSourceImpl(sl()),
|
||||
);
|
||||
|
||||
// Core - Dio (with dynamic base URL from settings)
|
||||
sl.registerLazySingleton<Dio>(() {
|
||||
final apiUrl = prefs.getString('api_url') ?? 'https://api.messenger.app';
|
||||
return Dio(BaseOptions(
|
||||
baseUrl: apiUrl,
|
||||
connectTimeout: const Duration(seconds: 30),
|
||||
receiveTimeout: const Duration(seconds: 30),
|
||||
));
|
||||
});
|
||||
|
||||
// Core - API Client
|
||||
sl.registerLazySingleton<ApiClient>(() => ApiClient(sl()));
|
||||
|
||||
// Settings
|
||||
sl.registerLazySingleton<SettingsRemoteDataSource>(
|
||||
() => SettingsRemoteDataSourceImpl(sl()),
|
||||
);
|
||||
sl.registerLazySingleton<SettingsRepository>(
|
||||
() => SettingsRepositoryImpl(sl(), sl()),
|
||||
);
|
||||
sl.registerFactory<SettingsBloc>(() => SettingsBloc(sl()));
|
||||
|
||||
// Auth
|
||||
sl.registerFactory<AuthBloc>(() => AuthBloc());
|
||||
|
||||
// Chat
|
||||
sl.registerFactory<ChatBloc>(() => ChatBloc());
|
||||
}
|
||||
21
client-mobile/lib/internal/router/chats_placeholder.dart
Normal file
21
client-mobile/lib/internal/router/chats_placeholder.dart
Normal file
@@ -0,0 +1,21 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ChatsPage extends StatelessWidget {
|
||||
const ChatsPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(Icons.chat_bubble_outline, size: 64, color: Colors.grey),
|
||||
SizedBox(height: 16),
|
||||
Text('Чаты', style: TextStyle(fontSize: 18)),
|
||||
SizedBox(height: 8),
|
||||
Text('Функция в разработке', style: TextStyle(color: Colors.grey)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
104
client-mobile/lib/internal/router/main_screen.dart
Normal file
104
client-mobile/lib/internal/router/main_screen.dart
Normal file
@@ -0,0 +1,104 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import '../../features/auth/presentation/bloc/auth_bloc.dart';
|
||||
import '../../features/auth/presentation/bloc/auth_state.dart';
|
||||
import '../../features/auth/presentation/pages/login_page.dart';
|
||||
import '../../features/settings/presentation/pages/settings_page.dart';
|
||||
import '../router/chats_placeholder.dart';
|
||||
|
||||
class MainScreen extends StatefulWidget {
|
||||
static const String routeName = '/main';
|
||||
|
||||
const MainScreen({super.key});
|
||||
|
||||
@override
|
||||
State<MainScreen> createState() => _MainScreenState();
|
||||
}
|
||||
|
||||
class _MainScreenState extends State<MainScreen> {
|
||||
int _currentIndex = 0;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: IndexedStack(
|
||||
index: _currentIndex,
|
||||
children: const [
|
||||
ChatsTab(),
|
||||
ContactsTab(),
|
||||
SettingsTab(),
|
||||
],
|
||||
),
|
||||
bottomNavigationBar: BottomNavigationBar(
|
||||
currentIndex: _currentIndex,
|
||||
onTap: (index) => setState(() => _currentIndex = index),
|
||||
type: BottomNavigationBarType.fixed,
|
||||
items: const [
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(Icons.chat_bubble_outline),
|
||||
activeIcon: Icon(Icons.chat_bubble),
|
||||
label: 'Чаты',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(Icons.contacts_outlined),
|
||||
activeIcon: Icon(Icons.contacts),
|
||||
label: 'Контакты',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(Icons.settings_outlined),
|
||||
activeIcon: Icon(Icons.settings),
|
||||
label: 'Настройки',
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ChatsTab extends StatelessWidget {
|
||||
const ChatsTab({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const ChatsPage();
|
||||
}
|
||||
}
|
||||
|
||||
class ContactsTab extends StatelessWidget {
|
||||
const ContactsTab({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(Icons.contacts_outlined, size: 64, color: Colors.grey),
|
||||
SizedBox(height: 16),
|
||||
Text('Контакты', style: TextStyle(fontSize: 18)),
|
||||
SizedBox(height: 8),
|
||||
Text('Функция в разработке', style: TextStyle(color: Colors.grey)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SettingsTab extends StatelessWidget {
|
||||
const SettingsTab({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<AuthBloc, AuthState>(
|
||||
builder: (context, authState) {
|
||||
return authState.when(
|
||||
initial: () => const Center(child: CircularProgressIndicator()),
|
||||
loading: () => const Center(child: CircularProgressIndicator()),
|
||||
authenticated: (_) => const SettingsPage(),
|
||||
unauthenticated: () => const LoginPage(),
|
||||
error: (_) => const LoginPage(),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
417
client-mobile/lib/l10n/app_localizations.dart
Normal file
417
client-mobile/lib/l10n/app_localizations.dart
Normal file
@@ -0,0 +1,417 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:intl/intl.dart' as intl;
|
||||
|
||||
import 'app_localizations_en.dart';
|
||||
import 'app_localizations_ru.dart';
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
|
||||
/// Callers can lookup localized strings with an instance of AppLocalizations
|
||||
/// returned by `AppLocalizations.of(context)`.
|
||||
///
|
||||
/// Applications need to include `AppLocalizations.delegate()` in their app's
|
||||
/// `localizationDelegates` list, and the locales they support in the app's
|
||||
/// `supportedLocales` list. For example:
|
||||
///
|
||||
/// ```dart
|
||||
/// import 'l10n/app_localizations.dart';
|
||||
///
|
||||
/// return MaterialApp(
|
||||
/// localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
/// supportedLocales: AppLocalizations.supportedLocales,
|
||||
/// home: MyApplicationHome(),
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// ## Update pubspec.yaml
|
||||
///
|
||||
/// Please make sure to update your pubspec.yaml to include the following
|
||||
/// packages:
|
||||
///
|
||||
/// ```yaml
|
||||
/// dependencies:
|
||||
/// # Internationalization support.
|
||||
/// flutter_localizations:
|
||||
/// sdk: flutter
|
||||
/// intl: any # Use the pinned version from flutter_localizations
|
||||
///
|
||||
/// # Rest of dependencies
|
||||
/// ```
|
||||
///
|
||||
/// ## iOS Applications
|
||||
///
|
||||
/// iOS applications define key application metadata, including supported
|
||||
/// locales, in an Info.plist file that is built into the application bundle.
|
||||
/// To configure the locales supported by your app, you’ll need to edit this
|
||||
/// file.
|
||||
///
|
||||
/// First, open your project’s ios/Runner.xcworkspace Xcode workspace file.
|
||||
/// Then, in the Project Navigator, open the Info.plist file under the Runner
|
||||
/// project’s Runner folder.
|
||||
///
|
||||
/// Next, select the Information Property List item, select Add Item from the
|
||||
/// Editor menu, then select Localizations from the pop-up menu.
|
||||
///
|
||||
/// Select and expand the newly-created Localizations item then, for each
|
||||
/// locale your application supports, add a new item and select the locale
|
||||
/// you wish to add from the pop-up menu in the Value field. This list should
|
||||
/// be consistent with the languages listed in the AppLocalizations.supportedLocales
|
||||
/// property.
|
||||
abstract class AppLocalizations {
|
||||
AppLocalizations(String locale) : localeName = intl.Intl.canonicalizedLocale(locale.toString());
|
||||
|
||||
final String localeName;
|
||||
|
||||
static AppLocalizations? of(BuildContext context) {
|
||||
return Localizations.of<AppLocalizations>(context, AppLocalizations);
|
||||
}
|
||||
|
||||
static const LocalizationsDelegate<AppLocalizations> delegate = _AppLocalizationsDelegate();
|
||||
|
||||
/// A list of this localizations delegate along with the default localizations
|
||||
/// delegates.
|
||||
///
|
||||
/// Returns a list of localizations delegates containing this delegate along with
|
||||
/// GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate,
|
||||
/// and GlobalWidgetsLocalizations.delegate.
|
||||
///
|
||||
/// Additional delegates can be added by appending to this list in
|
||||
/// MaterialApp. This list does not have to be used at all if a custom list
|
||||
/// of delegates is preferred or required.
|
||||
static const List<LocalizationsDelegate<dynamic>> localizationsDelegates = <LocalizationsDelegate<dynamic>>[
|
||||
delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
];
|
||||
|
||||
/// A list of this localizations delegate's supported locales.
|
||||
static const List<Locale> supportedLocales = <Locale>[
|
||||
Locale('en'),
|
||||
Locale('ru')
|
||||
];
|
||||
|
||||
/// No description provided for @appTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Messenger'**
|
||||
String get appTitle;
|
||||
|
||||
/// No description provided for @chats.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Chats'**
|
||||
String get chats;
|
||||
|
||||
/// No description provided for @contacts.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Contacts'**
|
||||
String get contacts;
|
||||
|
||||
/// No description provided for @settings.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Settings'**
|
||||
String get settings;
|
||||
|
||||
/// No description provided for @login.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Login'**
|
||||
String get login;
|
||||
|
||||
/// No description provided for @email.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Email'**
|
||||
String get email;
|
||||
|
||||
/// No description provided for @password.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Password'**
|
||||
String get password;
|
||||
|
||||
/// No description provided for @name.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Name'**
|
||||
String get name;
|
||||
|
||||
/// No description provided for @loginButton.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Sign In'**
|
||||
String get loginButton;
|
||||
|
||||
/// No description provided for @register.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Register'**
|
||||
String get register;
|
||||
|
||||
/// No description provided for @noAccount.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'No account? Sign up'**
|
||||
String get noAccount;
|
||||
|
||||
/// No description provided for @logout.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Sign Out'**
|
||||
String get logout;
|
||||
|
||||
/// No description provided for @serverSettings.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Server Settings'**
|
||||
String get serverSettings;
|
||||
|
||||
/// No description provided for @apiUrl.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'API URL'**
|
||||
String get apiUrl;
|
||||
|
||||
/// No description provided for @apiUrlHint.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'https://api.example.com'**
|
||||
String get apiUrlHint;
|
||||
|
||||
/// No description provided for @save.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Save'**
|
||||
String get save;
|
||||
|
||||
/// No description provided for @serverConfig.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Server Configuration'**
|
||||
String get serverConfig;
|
||||
|
||||
/// No description provided for @system.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'System'**
|
||||
String get system;
|
||||
|
||||
/// No description provided for @stories.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Stories'**
|
||||
String get stories;
|
||||
|
||||
/// No description provided for @chatsModule.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Chats'**
|
||||
String get chatsModule;
|
||||
|
||||
/// No description provided for @messages.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Messages'**
|
||||
String get messages;
|
||||
|
||||
/// No description provided for @calls.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Calls'**
|
||||
String get calls;
|
||||
|
||||
/// No description provided for @klipy.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Klipy'**
|
||||
String get klipy;
|
||||
|
||||
/// No description provided for @import.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Import'**
|
||||
String get import;
|
||||
|
||||
/// No description provided for @federation.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Federation'**
|
||||
String get federation;
|
||||
|
||||
/// No description provided for @domainUrl.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Domain'**
|
||||
String get domainUrl;
|
||||
|
||||
/// No description provided for @enableRegistration.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Registration Enabled'**
|
||||
String get enableRegistration;
|
||||
|
||||
/// No description provided for @enabled.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Enabled'**
|
||||
String get enabled;
|
||||
|
||||
/// No description provided for @disabled.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Disabled'**
|
||||
String get disabled;
|
||||
|
||||
/// No description provided for @language.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Language'**
|
||||
String get language;
|
||||
|
||||
/// No description provided for @russian.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Русский'**
|
||||
String get russian;
|
||||
|
||||
/// No description provided for @english.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'English'**
|
||||
String get english;
|
||||
|
||||
/// No description provided for @notifications.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Notifications'**
|
||||
String get notifications;
|
||||
|
||||
/// No description provided for @privacy.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Privacy'**
|
||||
String get privacy;
|
||||
|
||||
/// No description provided for @soundsAndVibration.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Sounds & Vibration'**
|
||||
String get soundsAndVibration;
|
||||
|
||||
/// No description provided for @dataAndStorage.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Data & Storage'**
|
||||
String get dataAndStorage;
|
||||
|
||||
/// No description provided for @aboutApp.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'About App'**
|
||||
String get aboutApp;
|
||||
|
||||
/// No description provided for @help.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Help'**
|
||||
String get help;
|
||||
|
||||
/// No description provided for @version.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Version'**
|
||||
String get version;
|
||||
|
||||
/// No description provided for @loading.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Loading...'**
|
||||
String get loading;
|
||||
|
||||
/// No description provided for @error.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Error'**
|
||||
String get error;
|
||||
|
||||
/// No description provided for @retry.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Retry'**
|
||||
String get retry;
|
||||
|
||||
/// No description provided for @noChats.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'No chats yet'**
|
||||
String get noChats;
|
||||
|
||||
/// No description provided for @inDevelopment.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'In development'**
|
||||
String get inDevelopment;
|
||||
|
||||
/// No description provided for @user.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'User'**
|
||||
String get user;
|
||||
|
||||
/// No description provided for @edit.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Edit'**
|
||||
String get edit;
|
||||
|
||||
/// No description provided for @serverConnectionError.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Server connection error'**
|
||||
String get serverConnectionError;
|
||||
|
||||
/// No description provided for @settingsSaved.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Settings saved'**
|
||||
String get settingsSaved;
|
||||
}
|
||||
|
||||
class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
|
||||
const _AppLocalizationsDelegate();
|
||||
|
||||
@override
|
||||
Future<AppLocalizations> load(Locale locale) {
|
||||
return SynchronousFuture<AppLocalizations>(lookupAppLocalizations(locale));
|
||||
}
|
||||
|
||||
@override
|
||||
bool isSupported(Locale locale) => <String>['en', 'ru'].contains(locale.languageCode);
|
||||
|
||||
@override
|
||||
bool shouldReload(_AppLocalizationsDelegate old) => false;
|
||||
}
|
||||
|
||||
AppLocalizations lookupAppLocalizations(Locale locale) {
|
||||
|
||||
|
||||
// Lookup logic when only language code is specified.
|
||||
switch (locale.languageCode) {
|
||||
case 'en': return AppLocalizationsEn();
|
||||
case 'ru': return AppLocalizationsRu();
|
||||
}
|
||||
|
||||
throw FlutterError(
|
||||
'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely '
|
||||
'an issue with the localizations generation tool. Please file an issue '
|
||||
'on GitHub with a reproducible sample app and the gen-l10n configuration '
|
||||
'that was used.'
|
||||
);
|
||||
}
|
||||
154
client-mobile/lib/l10n/app_localizations_en.dart
Normal file
154
client-mobile/lib/l10n/app_localizations_en.dart
Normal file
@@ -0,0 +1,154 @@
|
||||
// ignore: unused_import
|
||||
import 'package:intl/intl.dart' as intl;
|
||||
import 'app_localizations.dart';
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
|
||||
/// The translations for English (`en`).
|
||||
class AppLocalizationsEn extends AppLocalizations {
|
||||
AppLocalizationsEn([String locale = 'en']) : super(locale);
|
||||
|
||||
@override
|
||||
String get appTitle => 'Messenger';
|
||||
|
||||
@override
|
||||
String get chats => 'Chats';
|
||||
|
||||
@override
|
||||
String get contacts => 'Contacts';
|
||||
|
||||
@override
|
||||
String get settings => 'Settings';
|
||||
|
||||
@override
|
||||
String get login => 'Login';
|
||||
|
||||
@override
|
||||
String get email => 'Email';
|
||||
|
||||
@override
|
||||
String get password => 'Password';
|
||||
|
||||
@override
|
||||
String get name => 'Name';
|
||||
|
||||
@override
|
||||
String get loginButton => 'Sign In';
|
||||
|
||||
@override
|
||||
String get register => 'Register';
|
||||
|
||||
@override
|
||||
String get noAccount => 'No account? Sign up';
|
||||
|
||||
@override
|
||||
String get logout => 'Sign Out';
|
||||
|
||||
@override
|
||||
String get serverSettings => 'Server Settings';
|
||||
|
||||
@override
|
||||
String get apiUrl => 'API URL';
|
||||
|
||||
@override
|
||||
String get apiUrlHint => 'https://api.example.com';
|
||||
|
||||
@override
|
||||
String get save => 'Save';
|
||||
|
||||
@override
|
||||
String get serverConfig => 'Server Configuration';
|
||||
|
||||
@override
|
||||
String get system => 'System';
|
||||
|
||||
@override
|
||||
String get stories => 'Stories';
|
||||
|
||||
@override
|
||||
String get chatsModule => 'Chats';
|
||||
|
||||
@override
|
||||
String get messages => 'Messages';
|
||||
|
||||
@override
|
||||
String get calls => 'Calls';
|
||||
|
||||
@override
|
||||
String get klipy => 'Klipy';
|
||||
|
||||
@override
|
||||
String get import => 'Import';
|
||||
|
||||
@override
|
||||
String get federation => 'Federation';
|
||||
|
||||
@override
|
||||
String get domainUrl => 'Domain';
|
||||
|
||||
@override
|
||||
String get enableRegistration => 'Registration Enabled';
|
||||
|
||||
@override
|
||||
String get enabled => 'Enabled';
|
||||
|
||||
@override
|
||||
String get disabled => 'Disabled';
|
||||
|
||||
@override
|
||||
String get language => 'Language';
|
||||
|
||||
@override
|
||||
String get russian => 'Русский';
|
||||
|
||||
@override
|
||||
String get english => 'English';
|
||||
|
||||
@override
|
||||
String get notifications => 'Notifications';
|
||||
|
||||
@override
|
||||
String get privacy => 'Privacy';
|
||||
|
||||
@override
|
||||
String get soundsAndVibration => 'Sounds & Vibration';
|
||||
|
||||
@override
|
||||
String get dataAndStorage => 'Data & Storage';
|
||||
|
||||
@override
|
||||
String get aboutApp => 'About App';
|
||||
|
||||
@override
|
||||
String get help => 'Help';
|
||||
|
||||
@override
|
||||
String get version => 'Version';
|
||||
|
||||
@override
|
||||
String get loading => 'Loading...';
|
||||
|
||||
@override
|
||||
String get error => 'Error';
|
||||
|
||||
@override
|
||||
String get retry => 'Retry';
|
||||
|
||||
@override
|
||||
String get noChats => 'No chats yet';
|
||||
|
||||
@override
|
||||
String get inDevelopment => 'In development';
|
||||
|
||||
@override
|
||||
String get user => 'User';
|
||||
|
||||
@override
|
||||
String get edit => 'Edit';
|
||||
|
||||
@override
|
||||
String get serverConnectionError => 'Server connection error';
|
||||
|
||||
@override
|
||||
String get settingsSaved => 'Settings saved';
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user