Приложение на флаторе, настройки

This commit is contained in:
Халимов Рустам
2026-05-13 17:21:37 +03:00
parent 89e325556c
commit e8161d23d4
119 changed files with 18469 additions and 0 deletions

44
client-mobile/.gitignore vendored Normal file
View 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
View 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

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

View 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
View File

@@ -0,0 +1,7 @@
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java

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

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

View File

@@ -0,0 +1,5 @@
package com.example.messenger_app
import io.flutter.embedding.android.FlutterActivity
class MainActivity: FlutterActivity()

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

@@ -0,0 +1,3 @@
org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true
android.enableJetifier=true

View 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

View 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"

View 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

View 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 --")

View File

@@ -0,0 +1,5 @@
#
# Generated file, do not edit.
#
command script import --relative-to-command-file flutter_lldb_helper.py

View 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"

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

View 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 */

View 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
View File

@@ -0,0 +1,4 @@
arb-dir: l10n
template-arb-file: app_ru.arb
output-localization-file: app_localizations.dart
output-class: AppLocalizations

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

View 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, youll need to edit this
/// file.
///
/// First, open your projects ios/Runner.xcworkspace Xcode workspace file.
/// Then, in the Project Navigator, open the Info.plist file under the Runner
/// projects 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.');
}

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

View 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 => 'Настройки сохранены';
}

View 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": "Настройки сохранены"
}

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

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

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

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

File diff suppressed because it is too large Load Diff

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

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

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

View File

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

View File

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

View File

@@ -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);
}
}

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

View File

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

View File

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

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

View File

@@ -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) {}
}

View File

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

View File

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

View File

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

View File

@@ -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('Нет аккаунта? Зарегистрироваться'),
),
],
),
),
),
),
),
);
}
}

View File

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

View File

@@ -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);
}

View File

@@ -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);
}
}

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

View File

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

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

View File

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

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

View File

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

View File

@@ -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);
}

View File

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

View File

@@ -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 {}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -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);
}

View File

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

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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'));
}
}
}

View File

@@ -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);
}
}

View File

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

View File

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

View File

@@ -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);
}

View File

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

View File

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

View File

@@ -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);
}
}

View File

@@ -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));
}
}

View File

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

View File

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

View File

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

View File

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

View 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, youll need to edit this
/// file.
///
/// First, open your projects ios/Runner.xcworkspace Xcode workspace file.
/// Then, in the Project Navigator, open the Info.plist file under the Runner
/// projects 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.'
);
}

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

View 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 => 'Настройки сохранены';
}

View File

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

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

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

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

View 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, youll need to edit this
/// file.
///
/// First, open your projects ios/Runner.xcworkspace Xcode workspace file.
/// Then, in the Project Navigator, open the Info.plist file under the Runner
/// projects 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.'
);
}

View 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