diff --git a/android/app/build.gradle b/android/app/build.gradle index 4c483ee5..7b3371b2 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -1,7 +1,9 @@ -plugins{ - id 'com.android.application' - id 'kotlin-android' +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()) { @@ -10,11 +12,6 @@ if (localPropertiesFile.exists()) { } } -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - def flutterVersionCode = localProperties.getProperty('flutter.versionCode') if (flutterVersionCode == null) { flutterVersionCode = '1' @@ -25,11 +22,18 @@ if (flutterVersionName == null) { flutterVersionName = '1.0' } -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - android { compileSdkVersion flutter.compileSdkVersion + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + sourceSets { main.java.srcDirs += 'src/main/kotlin' } @@ -61,7 +65,4 @@ flutter { source '../..' } -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation "androidx.multidex:multidex:2.0.1" -} +dependencies {} diff --git a/android/build.gradle b/android/build.gradle index d7f8aafa..bc157bd1 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,20 +1,7 @@ -buildscript { - ext.kotlin_version = '1.7.20' - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:7.2.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - allprojects { repositories { google() - jcenter() + mavenCentral() } } diff --git a/android/gradle.properties b/android/gradle.properties index 94adc3a3..598d13fe 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 6b665338..e1ca574e 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Fri Jun 23 08:50:38 CEST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip diff --git a/android/settings.gradle b/android/settings.gradle index 44e62bcf..1d6d19b7 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1,11 +1,26 @@ -include ':app' +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 + } + settings.ext.flutterSdkPath = flutterSdkPath() -def localPropertiesFile = new File(rootProject.projectDir, "local.properties") -def properties = new Properties() + includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle") -assert localPropertiesFile.exists() -localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} -def flutterSdkPath = properties.getProperty("flutter.sdk") -assert flutterSdkPath != null, "flutter.sdk not set in local.properties" -apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + id "com.android.application" version "7.3.0" apply false + id "org.jetbrains.kotlin.android" version "1.7.10" apply false +} + +include ":app" diff --git a/assets/fonts/MulishBold.ttf b/assets/fonts/MulishBold.ttf index 0c1eed73..e69de29b 100644 Binary files a/assets/fonts/MulishBold.ttf and b/assets/fonts/MulishBold.ttf differ diff --git a/assets/fonts/MulishRegular.ttf b/assets/fonts/MulishRegular.ttf index 0971518b..e69de29b 100644 Binary files a/assets/fonts/MulishRegular.ttf and b/assets/fonts/MulishRegular.ttf differ diff --git a/assets/fonts/MulishSemiBold.ttf b/assets/fonts/MulishSemiBold.ttf index 9ac1fc8f..e69de29b 100644 Binary files a/assets/fonts/MulishSemiBold.ttf and b/assets/fonts/MulishSemiBold.ttf differ diff --git a/assets/fonts/SegoeUISemibold.ttf b/assets/fonts/SegoeUISemibold.ttf index 46b3b993..e69de29b 100644 Binary files a/assets/fonts/SegoeUISemibold.ttf and b/assets/fonts/SegoeUISemibold.ttf differ diff --git a/devtools_options.yaml b/devtools_options.yaml index 7e7e7f67..5c27c3e3 100644 --- a/devtools_options.yaml +++ b/devtools_options.yaml @@ -1 +1,2 @@ extensions: + - provider: true \ No newline at end of file diff --git a/lib/app_router.dart b/lib/app_router.dart index c6de2d5a..8cdc75a2 100644 --- a/lib/app_router.dart +++ b/lib/app_router.dart @@ -1,6 +1,7 @@ +import 'package:eatvio_app/core/token_storage.dart'; +import 'package:eatvio_app/features/chat/presentation/pages/chat_screen.dart'; +import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen/chat_select_screen.dart'; import 'package:eatvio_app/presentation/auth/auth_screen/auth_screen.dart'; -import 'package:eatvio_app/presentation/chat/chat_screen/chat_screen.dart'; -import 'package:eatvio_app/presentation/chat/chat_select_screen/chat_select_screen.dart'; import 'package:eatvio_app/presentation/diary/diary_edit_screen/diary_edit_screen.dart'; import 'package:eatvio_app/presentation/diets/diet_create_screen/diet_create_screen.dart'; import 'package:eatvio_app/presentation/diets/diet_select_screen/diet_select_screen.dart'; @@ -31,7 +32,6 @@ import 'package:eatvio_app/presentation/registration/weight_screen/weight_screen import 'package:eatvio_app/widgets/bottom_navigation_bar_widget.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; -import 'package:hive_flutter/hive_flutter.dart'; class AppRouter { static GlobalKey navigatorKey = GlobalKey(); @@ -44,11 +44,7 @@ class AppRouter { path: '/auth-screen', name: 'authScreen', redirect: (context, state) async { - final box = await Hive.openBox('token'); - final token = box.get('token'); - if (token != null) { - return '/my-profile-screen'; - } + if (await TokenStorage.haveTokenInStorage()) return '/my-profile-screen'; return null; }, builder: (context, state) => AuthScreen.builder(context), @@ -209,7 +205,7 @@ class AppRouter { GoRoute( path: 'chat-screen', name: 'chatScreen', - builder: (context, state) => ChatScreen.builder(context, state.extra), + builder: (context, state) => ChatScreen(chatId: state.extra as String), ), ], ), diff --git a/lib/core/token_storage.dart b/lib/core/token_storage.dart new file mode 100644 index 00000000..82d2935e --- /dev/null +++ b/lib/core/token_storage.dart @@ -0,0 +1,32 @@ +import 'package:dio/dio.dart'; +import 'package:eatvio_app/locator_service.dart'; +import 'package:hive_flutter/hive_flutter.dart'; + +abstract class TokenStorage { + static addTokenToDioHeader(String token) { + sl().options.headers['Authorization'] = 'Bearer $token'; + } + + static haveTokenInStorage() async { + final box = await Hive.openBox('token'); + final token = box.get('token'); + if (token == null) { + return false; + } else { + addTokenToDioHeader(token); + return true; + } + } + + static getTokenFromStorage() async => await Hive.openBox('token') + ..get('token'); + + static saveTokenInStorage(String token) async { + await Hive.openBox('token') + ..put('token', token); + addTokenToDioHeader(token); + } + + static removeTokenInStorage(String token) async => await Hive.openBox('token') + ..delete('token'); +} diff --git a/lib/data/models/tokenModel/token_model.dart b/lib/data/models/tokenModel/token_model.dart index 17ab28a1..3aa1d3f6 100644 --- a/lib/data/models/tokenModel/token_model.dart +++ b/lib/data/models/tokenModel/token_model.dart @@ -1,5 +1,5 @@ import 'package:hive/hive.dart'; - +/// https://pub.dev/packages/flutter_secure_storage TODO replace hive to secure_storage for token storage @HiveType(typeId: 0) class TokenModel { @HiveField(0) diff --git a/lib/features/chat/models/chat_message_model.dart b/lib/features/chat/models/chat_message_model.dart new file mode 100644 index 00000000..220df3bf --- /dev/null +++ b/lib/features/chat/models/chat_message_model.dart @@ -0,0 +1,18 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'chat_message_model.freezed.dart'; + +part 'chat_message_model.g.dart'; + +@freezed +class ChatMessageModel with _$ChatMessageModel { + const factory ChatMessageModel({ + required int id, + required String data, + @JsonKey(name: 'media_data') required List mediaData, + @JsonKey(name: 'author_id') required int authorId, + @JsonKey(name: 'updated_at') required String updatedAt, + }) = _ChatMessageModel; + + factory ChatMessageModel.fromJson(Map json) => _$ChatMessageModelFromJson(json); +} diff --git a/lib/features/chat/models/chat_message_model.freezed.dart b/lib/features/chat/models/chat_message_model.freezed.dart new file mode 100644 index 00000000..61856085 --- /dev/null +++ b/lib/features/chat/models/chat_message_model.freezed.dart @@ -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 'chat_message_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(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'); + +ChatMessageModel _$ChatMessageModelFromJson(Map json) { + return _ChatMessageModel.fromJson(json); +} + +/// @nodoc +mixin _$ChatMessageModel { + int get id => throw _privateConstructorUsedError; + String get data => throw _privateConstructorUsedError; + @JsonKey(name: 'media_data') + List get mediaData => throw _privateConstructorUsedError; + @JsonKey(name: 'author_id') + int get authorId => throw _privateConstructorUsedError; + @JsonKey(name: 'updated_at') + String get updatedAt => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $ChatMessageModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ChatMessageModelCopyWith<$Res> { + factory $ChatMessageModelCopyWith( + ChatMessageModel value, $Res Function(ChatMessageModel) then) = + _$ChatMessageModelCopyWithImpl<$Res, ChatMessageModel>; + @useResult + $Res call( + {int id, + String data, + @JsonKey(name: 'media_data') List mediaData, + @JsonKey(name: 'author_id') int authorId, + @JsonKey(name: 'updated_at') String updatedAt}); +} + +/// @nodoc +class _$ChatMessageModelCopyWithImpl<$Res, $Val extends ChatMessageModel> + implements $ChatMessageModelCopyWith<$Res> { + _$ChatMessageModelCopyWithImpl(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? data = null, + Object? mediaData = null, + Object? authorId = null, + Object? updatedAt = null, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + data: null == data + ? _value.data + : data // ignore: cast_nullable_to_non_nullable + as String, + mediaData: null == mediaData + ? _value.mediaData + : mediaData // ignore: cast_nullable_to_non_nullable + as List, + authorId: null == authorId + ? _value.authorId + : authorId // ignore: cast_nullable_to_non_nullable + as int, + updatedAt: null == updatedAt + ? _value.updatedAt + : updatedAt // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$ChatMessageModelImplCopyWith<$Res> + implements $ChatMessageModelCopyWith<$Res> { + factory _$$ChatMessageModelImplCopyWith(_$ChatMessageModelImpl value, + $Res Function(_$ChatMessageModelImpl) then) = + __$$ChatMessageModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {int id, + String data, + @JsonKey(name: 'media_data') List mediaData, + @JsonKey(name: 'author_id') int authorId, + @JsonKey(name: 'updated_at') String updatedAt}); +} + +/// @nodoc +class __$$ChatMessageModelImplCopyWithImpl<$Res> + extends _$ChatMessageModelCopyWithImpl<$Res, _$ChatMessageModelImpl> + implements _$$ChatMessageModelImplCopyWith<$Res> { + __$$ChatMessageModelImplCopyWithImpl(_$ChatMessageModelImpl _value, + $Res Function(_$ChatMessageModelImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? data = null, + Object? mediaData = null, + Object? authorId = null, + Object? updatedAt = null, + }) { + return _then(_$ChatMessageModelImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + data: null == data + ? _value.data + : data // ignore: cast_nullable_to_non_nullable + as String, + mediaData: null == mediaData + ? _value._mediaData + : mediaData // ignore: cast_nullable_to_non_nullable + as List, + authorId: null == authorId + ? _value.authorId + : authorId // ignore: cast_nullable_to_non_nullable + as int, + updatedAt: null == updatedAt + ? _value.updatedAt + : updatedAt // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$ChatMessageModelImpl implements _ChatMessageModel { + const _$ChatMessageModelImpl( + {required this.id, + required this.data, + @JsonKey(name: 'media_data') required final List mediaData, + @JsonKey(name: 'author_id') required this.authorId, + @JsonKey(name: 'updated_at') required this.updatedAt}) + : _mediaData = mediaData; + + factory _$ChatMessageModelImpl.fromJson(Map json) => + _$$ChatMessageModelImplFromJson(json); + + @override + final int id; + @override + final String data; + final List _mediaData; + @override + @JsonKey(name: 'media_data') + List get mediaData { + if (_mediaData is EqualUnmodifiableListView) return _mediaData; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_mediaData); + } + + @override + @JsonKey(name: 'author_id') + final int authorId; + @override + @JsonKey(name: 'updated_at') + final String updatedAt; + + @override + String toString() { + return 'ChatMessageModel(id: $id, data: $data, mediaData: $mediaData, authorId: $authorId, updatedAt: $updatedAt)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ChatMessageModelImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.data, data) || other.data == data) && + const DeepCollectionEquality() + .equals(other._mediaData, _mediaData) && + (identical(other.authorId, authorId) || + other.authorId == authorId) && + (identical(other.updatedAt, updatedAt) || + other.updatedAt == updatedAt)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, id, data, + const DeepCollectionEquality().hash(_mediaData), authorId, updatedAt); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ChatMessageModelImplCopyWith<_$ChatMessageModelImpl> get copyWith => + __$$ChatMessageModelImplCopyWithImpl<_$ChatMessageModelImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$ChatMessageModelImplToJson( + this, + ); + } +} + +abstract class _ChatMessageModel implements ChatMessageModel { + const factory _ChatMessageModel( + {required final int id, + required final String data, + @JsonKey(name: 'media_data') required final List mediaData, + @JsonKey(name: 'author_id') required final int authorId, + @JsonKey(name: 'updated_at') required final String updatedAt}) = + _$ChatMessageModelImpl; + + factory _ChatMessageModel.fromJson(Map json) = + _$ChatMessageModelImpl.fromJson; + + @override + int get id; + @override + String get data; + @override + @JsonKey(name: 'media_data') + List get mediaData; + @override + @JsonKey(name: 'author_id') + int get authorId; + @override + @JsonKey(name: 'updated_at') + String get updatedAt; + @override + @JsonKey(ignore: true) + _$$ChatMessageModelImplCopyWith<_$ChatMessageModelImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/features/chat/models/chat_message_model.g.dart b/lib/features/chat/models/chat_message_model.g.dart new file mode 100644 index 00000000..8b28b749 --- /dev/null +++ b/lib/features/chat/models/chat_message_model.g.dart @@ -0,0 +1,27 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'chat_message_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$ChatMessageModelImpl _$$ChatMessageModelImplFromJson( + Map json) => + _$ChatMessageModelImpl( + id: (json['id'] as num).toInt(), + data: json['data'] as String, + mediaData: json['media_data'] as List, + authorId: (json['author_id'] as num).toInt(), + updatedAt: json['updated_at'] as String, + ); + +Map _$$ChatMessageModelImplToJson( + _$ChatMessageModelImpl instance) => + { + 'id': instance.id, + 'data': instance.data, + 'media_data': instance.mediaData, + 'author_id': instance.authorId, + 'updated_at': instance.updatedAt, + }; diff --git a/lib/features/chat/models/chat_room_model.dart b/lib/features/chat/models/chat_room_model.dart new file mode 100644 index 00000000..1fa5afe7 --- /dev/null +++ b/lib/features/chat/models/chat_room_model.dart @@ -0,0 +1,20 @@ +import 'package:eatvio_app/features/chat/models/chat_message_model.dart'; +import 'package:eatvio_app/features/chat/models/chat_room_settings_model.dart'; +import 'package:eatvio_app/features/chat/models/chat_user_model.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'chat_room_model.freezed.dart'; + +part 'chat_room_model.g.dart'; + +@freezed +class ChatRoomModel with _$ChatRoomModel { + const factory ChatRoomModel({ + required String id, + @JsonKey(name: 'chat_room_setting') required ChatRoomSettingsModel chatRoomSettings, + required List messages, + required Map users, + }) = _ChatRoomModel; + + factory ChatRoomModel.fromJson(Map json) => _$ChatRoomModelFromJson(json); +} diff --git a/lib/features/chat/models/chat_room_model.freezed.dart b/lib/features/chat/models/chat_room_model.freezed.dart new file mode 100644 index 00000000..b8b4ce46 --- /dev/null +++ b/lib/features/chat/models/chat_room_model.freezed.dart @@ -0,0 +1,255 @@ +// 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_room_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(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'); + +ChatRoomModel _$ChatRoomModelFromJson(Map json) { + return _ChatRoomModel.fromJson(json); +} + +/// @nodoc +mixin _$ChatRoomModel { + String get id => throw _privateConstructorUsedError; + @JsonKey(name: 'chat_room_setting') + ChatRoomSettingsModel get chatRoomSettings => + throw _privateConstructorUsedError; + List get messages => throw _privateConstructorUsedError; + Map get users => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $ChatRoomModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ChatRoomModelCopyWith<$Res> { + factory $ChatRoomModelCopyWith( + ChatRoomModel value, $Res Function(ChatRoomModel) then) = + _$ChatRoomModelCopyWithImpl<$Res, ChatRoomModel>; + @useResult + $Res call( + {String id, + @JsonKey(name: 'chat_room_setting') + ChatRoomSettingsModel chatRoomSettings, + List messages, + Map users}); + + $ChatRoomSettingsModelCopyWith<$Res> get chatRoomSettings; +} + +/// @nodoc +class _$ChatRoomModelCopyWithImpl<$Res, $Val extends ChatRoomModel> + implements $ChatRoomModelCopyWith<$Res> { + _$ChatRoomModelCopyWithImpl(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? chatRoomSettings = null, + Object? messages = null, + Object? users = null, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + chatRoomSettings: null == chatRoomSettings + ? _value.chatRoomSettings + : chatRoomSettings // ignore: cast_nullable_to_non_nullable + as ChatRoomSettingsModel, + messages: null == messages + ? _value.messages + : messages // ignore: cast_nullable_to_non_nullable + as List, + users: null == users + ? _value.users + : users // ignore: cast_nullable_to_non_nullable + as Map, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $ChatRoomSettingsModelCopyWith<$Res> get chatRoomSettings { + return $ChatRoomSettingsModelCopyWith<$Res>(_value.chatRoomSettings, + (value) { + return _then(_value.copyWith(chatRoomSettings: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$ChatRoomModelImplCopyWith<$Res> + implements $ChatRoomModelCopyWith<$Res> { + factory _$$ChatRoomModelImplCopyWith( + _$ChatRoomModelImpl value, $Res Function(_$ChatRoomModelImpl) then) = + __$$ChatRoomModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String id, + @JsonKey(name: 'chat_room_setting') + ChatRoomSettingsModel chatRoomSettings, + List messages, + Map users}); + + @override + $ChatRoomSettingsModelCopyWith<$Res> get chatRoomSettings; +} + +/// @nodoc +class __$$ChatRoomModelImplCopyWithImpl<$Res> + extends _$ChatRoomModelCopyWithImpl<$Res, _$ChatRoomModelImpl> + implements _$$ChatRoomModelImplCopyWith<$Res> { + __$$ChatRoomModelImplCopyWithImpl( + _$ChatRoomModelImpl _value, $Res Function(_$ChatRoomModelImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? chatRoomSettings = null, + Object? messages = null, + Object? users = null, + }) { + return _then(_$ChatRoomModelImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + chatRoomSettings: null == chatRoomSettings + ? _value.chatRoomSettings + : chatRoomSettings // ignore: cast_nullable_to_non_nullable + as ChatRoomSettingsModel, + messages: null == messages + ? _value._messages + : messages // ignore: cast_nullable_to_non_nullable + as List, + users: null == users + ? _value._users + : users // ignore: cast_nullable_to_non_nullable + as Map, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$ChatRoomModelImpl implements _ChatRoomModel { + const _$ChatRoomModelImpl( + {required this.id, + @JsonKey(name: 'chat_room_setting') required this.chatRoomSettings, + required final List messages, + required final Map users}) + : _messages = messages, + _users = users; + + factory _$ChatRoomModelImpl.fromJson(Map json) => + _$$ChatRoomModelImplFromJson(json); + + @override + final String id; + @override + @JsonKey(name: 'chat_room_setting') + final ChatRoomSettingsModel chatRoomSettings; + final List _messages; + @override + List get messages { + if (_messages is EqualUnmodifiableListView) return _messages; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_messages); + } + + final Map _users; + @override + Map get users { + if (_users is EqualUnmodifiableMapView) return _users; + // ignore: implicit_dynamic_type + return EqualUnmodifiableMapView(_users); + } + + @override + String toString() { + return 'ChatRoomModel(id: $id, chatRoomSettings: $chatRoomSettings, messages: $messages, users: $users)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ChatRoomModelImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.chatRoomSettings, chatRoomSettings) || + other.chatRoomSettings == chatRoomSettings) && + const DeepCollectionEquality().equals(other._messages, _messages) && + const DeepCollectionEquality().equals(other._users, _users)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, + id, + chatRoomSettings, + const DeepCollectionEquality().hash(_messages), + const DeepCollectionEquality().hash(_users)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ChatRoomModelImplCopyWith<_$ChatRoomModelImpl> get copyWith => + __$$ChatRoomModelImplCopyWithImpl<_$ChatRoomModelImpl>(this, _$identity); + + @override + Map toJson() { + return _$$ChatRoomModelImplToJson( + this, + ); + } +} + +abstract class _ChatRoomModel implements ChatRoomModel { + const factory _ChatRoomModel( + {required final String id, + @JsonKey(name: 'chat_room_setting') + required final ChatRoomSettingsModel chatRoomSettings, + required final List messages, + required final Map users}) = _$ChatRoomModelImpl; + + factory _ChatRoomModel.fromJson(Map json) = + _$ChatRoomModelImpl.fromJson; + + @override + String get id; + @override + @JsonKey(name: 'chat_room_setting') + ChatRoomSettingsModel get chatRoomSettings; + @override + List get messages; + @override + Map get users; + @override + @JsonKey(ignore: true) + _$$ChatRoomModelImplCopyWith<_$ChatRoomModelImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/features/chat/models/chat_room_model.g.dart b/lib/features/chat/models/chat_room_model.g.dart new file mode 100644 index 00000000..4ab38671 --- /dev/null +++ b/lib/features/chat/models/chat_room_model.g.dart @@ -0,0 +1,29 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'chat_room_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$ChatRoomModelImpl _$$ChatRoomModelImplFromJson(Map json) => + _$ChatRoomModelImpl( + id: json['id'] as String, + chatRoomSettings: ChatRoomSettingsModel.fromJson( + json['chat_room_setting'] as Map), + messages: (json['messages'] as List) + .map((e) => ChatMessageModel.fromJson(e as Map)) + .toList(), + users: (json['users'] as Map).map( + (k, e) => + MapEntry(k, ChatUserModel.fromJson(e as Map)), + ), + ); + +Map _$$ChatRoomModelImplToJson(_$ChatRoomModelImpl instance) => + { + 'id': instance.id, + 'chat_room_setting': instance.chatRoomSettings, + 'messages': instance.messages, + 'users': instance.users, + }; diff --git a/lib/features/chat/models/chat_room_settings_model.dart b/lib/features/chat/models/chat_room_settings_model.dart new file mode 100644 index 00000000..7262c9a2 --- /dev/null +++ b/lib/features/chat/models/chat_room_settings_model.dart @@ -0,0 +1,18 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'chat_room_settings_model.freezed.dart'; + +part 'chat_room_settings_model.g.dart'; + +@freezed +class ChatRoomSettingsModel with _$ChatRoomSettingsModel { + const factory ChatRoomSettingsModel({ + required int id, + @JsonKey(name: 'room_name') required String roomName, + required String state, + @JsonKey(name: 'access_level') required String accessLevel, + @JsonKey(name: 'updated_at') required String updatedAt, + }) = _ChatRoomSettingsModel; + + factory ChatRoomSettingsModel.fromJson(Map json) => _$ChatRoomSettingsModelFromJson(json); +} diff --git a/lib/features/chat/models/chat_room_settings_model.freezed.dart b/lib/features/chat/models/chat_room_settings_model.freezed.dart new file mode 100644 index 00000000..4f217556 --- /dev/null +++ b/lib/features/chat/models/chat_room_settings_model.freezed.dart @@ -0,0 +1,254 @@ +// 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_room_settings_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(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'); + +ChatRoomSettingsModel _$ChatRoomSettingsModelFromJson( + Map json) { + return _ChatRoomSettingsModel.fromJson(json); +} + +/// @nodoc +mixin _$ChatRoomSettingsModel { + int get id => throw _privateConstructorUsedError; + @JsonKey(name: 'room_name') + String get roomName => throw _privateConstructorUsedError; + String get state => throw _privateConstructorUsedError; + @JsonKey(name: 'access_level') + String get accessLevel => throw _privateConstructorUsedError; + @JsonKey(name: 'updated_at') + String get updatedAt => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $ChatRoomSettingsModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ChatRoomSettingsModelCopyWith<$Res> { + factory $ChatRoomSettingsModelCopyWith(ChatRoomSettingsModel value, + $Res Function(ChatRoomSettingsModel) then) = + _$ChatRoomSettingsModelCopyWithImpl<$Res, ChatRoomSettingsModel>; + @useResult + $Res call( + {int id, + @JsonKey(name: 'room_name') String roomName, + String state, + @JsonKey(name: 'access_level') String accessLevel, + @JsonKey(name: 'updated_at') String updatedAt}); +} + +/// @nodoc +class _$ChatRoomSettingsModelCopyWithImpl<$Res, + $Val extends ChatRoomSettingsModel> + implements $ChatRoomSettingsModelCopyWith<$Res> { + _$ChatRoomSettingsModelCopyWithImpl(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? roomName = null, + Object? state = null, + Object? accessLevel = null, + Object? updatedAt = null, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + roomName: null == roomName + ? _value.roomName + : roomName // ignore: cast_nullable_to_non_nullable + as String, + state: null == state + ? _value.state + : state // ignore: cast_nullable_to_non_nullable + as String, + accessLevel: null == accessLevel + ? _value.accessLevel + : accessLevel // ignore: cast_nullable_to_non_nullable + as String, + updatedAt: null == updatedAt + ? _value.updatedAt + : updatedAt // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$ChatRoomSettingsModelImplCopyWith<$Res> + implements $ChatRoomSettingsModelCopyWith<$Res> { + factory _$$ChatRoomSettingsModelImplCopyWith( + _$ChatRoomSettingsModelImpl value, + $Res Function(_$ChatRoomSettingsModelImpl) then) = + __$$ChatRoomSettingsModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {int id, + @JsonKey(name: 'room_name') String roomName, + String state, + @JsonKey(name: 'access_level') String accessLevel, + @JsonKey(name: 'updated_at') String updatedAt}); +} + +/// @nodoc +class __$$ChatRoomSettingsModelImplCopyWithImpl<$Res> + extends _$ChatRoomSettingsModelCopyWithImpl<$Res, + _$ChatRoomSettingsModelImpl> + implements _$$ChatRoomSettingsModelImplCopyWith<$Res> { + __$$ChatRoomSettingsModelImplCopyWithImpl(_$ChatRoomSettingsModelImpl _value, + $Res Function(_$ChatRoomSettingsModelImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? roomName = null, + Object? state = null, + Object? accessLevel = null, + Object? updatedAt = null, + }) { + return _then(_$ChatRoomSettingsModelImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + roomName: null == roomName + ? _value.roomName + : roomName // ignore: cast_nullable_to_non_nullable + as String, + state: null == state + ? _value.state + : state // ignore: cast_nullable_to_non_nullable + as String, + accessLevel: null == accessLevel + ? _value.accessLevel + : accessLevel // ignore: cast_nullable_to_non_nullable + as String, + updatedAt: null == updatedAt + ? _value.updatedAt + : updatedAt // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$ChatRoomSettingsModelImpl implements _ChatRoomSettingsModel { + const _$ChatRoomSettingsModelImpl( + {required this.id, + @JsonKey(name: 'room_name') required this.roomName, + required this.state, + @JsonKey(name: 'access_level') required this.accessLevel, + @JsonKey(name: 'updated_at') required this.updatedAt}); + + factory _$ChatRoomSettingsModelImpl.fromJson(Map json) => + _$$ChatRoomSettingsModelImplFromJson(json); + + @override + final int id; + @override + @JsonKey(name: 'room_name') + final String roomName; + @override + final String state; + @override + @JsonKey(name: 'access_level') + final String accessLevel; + @override + @JsonKey(name: 'updated_at') + final String updatedAt; + + @override + String toString() { + return 'ChatRoomSettingsModel(id: $id, roomName: $roomName, state: $state, accessLevel: $accessLevel, updatedAt: $updatedAt)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ChatRoomSettingsModelImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.roomName, roomName) || + other.roomName == roomName) && + (identical(other.state, state) || other.state == state) && + (identical(other.accessLevel, accessLevel) || + other.accessLevel == accessLevel) && + (identical(other.updatedAt, updatedAt) || + other.updatedAt == updatedAt)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => + Object.hash(runtimeType, id, roomName, state, accessLevel, updatedAt); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ChatRoomSettingsModelImplCopyWith<_$ChatRoomSettingsModelImpl> + get copyWith => __$$ChatRoomSettingsModelImplCopyWithImpl< + _$ChatRoomSettingsModelImpl>(this, _$identity); + + @override + Map toJson() { + return _$$ChatRoomSettingsModelImplToJson( + this, + ); + } +} + +abstract class _ChatRoomSettingsModel implements ChatRoomSettingsModel { + const factory _ChatRoomSettingsModel( + {required final int id, + @JsonKey(name: 'room_name') required final String roomName, + required final String state, + @JsonKey(name: 'access_level') required final String accessLevel, + @JsonKey(name: 'updated_at') required final String updatedAt}) = + _$ChatRoomSettingsModelImpl; + + factory _ChatRoomSettingsModel.fromJson(Map json) = + _$ChatRoomSettingsModelImpl.fromJson; + + @override + int get id; + @override + @JsonKey(name: 'room_name') + String get roomName; + @override + String get state; + @override + @JsonKey(name: 'access_level') + String get accessLevel; + @override + @JsonKey(name: 'updated_at') + String get updatedAt; + @override + @JsonKey(ignore: true) + _$$ChatRoomSettingsModelImplCopyWith<_$ChatRoomSettingsModelImpl> + get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/features/chat/models/chat_room_settings_model.g.dart b/lib/features/chat/models/chat_room_settings_model.g.dart new file mode 100644 index 00000000..7b824334 --- /dev/null +++ b/lib/features/chat/models/chat_room_settings_model.g.dart @@ -0,0 +1,27 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'chat_room_settings_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$ChatRoomSettingsModelImpl _$$ChatRoomSettingsModelImplFromJson( + Map json) => + _$ChatRoomSettingsModelImpl( + id: (json['id'] as num).toInt(), + roomName: json['room_name'] as String, + state: json['state'] as String, + accessLevel: json['access_level'] as String, + updatedAt: json['updated_at'] as String, + ); + +Map _$$ChatRoomSettingsModelImplToJson( + _$ChatRoomSettingsModelImpl instance) => + { + 'id': instance.id, + 'room_name': instance.roomName, + 'state': instance.state, + 'access_level': instance.accessLevel, + 'updated_at': instance.updatedAt, + }; diff --git a/lib/features/chat/models/chat_user_model.dart b/lib/features/chat/models/chat_user_model.dart new file mode 100644 index 00000000..dd8bf02a --- /dev/null +++ b/lib/features/chat/models/chat_user_model.dart @@ -0,0 +1,19 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'chat_user_model.freezed.dart'; + +part 'chat_user_model.g.dart'; + +@freezed +class ChatUserModel with _$ChatUserModel { + const factory ChatUserModel({ + required int id, + required String name, + @JsonKey(name: 'profile_photo_path') + String? profilePhotoPath, + @JsonKey(name: 'profile_photo_url') + String? profilePhotoUrl, + }) = _ChatUserModel; + + factory ChatUserModel.fromJson(Map json) => _$ChatUserModelFromJson(json); +} diff --git a/lib/features/chat/models/chat_user_model.freezed.dart b/lib/features/chat/models/chat_user_model.freezed.dart new file mode 100644 index 00000000..095c09e2 --- /dev/null +++ b/lib/features/chat/models/chat_user_model.freezed.dart @@ -0,0 +1,225 @@ +// 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_user_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(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'); + +ChatUserModel _$ChatUserModelFromJson(Map json) { + return _ChatUserModel.fromJson(json); +} + +/// @nodoc +mixin _$ChatUserModel { + int get id => throw _privateConstructorUsedError; + String get name => throw _privateConstructorUsedError; + @JsonKey(name: 'profile_photo_path') + String? get profilePhotoPath => throw _privateConstructorUsedError; + @JsonKey(name: 'profile_photo_url') + String? get profilePhotoUrl => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $ChatUserModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ChatUserModelCopyWith<$Res> { + factory $ChatUserModelCopyWith( + ChatUserModel value, $Res Function(ChatUserModel) then) = + _$ChatUserModelCopyWithImpl<$Res, ChatUserModel>; + @useResult + $Res call( + {int id, + String name, + @JsonKey(name: 'profile_photo_path') String? profilePhotoPath, + @JsonKey(name: 'profile_photo_url') String? profilePhotoUrl}); +} + +/// @nodoc +class _$ChatUserModelCopyWithImpl<$Res, $Val extends ChatUserModel> + implements $ChatUserModelCopyWith<$Res> { + _$ChatUserModelCopyWithImpl(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? profilePhotoPath = freezed, + Object? profilePhotoUrl = freezed, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + profilePhotoPath: freezed == profilePhotoPath + ? _value.profilePhotoPath + : profilePhotoPath // ignore: cast_nullable_to_non_nullable + as String?, + profilePhotoUrl: freezed == profilePhotoUrl + ? _value.profilePhotoUrl + : profilePhotoUrl // ignore: cast_nullable_to_non_nullable + as String?, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$ChatUserModelImplCopyWith<$Res> + implements $ChatUserModelCopyWith<$Res> { + factory _$$ChatUserModelImplCopyWith( + _$ChatUserModelImpl value, $Res Function(_$ChatUserModelImpl) then) = + __$$ChatUserModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {int id, + String name, + @JsonKey(name: 'profile_photo_path') String? profilePhotoPath, + @JsonKey(name: 'profile_photo_url') String? profilePhotoUrl}); +} + +/// @nodoc +class __$$ChatUserModelImplCopyWithImpl<$Res> + extends _$ChatUserModelCopyWithImpl<$Res, _$ChatUserModelImpl> + implements _$$ChatUserModelImplCopyWith<$Res> { + __$$ChatUserModelImplCopyWithImpl( + _$ChatUserModelImpl _value, $Res Function(_$ChatUserModelImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? name = null, + Object? profilePhotoPath = freezed, + Object? profilePhotoUrl = freezed, + }) { + return _then(_$ChatUserModelImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + profilePhotoPath: freezed == profilePhotoPath + ? _value.profilePhotoPath + : profilePhotoPath // ignore: cast_nullable_to_non_nullable + as String?, + profilePhotoUrl: freezed == profilePhotoUrl + ? _value.profilePhotoUrl + : profilePhotoUrl // ignore: cast_nullable_to_non_nullable + as String?, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$ChatUserModelImpl implements _ChatUserModel { + const _$ChatUserModelImpl( + {required this.id, + required this.name, + @JsonKey(name: 'profile_photo_path') this.profilePhotoPath, + @JsonKey(name: 'profile_photo_url') this.profilePhotoUrl}); + + factory _$ChatUserModelImpl.fromJson(Map json) => + _$$ChatUserModelImplFromJson(json); + + @override + final int id; + @override + final String name; + @override + @JsonKey(name: 'profile_photo_path') + final String? profilePhotoPath; + @override + @JsonKey(name: 'profile_photo_url') + final String? profilePhotoUrl; + + @override + String toString() { + return 'ChatUserModel(id: $id, name: $name, profilePhotoPath: $profilePhotoPath, profilePhotoUrl: $profilePhotoUrl)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ChatUserModelImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.name, name) || other.name == name) && + (identical(other.profilePhotoPath, profilePhotoPath) || + other.profilePhotoPath == profilePhotoPath) && + (identical(other.profilePhotoUrl, profilePhotoUrl) || + other.profilePhotoUrl == profilePhotoUrl)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => + Object.hash(runtimeType, id, name, profilePhotoPath, profilePhotoUrl); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ChatUserModelImplCopyWith<_$ChatUserModelImpl> get copyWith => + __$$ChatUserModelImplCopyWithImpl<_$ChatUserModelImpl>(this, _$identity); + + @override + Map toJson() { + return _$$ChatUserModelImplToJson( + this, + ); + } +} + +abstract class _ChatUserModel implements ChatUserModel { + const factory _ChatUserModel( + {required final int id, + required final String name, + @JsonKey(name: 'profile_photo_path') final String? profilePhotoPath, + @JsonKey(name: 'profile_photo_url') final String? profilePhotoUrl}) = + _$ChatUserModelImpl; + + factory _ChatUserModel.fromJson(Map json) = + _$ChatUserModelImpl.fromJson; + + @override + int get id; + @override + String get name; + @override + @JsonKey(name: 'profile_photo_path') + String? get profilePhotoPath; + @override + @JsonKey(name: 'profile_photo_url') + String? get profilePhotoUrl; + @override + @JsonKey(ignore: true) + _$$ChatUserModelImplCopyWith<_$ChatUserModelImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/features/chat/models/chat_user_model.g.dart b/lib/features/chat/models/chat_user_model.g.dart new file mode 100644 index 00000000..78e0f981 --- /dev/null +++ b/lib/features/chat/models/chat_user_model.g.dart @@ -0,0 +1,23 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'chat_user_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$ChatUserModelImpl _$$ChatUserModelImplFromJson(Map json) => + _$ChatUserModelImpl( + id: (json['id'] as num).toInt(), + name: json['name'] as String, + profilePhotoPath: json['profile_photo_path'] as String?, + profilePhotoUrl: json['profile_photo_url'] as String?, + ); + +Map _$$ChatUserModelImplToJson(_$ChatUserModelImpl instance) => + { + 'id': instance.id, + 'name': instance.name, + 'profile_photo_path': instance.profilePhotoPath, + 'profile_photo_url': instance.profilePhotoUrl, + }; diff --git a/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart b/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart new file mode 100644 index 00000000..f66069e2 --- /dev/null +++ b/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart @@ -0,0 +1,20 @@ +import 'package:eatvio_app/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.dart'; +import 'package:eatvio_app/features/chat/repositories/chat_repository.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class ChatRoomCubit extends Cubit { + final ChatRepository chatRepository; + + ChatRoomCubit({ + required this.chatRepository, + }) : super(ChatRoomState.loading()); + + initChat(String chatId) async { + try { + final chatRoomModel = await chatRepository.getChatRoom(chatId); + emit(ChatRoomState.loaded(chatRoomModel: chatRoomModel)); + } catch (e) { + emit(ChatRoomState.error(errorMessage: 'Ошибка получеия данных')); + } + } +} diff --git a/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.dart b/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.dart new file mode 100644 index 00000000..89184a63 --- /dev/null +++ b/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.dart @@ -0,0 +1,19 @@ +import 'package:eatvio_app/features/chat/models/chat_room_model.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'chat_room_state.freezed.dart'; + +@freezed +abstract class ChatRoomState with _$ChatRoomState { + const factory ChatRoomState() = _ChatRoomState; + + const factory ChatRoomState.loading() = ChatRoomStateLoading; + + const factory ChatRoomState.loaded({ + required ChatRoomModel chatRoomModel, + }) = ChatRoomStateLoaded; + + const factory ChatRoomState.error({ + required String errorMessage, + }) = ChatRoomStateError; +} diff --git a/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.freezed.dart b/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.freezed.dart new file mode 100644 index 00000000..5bd9ae89 --- /dev/null +++ b/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.freezed.dart @@ -0,0 +1,622 @@ +// 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_room_state.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(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 _$ChatRoomState { + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(ChatRoomModel chatRoomModel) loaded, + required TResult Function(String errorMessage) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(ChatRoomModel chatRoomModel)? loaded, + TResult? Function(String errorMessage)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(ChatRoomModel chatRoomModel)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map( + TResult Function(_ChatRoomState value) $default, { + required TResult Function(ChatRoomStateLoading value) loading, + required TResult Function(ChatRoomStateLoaded value) loaded, + required TResult Function(ChatRoomStateError value) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_ChatRoomState value)? $default, { + TResult? Function(ChatRoomStateLoading value)? loading, + TResult? Function(ChatRoomStateLoaded value)? loaded, + TResult? Function(ChatRoomStateError value)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap( + TResult Function(_ChatRoomState value)? $default, { + TResult Function(ChatRoomStateLoading value)? loading, + TResult Function(ChatRoomStateLoaded value)? loaded, + TResult Function(ChatRoomStateError value)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ChatRoomStateCopyWith<$Res> { + factory $ChatRoomStateCopyWith( + ChatRoomState value, $Res Function(ChatRoomState) then) = + _$ChatRoomStateCopyWithImpl<$Res, ChatRoomState>; +} + +/// @nodoc +class _$ChatRoomStateCopyWithImpl<$Res, $Val extends ChatRoomState> + implements $ChatRoomStateCopyWith<$Res> { + _$ChatRoomStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$ChatRoomStateImplCopyWith<$Res> { + factory _$$ChatRoomStateImplCopyWith( + _$ChatRoomStateImpl value, $Res Function(_$ChatRoomStateImpl) then) = + __$$ChatRoomStateImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$ChatRoomStateImplCopyWithImpl<$Res> + extends _$ChatRoomStateCopyWithImpl<$Res, _$ChatRoomStateImpl> + implements _$$ChatRoomStateImplCopyWith<$Res> { + __$$ChatRoomStateImplCopyWithImpl( + _$ChatRoomStateImpl _value, $Res Function(_$ChatRoomStateImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$ChatRoomStateImpl implements _ChatRoomState { + const _$ChatRoomStateImpl(); + + @override + String toString() { + return 'ChatRoomState()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$ChatRoomStateImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(ChatRoomModel chatRoomModel) loaded, + required TResult Function(String errorMessage) error, + }) { + return $default(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(ChatRoomModel chatRoomModel)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return $default?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(ChatRoomModel chatRoomModel)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if ($default != null) { + return $default(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_ChatRoomState value) $default, { + required TResult Function(ChatRoomStateLoading value) loading, + required TResult Function(ChatRoomStateLoaded value) loaded, + required TResult Function(ChatRoomStateError value) error, + }) { + return $default(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_ChatRoomState value)? $default, { + TResult? Function(ChatRoomStateLoading value)? loading, + TResult? Function(ChatRoomStateLoaded value)? loaded, + TResult? Function(ChatRoomStateError value)? error, + }) { + return $default?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_ChatRoomState value)? $default, { + TResult Function(ChatRoomStateLoading value)? loading, + TResult Function(ChatRoomStateLoaded value)? loaded, + TResult Function(ChatRoomStateError value)? error, + required TResult orElse(), + }) { + if ($default != null) { + return $default(this); + } + return orElse(); + } +} + +abstract class _ChatRoomState implements ChatRoomState { + const factory _ChatRoomState() = _$ChatRoomStateImpl; +} + +/// @nodoc +abstract class _$$ChatRoomStateLoadingImplCopyWith<$Res> { + factory _$$ChatRoomStateLoadingImplCopyWith(_$ChatRoomStateLoadingImpl value, + $Res Function(_$ChatRoomStateLoadingImpl) then) = + __$$ChatRoomStateLoadingImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$ChatRoomStateLoadingImplCopyWithImpl<$Res> + extends _$ChatRoomStateCopyWithImpl<$Res, _$ChatRoomStateLoadingImpl> + implements _$$ChatRoomStateLoadingImplCopyWith<$Res> { + __$$ChatRoomStateLoadingImplCopyWithImpl(_$ChatRoomStateLoadingImpl _value, + $Res Function(_$ChatRoomStateLoadingImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$ChatRoomStateLoadingImpl implements ChatRoomStateLoading { + const _$ChatRoomStateLoadingImpl(); + + @override + String toString() { + return 'ChatRoomState.loading()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ChatRoomStateLoadingImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(ChatRoomModel chatRoomModel) loaded, + required TResult Function(String errorMessage) error, + }) { + return loading(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(ChatRoomModel chatRoomModel)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return loading?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(ChatRoomModel chatRoomModel)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_ChatRoomState value) $default, { + required TResult Function(ChatRoomStateLoading value) loading, + required TResult Function(ChatRoomStateLoaded value) loaded, + required TResult Function(ChatRoomStateError value) error, + }) { + return loading(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_ChatRoomState value)? $default, { + TResult? Function(ChatRoomStateLoading value)? loading, + TResult? Function(ChatRoomStateLoaded value)? loaded, + TResult? Function(ChatRoomStateError value)? error, + }) { + return loading?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_ChatRoomState value)? $default, { + TResult Function(ChatRoomStateLoading value)? loading, + TResult Function(ChatRoomStateLoaded value)? loaded, + TResult Function(ChatRoomStateError value)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(this); + } + return orElse(); + } +} + +abstract class ChatRoomStateLoading implements ChatRoomState { + const factory ChatRoomStateLoading() = _$ChatRoomStateLoadingImpl; +} + +/// @nodoc +abstract class _$$ChatRoomStateLoadedImplCopyWith<$Res> { + factory _$$ChatRoomStateLoadedImplCopyWith(_$ChatRoomStateLoadedImpl value, + $Res Function(_$ChatRoomStateLoadedImpl) then) = + __$$ChatRoomStateLoadedImplCopyWithImpl<$Res>; + @useResult + $Res call({ChatRoomModel chatRoomModel}); + + $ChatRoomModelCopyWith<$Res> get chatRoomModel; +} + +/// @nodoc +class __$$ChatRoomStateLoadedImplCopyWithImpl<$Res> + extends _$ChatRoomStateCopyWithImpl<$Res, _$ChatRoomStateLoadedImpl> + implements _$$ChatRoomStateLoadedImplCopyWith<$Res> { + __$$ChatRoomStateLoadedImplCopyWithImpl(_$ChatRoomStateLoadedImpl _value, + $Res Function(_$ChatRoomStateLoadedImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? chatRoomModel = null, + }) { + return _then(_$ChatRoomStateLoadedImpl( + chatRoomModel: null == chatRoomModel + ? _value.chatRoomModel + : chatRoomModel // ignore: cast_nullable_to_non_nullable + as ChatRoomModel, + )); + } + + @override + @pragma('vm:prefer-inline') + $ChatRoomModelCopyWith<$Res> get chatRoomModel { + return $ChatRoomModelCopyWith<$Res>(_value.chatRoomModel, (value) { + return _then(_value.copyWith(chatRoomModel: value)); + }); + } +} + +/// @nodoc + +class _$ChatRoomStateLoadedImpl implements ChatRoomStateLoaded { + const _$ChatRoomStateLoadedImpl({required this.chatRoomModel}); + + @override + final ChatRoomModel chatRoomModel; + + @override + String toString() { + return 'ChatRoomState.loaded(chatRoomModel: $chatRoomModel)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ChatRoomStateLoadedImpl && + (identical(other.chatRoomModel, chatRoomModel) || + other.chatRoomModel == chatRoomModel)); + } + + @override + int get hashCode => Object.hash(runtimeType, chatRoomModel); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ChatRoomStateLoadedImplCopyWith<_$ChatRoomStateLoadedImpl> get copyWith => + __$$ChatRoomStateLoadedImplCopyWithImpl<_$ChatRoomStateLoadedImpl>( + this, _$identity); + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(ChatRoomModel chatRoomModel) loaded, + required TResult Function(String errorMessage) error, + }) { + return loaded(chatRoomModel); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(ChatRoomModel chatRoomModel)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return loaded?.call(chatRoomModel); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(ChatRoomModel chatRoomModel)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(chatRoomModel); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_ChatRoomState value) $default, { + required TResult Function(ChatRoomStateLoading value) loading, + required TResult Function(ChatRoomStateLoaded value) loaded, + required TResult Function(ChatRoomStateError value) error, + }) { + return loaded(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_ChatRoomState value)? $default, { + TResult? Function(ChatRoomStateLoading value)? loading, + TResult? Function(ChatRoomStateLoaded value)? loaded, + TResult? Function(ChatRoomStateError value)? error, + }) { + return loaded?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_ChatRoomState value)? $default, { + TResult Function(ChatRoomStateLoading value)? loading, + TResult Function(ChatRoomStateLoaded value)? loaded, + TResult Function(ChatRoomStateError value)? error, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(this); + } + return orElse(); + } +} + +abstract class ChatRoomStateLoaded implements ChatRoomState { + const factory ChatRoomStateLoaded( + {required final ChatRoomModel chatRoomModel}) = _$ChatRoomStateLoadedImpl; + + ChatRoomModel get chatRoomModel; + @JsonKey(ignore: true) + _$$ChatRoomStateLoadedImplCopyWith<_$ChatRoomStateLoadedImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$ChatRoomStateErrorImplCopyWith<$Res> { + factory _$$ChatRoomStateErrorImplCopyWith(_$ChatRoomStateErrorImpl value, + $Res Function(_$ChatRoomStateErrorImpl) then) = + __$$ChatRoomStateErrorImplCopyWithImpl<$Res>; + @useResult + $Res call({String errorMessage}); +} + +/// @nodoc +class __$$ChatRoomStateErrorImplCopyWithImpl<$Res> + extends _$ChatRoomStateCopyWithImpl<$Res, _$ChatRoomStateErrorImpl> + implements _$$ChatRoomStateErrorImplCopyWith<$Res> { + __$$ChatRoomStateErrorImplCopyWithImpl(_$ChatRoomStateErrorImpl _value, + $Res Function(_$ChatRoomStateErrorImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? errorMessage = null, + }) { + return _then(_$ChatRoomStateErrorImpl( + errorMessage: null == errorMessage + ? _value.errorMessage + : errorMessage // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc + +class _$ChatRoomStateErrorImpl implements ChatRoomStateError { + const _$ChatRoomStateErrorImpl({required this.errorMessage}); + + @override + final String errorMessage; + + @override + String toString() { + return 'ChatRoomState.error(errorMessage: $errorMessage)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ChatRoomStateErrorImpl && + (identical(other.errorMessage, errorMessage) || + other.errorMessage == errorMessage)); + } + + @override + int get hashCode => Object.hash(runtimeType, errorMessage); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ChatRoomStateErrorImplCopyWith<_$ChatRoomStateErrorImpl> get copyWith => + __$$ChatRoomStateErrorImplCopyWithImpl<_$ChatRoomStateErrorImpl>( + this, _$identity); + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(ChatRoomModel chatRoomModel) loaded, + required TResult Function(String errorMessage) error, + }) { + return error(errorMessage); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(ChatRoomModel chatRoomModel)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return error?.call(errorMessage); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(ChatRoomModel chatRoomModel)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(errorMessage); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_ChatRoomState value) $default, { + required TResult Function(ChatRoomStateLoading value) loading, + required TResult Function(ChatRoomStateLoaded value) loaded, + required TResult Function(ChatRoomStateError value) error, + }) { + return error(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_ChatRoomState value)? $default, { + TResult? Function(ChatRoomStateLoading value)? loading, + TResult? Function(ChatRoomStateLoaded value)? loaded, + TResult? Function(ChatRoomStateError value)? error, + }) { + return error?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_ChatRoomState value)? $default, { + TResult Function(ChatRoomStateLoading value)? loading, + TResult Function(ChatRoomStateLoaded value)? loaded, + TResult Function(ChatRoomStateError value)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(this); + } + return orElse(); + } +} + +abstract class ChatRoomStateError implements ChatRoomState { + const factory ChatRoomStateError({required final String errorMessage}) = + _$ChatRoomStateErrorImpl; + + String get errorMessage; + @JsonKey(ignore: true) + _$$ChatRoomStateErrorImplCopyWith<_$ChatRoomStateErrorImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/features/chat/presentation/pages/chat_screen.dart b/lib/features/chat/presentation/pages/chat_screen.dart new file mode 100644 index 00000000..f9fd9dbd --- /dev/null +++ b/lib/features/chat/presentation/pages/chat_screen.dart @@ -0,0 +1,161 @@ +import 'package:eatvio_app/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart'; +import 'package:eatvio_app/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.dart'; +import 'package:eatvio_app/features/chat/presentation/widgets/chat_bubble_widget.dart'; +import 'package:eatvio_app/locator_service.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:eatvio_app/core/app_export.dart'; +import 'package:flutter/material.dart'; + +class ChatScreen extends StatelessWidget { + final String chatId; + + const ChatScreen({ + required this.chatId, + super.key, + }); + + Widget build(BuildContext context) { + return BlocProvider( + create: (BuildContext context) => sl()..initChat(chatId), + child: BlocBuilder( + builder: (context, state) { + if (state is ChatRoomStateLoading) { + return Scaffold( + body: Center( + child: CircularProgressIndicator(), + ), + ); + } else if (state is ChatRoomStateLoaded) { + return _buildChat(context, state); + } else if (state is ChatRoomStateError) { + return Center(child: Text(state.errorMessage)); + } else { + return Scaffold( + body: Center( + child: CircularProgressIndicator(), + ), + ); + } + }, + ), + ); + } + + _buildChat(BuildContext context, ChatRoomStateLoaded state) { + mediaQueryData = MediaQuery.of(context); + return Scaffold( + resizeToAvoidBottomInset: true, + appBar: AppBar( + titleSpacing: 0, + centerTitle: false, + title: Row( + children: [ + ClipOval( + child: SvgPicture.network( + width: 40, + height: 40, + state.chatRoomModel.users['to_chat_user']!.profilePhotoUrl!, + placeholderBuilder: (context) => CircleAvatar( + foregroundColor: PrimaryColors().backgroundAvatar, + ), + ), + ), + SizedBox(width: 16), + Text( + state.chatRoomModel.users['to_chat_user']!.name, + style: CustomTextStyles.titleSmallBold.copyWith(color: PrimaryColors().blueGray800), + ), + ], + ), + ), + body: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Expanded( + child: Container( + width: double.maxFinite, + child: ListView.builder( + reverse: true, + padding: EdgeInsets.symmetric(vertical: 16), + shrinkWrap: true, + itemBuilder: (BuildContext context, int index) { + return ChatBubbleWidget( + text: state.chatRoomModel.messages[state.chatRoomModel.messages.length - index - 1].data, + isCurrentUser: state.chatRoomModel.users['to_chat_user']!.id != state.chatRoomModel.messages[index].authorId, + ); + }, + itemCount: state.chatRoomModel.messages.length, + ), + ), + ), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox(width: 8), + InkWell( + onTap: () {}, + borderRadius: BorderRadius.circular(16), + child: Ink( + height: 32, + width: 32, + child: Icon( + Icons.attach_file_rounded, + size: 28, + ), + ), + ), + SizedBox(width: 8), + SizedBox( + width: mediaQueryData.size.width - 96, + child: TextFormField( + maxLines: 5, + minLines: 1, + keyboardType: TextInputType.multiline, + decoration: InputDecoration( + contentPadding: EdgeInsets.symmetric(horizontal: 8, vertical: 0), + hintText: 'Сообщение', + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(16), + borderSide: BorderSide( + color: Color(0xFFD1D1D6), + width: 1, + ), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(16), + borderSide: BorderSide( + color: Color(0xFFD1D1D6), + width: 1, + ), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(16), + borderSide: BorderSide( + color: Color(0xFFD1D1D6), + width: 1, + ), + ), + ), + ), + ), + SizedBox(width: 8), + InkWell( + borderRadius: BorderRadius.circular(16), + onTap: () {}, + child: Ink( + height: 32, + width: 32, + child: Icon( + Icons.send, + size: 28, + ), + ), + ), + SizedBox(width: 8), + ], + ), + ], + ), + ); + } +} diff --git a/lib/presentation/chat/chat_select_screen/bloc/chat_select_bloc.dart b/lib/features/chat/presentation/pages/chat_select_screen/bloc/chat_select_bloc.dart similarity index 94% rename from lib/presentation/chat/chat_select_screen/bloc/chat_select_bloc.dart rename to lib/features/chat/presentation/pages/chat_select_screen/bloc/chat_select_bloc.dart index b71f87c2..ba44ade1 100644 --- a/lib/presentation/chat/chat_select_screen/bloc/chat_select_bloc.dart +++ b/lib/features/chat/presentation/pages/chat_select_screen/bloc/chat_select_bloc.dart @@ -1,4 +1,6 @@ import 'package:eatvio_app/app_router.dart'; +import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen/models/chat_entry.dart'; +import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen/models/chat_select_model.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; @@ -8,8 +10,6 @@ import 'package:intl/intl.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'dart:convert'; import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/chat/chat_select_screen/models/chat_select_model.dart'; -import 'package:eatvio_app/presentation/chat/chat_select_screen/models/chat_entry.dart'; import 'package:go_router/go_router.dart'; part 'chat_select_event.dart'; diff --git a/lib/presentation/chat/chat_select_screen/bloc/chat_select_event.dart b/lib/features/chat/presentation/pages/chat_select_screen/bloc/chat_select_event.dart similarity index 100% rename from lib/presentation/chat/chat_select_screen/bloc/chat_select_event.dart rename to lib/features/chat/presentation/pages/chat_select_screen/bloc/chat_select_event.dart diff --git a/lib/presentation/chat/chat_select_screen/bloc/chat_select_state.dart b/lib/features/chat/presentation/pages/chat_select_screen/bloc/chat_select_state.dart similarity index 100% rename from lib/presentation/chat/chat_select_screen/bloc/chat_select_state.dart rename to lib/features/chat/presentation/pages/chat_select_screen/bloc/chat_select_state.dart diff --git a/lib/presentation/chat/chat_select_screen/chat_search_view.dart b/lib/features/chat/presentation/pages/chat_select_screen/chat_search_view.dart similarity index 100% rename from lib/presentation/chat/chat_select_screen/chat_search_view.dart rename to lib/features/chat/presentation/pages/chat_select_screen/chat_search_view.dart diff --git a/lib/presentation/chat/chat_select_screen/chat_select_screen.dart b/lib/features/chat/presentation/pages/chat_select_screen/chat_select_screen.dart similarity index 91% rename from lib/presentation/chat/chat_select_screen/chat_select_screen.dart rename to lib/features/chat/presentation/pages/chat_select_screen/chat_select_screen.dart index ba6c8869..e1c69857 100644 --- a/lib/presentation/chat/chat_select_screen/chat_select_screen.dart +++ b/lib/features/chat/presentation/pages/chat_select_screen/chat_select_screen.dart @@ -1,10 +1,12 @@ + +import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen/models/chat_entry.dart'; +import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen/widgets/chat_entry_widget.dart'; + import 'bloc/chat_select_bloc.dart'; import 'models/chat_select_model.dart'; import 'package:eatvio_app/core/app_export.dart'; -import '../chat_select_screen/chat_search_view.dart'; +import 'chat_search_view.dart'; import 'package:flutter/material.dart'; -import 'package:eatvio_app/presentation/chat/chat_select_screen/models/chat_entry.dart'; // ignore: must_be_immutable -import 'package:eatvio_app/presentation/chat/chat_select_screen/widgets/chat_entry_widget.dart'; // ignore: must_be_immutable class ChatSelectScreen extends StatelessWidget { const ChatSelectScreen({Key? key}) : super(key: key); diff --git a/lib/presentation/chat/chat_select_screen/models/chat_entry.dart b/lib/features/chat/presentation/pages/chat_select_screen/models/chat_entry.dart similarity index 100% rename from lib/presentation/chat/chat_select_screen/models/chat_entry.dart rename to lib/features/chat/presentation/pages/chat_select_screen/models/chat_entry.dart diff --git a/lib/presentation/chat/chat_select_screen/models/chat_select_model.dart b/lib/features/chat/presentation/pages/chat_select_screen/models/chat_select_model.dart similarity index 84% rename from lib/presentation/chat/chat_select_screen/models/chat_select_model.dart rename to lib/features/chat/presentation/pages/chat_select_screen/models/chat_select_model.dart index 2b90449e..c95b52ee 100644 --- a/lib/presentation/chat/chat_select_screen/models/chat_select_model.dart +++ b/lib/features/chat/presentation/pages/chat_select_screen/models/chat_select_model.dart @@ -1,7 +1,7 @@ // ignore_for_file: must_be_immutable +import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen/models/chat_entry.dart'; import 'package:equatable/equatable.dart'; -import 'package:eatvio_app/presentation/chat/chat_select_screen/models/chat_entry.dart'; /// This class defines the variables used in the [chat_select_screen], /// and is typically used to hold data that is passed between different parts of the application. diff --git a/lib/presentation/chat/chat_select_screen/widgets/chat_entry_widget.dart b/lib/features/chat/presentation/pages/chat_select_screen/widgets/chat_entry_widget.dart similarity index 97% rename from lib/presentation/chat/chat_select_screen/widgets/chat_entry_widget.dart rename to lib/features/chat/presentation/pages/chat_select_screen/widgets/chat_entry_widget.dart index 688999b9..6175a40e 100644 --- a/lib/presentation/chat/chat_select_screen/widgets/chat_entry_widget.dart +++ b/lib/features/chat/presentation/pages/chat_select_screen/widgets/chat_entry_widget.dart @@ -1,9 +1,9 @@ // ignore_for_file: must_be_immutable +import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen/models/chat_entry.dart'; import 'package:flutter/material.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:eatvio_app/core/app_export.dart'; -import 'package:eatvio_app/presentation/chat/chat_select_screen/models/chat_entry.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:go_router/go_router.dart'; diff --git a/lib/features/chat/presentation/widgets/chat_bubble_widget.dart b/lib/features/chat/presentation/widgets/chat_bubble_widget.dart new file mode 100644 index 00000000..88916873 --- /dev/null +++ b/lib/features/chat/presentation/widgets/chat_bubble_widget.dart @@ -0,0 +1,37 @@ +import 'package:flutter/material.dart'; + +class ChatBubbleWidget extends StatelessWidget { + const ChatBubbleWidget({ + super.key, + required this.text, + required this.isCurrentUser, + }); + + final String text; + final bool isCurrentUser; + + @override + Widget build(BuildContext context) { + return Padding( + padding: EdgeInsets.fromLTRB(isCurrentUser ? 64 : 16, 4, isCurrentUser ? 16 : 64, 4), + child: Align( + alignment: isCurrentUser ? Alignment.centerRight : Alignment.centerLeft, + child: DecoratedBox( + decoration: BoxDecoration( + color: isCurrentUser ? Colors.blue : Colors.grey[300], + borderRadius: BorderRadius.circular(16), + ), + child: Padding( + padding: const EdgeInsets.all(12), + child: Text( + text, + style: TextStyle( + color: isCurrentUser ? Colors.white : Colors.black87, + ), + ), + ), + ), + ), + ); + } +} diff --git a/lib/features/chat/repositories/chat_repository.dart b/lib/features/chat/repositories/chat_repository.dart new file mode 100644 index 00000000..2b4b87a6 --- /dev/null +++ b/lib/features/chat/repositories/chat_repository.dart @@ -0,0 +1,20 @@ +import 'package:eatvio_app/features/chat/models/chat_room_model.dart'; +import 'package:eatvio_app/features/chat/services/chat_service.dart'; + +class ChatRepository { + final ChatService chatService; + + ChatRepository({ + required this.chatService, + }); + + /// TODO use "dartz" package because need Either for error handling + Future getChatRoom(String chatId) async { + try { + return (await chatService.getChatRoomModel(chatId))['chatRoom']!; + } catch (e) { + print(e); + throw (e); + } + } +} diff --git a/lib/features/chat/services/chat_service.dart b/lib/features/chat/services/chat_service.dart new file mode 100644 index 00000000..706ecee1 --- /dev/null +++ b/lib/features/chat/services/chat_service.dart @@ -0,0 +1,13 @@ +import 'package:eatvio_app/features/chat/models/chat_room_model.dart'; +import 'package:dio/dio.dart'; +import 'package:retrofit/retrofit.dart'; + +part 'chat_service.g.dart'; + +@RestApi() +abstract class ChatService { + factory ChatService(Dio dio) = _ChatService; + + @GET('/chat/show/{id}') + Future> getChatRoomModel(@Path() String id); +} diff --git a/lib/features/chat/services/chat_service.g.dart b/lib/features/chat/services/chat_service.g.dart new file mode 100644 index 00000000..435965f3 --- /dev/null +++ b/lib/features/chat/services/chat_service.g.dart @@ -0,0 +1,78 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'chat_service.dart'; + +// ************************************************************************** +// RetrofitGenerator +// ************************************************************************** + +// ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers + +class _ChatService implements ChatService { + _ChatService( + this._dio, { + this.baseUrl, + }); + + final Dio _dio; + + String? baseUrl; + + @override + Future> getChatRoomModel(String id) async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + const Map? _data = null; + final _result = await _dio.fetch>( + _setStreamType>(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/chat/show/${id}', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + )))); + var value = _result.data!.map((k, dynamic v) => + MapEntry(k, ChatRoomModel.fromJson(v as Map))); + return value; + } + + RequestOptions _setStreamType(RequestOptions requestOptions) { + if (T != dynamic && + !(requestOptions.responseType == ResponseType.bytes || + requestOptions.responseType == ResponseType.stream)) { + if (T == String) { + requestOptions.responseType = ResponseType.plain; + } else { + requestOptions.responseType = ResponseType.json; + } + } + return requestOptions; + } + + String _combineBaseUrls( + String dioBaseUrl, + String? baseUrl, + ) { + if (baseUrl == null || baseUrl.trim().isEmpty) { + return dioBaseUrl; + } + + final url = Uri.parse(baseUrl); + + if (url.isAbsolute) { + return url.toString(); + } + + return Uri.parse(dioBaseUrl).resolveUri(url).toString(); + } +} diff --git a/lib/locator_service.dart b/lib/locator_service.dart new file mode 100644 index 00000000..68233789 --- /dev/null +++ b/lib/locator_service.dart @@ -0,0 +1,28 @@ +import 'package:dio/dio.dart'; +import 'package:eatvio_app/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart'; +import 'package:eatvio_app/features/chat/repositories/chat_repository.dart'; +import 'package:eatvio_app/features/chat/services/chat_service.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:get_it/get_it.dart'; + +final sl = GetIt.instance; + +Future init() async { + // BLoC + sl.registerFactory(() => ChatRoomCubit(chatRepository: sl())); + + // Repository + sl.registerLazySingleton(() => ChatRepository(chatService: sl())); + + // Services + sl.registerLazySingleton(() => ChatService(sl())); + + // External + sl.registerLazySingleton( + () => Dio( + BaseOptions( + baseUrl: dotenv.env['SERVER_ROOT']!, + ), + ), + ); +} diff --git a/lib/main.dart b/lib/main.dart index a99347ee..8e0c1b94 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,6 @@ import 'package:eatvio_app/app_router.dart'; -import 'package:eatvio_app/presentation/chat/chat_select_screen/bloc/chat_select_bloc.dart'; -import 'package:eatvio_app/presentation/chat/chat_select_screen/models/chat_select_model.dart'; +import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen/bloc/chat_select_bloc.dart'; +import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen/models/chat_select_model.dart'; import 'package:eatvio_app/presentation/diary/diary_edit_screen/bloc/diary_edit_bloc.dart'; import 'package:eatvio_app/presentation/diary/diary_edit_screen/models/diary_edit_model.dart'; import 'package:eatvio_app/presentation/feed/feed_screen/bloc/feed_bloc.dart'; @@ -15,11 +15,13 @@ import 'package:hive_flutter/hive_flutter.dart'; import 'package:path_provider/path_provider.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:keyboard_dismisser/keyboard_dismisser.dart'; +import 'package:eatvio_app/locator_service.dart' as di; var globalMessengerKey = GlobalKey(); void main() async { WidgetsFlutterBinding.ensureInitialized(); + await di.init(); final appDocumentDir = await getApplicationDocumentsDirectory(); final path = appDocumentDir.path; await dotenv.load(fileName: ".env"); diff --git a/lib/presentation/auth/auth_screen/auth_screen.dart b/lib/presentation/auth/auth_screen/auth_screen.dart index 72353727..67f9d1a3 100644 --- a/lib/presentation/auth/auth_screen/auth_screen.dart +++ b/lib/presentation/auth/auth_screen/auth_screen.dart @@ -1,3 +1,4 @@ +import 'package:eatvio_app/core/token_storage.dart'; import 'package:go_router/go_router.dart'; import 'bloc/auth_bloc.dart'; @@ -106,6 +107,7 @@ class AuthScreen extends StatelessWidget { final box = await Hive.openBox('token'); final token = res['token']; box.put('token', token); + TokenStorage.saveTokenInStorage(token); GoRouter.of(context).go('/my-profile-screen'); } else { showDialog( diff --git a/lib/presentation/chat/chat_screen/bloc/chat_bloc.dart b/lib/presentation/chat/chat_screen/bloc/chat_bloc.dart deleted file mode 100644 index caaa4c1b..00000000 --- a/lib/presentation/chat/chat_screen/bloc/chat_bloc.dart +++ /dev/null @@ -1,76 +0,0 @@ -import 'package:eatvio_app/app_router.dart'; -import 'package:equatable/equatable.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; -import 'package:hive/hive.dart'; -import 'package:http/http.dart' as http; -import 'package:go_router/go_router.dart'; -import 'dart:convert'; -import '/core/app_export.dart'; -import 'package:eatvio_app/presentation/chat/chat_screen/models/chat_model.dart'; -import 'package:eatvio_app/presentation/chat/chat_screen/models/chat_message_model.dart'; - -part 'chat_event.dart'; - -part 'chat_state.dart'; - -/// A bloc that manages the state of a Chat according to the event that is dispatched to it. -class ChatBloc extends Bloc { - ChatBloc(ChatState initialState) : super(initialState) { - on(_onInitialize); - } - - _onInitialize( - ChatInitialEvent event, - Emitter emit, - ) async { - try { - final box = await Hive.openBox('token'); - final token = box.get('token'); - if (token == null) { - AppRouter.navigatorKey.currentContext?.goNamed('authScreen'); - } - final String? chatID = state.chatModelObj?.chatID; - final response = await http.get( - Uri.parse(dotenv.env['SERVER_ROOT']! + '/chat/show/$chatID'), - headers: { - 'Authorization': 'Bearer $token', - }, - ); - if (response.statusCode == 200) { - final data = jsonDecode(response.body); - if (data is Map && data.containsKey('chatRoom') && data['chatRoom'].containsKey('messages')) { - if (state is ChatLoadedState) { - var currentState = state as ChatLoadedState; - emit(currentState.copyWith(chatModelObj: currentState.chatModelObj, messages: currentState.messages)); - } else { - emit(ChatLoadedState(messages: fillMessages(data['chatRoom']['messages']))); - } - } else { - // Один или несколько ключевых полей отсутствуют, обрабатываем ошибку - emit(ChatErrorState('Некоторые необходимые данные отсутствуют.')); - } - } else { - // Статус ответа не равен 200, обрабатываем ошибку - emit(ChatErrorState('Ошибка сервера: ${response.statusCode}')); - } - } catch (e) { - // Ошибка при декодировании JSON или другая ошибка выполнения - emit(ChatErrorState('Ошибка при получении данных о чатах: $e')); - } - } - - List fillMessages(List messagesJSON) { - List messages = []; - for (int i = 0; i < messagesJSON.length; i++) { - messages.add(ChatMessageModel( - id: messagesJSON[i]['id'], - data: messagesJSON[i]['data'], - mediaData: messagesJSON[i]['mediaData'] ?? [], - updatedAt: messagesJSON[i]['updated_at'], - authorId: messagesJSON[i]['author_id'])); - } - - return messages; - } -} diff --git a/lib/presentation/chat/chat_screen/bloc/chat_event.dart b/lib/presentation/chat/chat_screen/bloc/chat_event.dart deleted file mode 100644 index 1fe6df94..00000000 --- a/lib/presentation/chat/chat_screen/bloc/chat_event.dart +++ /dev/null @@ -1,16 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'chat_bloc.dart'; - -/// Abstract class for all events that can be dispatched from the -///Chat widget. -/// -/// Events must be immutable and implement the [Equatable] interface. -@immutable -abstract class ChatEvent extends Equatable {} - -/// Event that is dispatched when the Chat widget is first created. -class ChatInitialEvent extends ChatEvent { - @override - List get props => []; -} diff --git a/lib/presentation/chat/chat_screen/bloc/chat_state.dart b/lib/presentation/chat/chat_screen/bloc/chat_state.dart deleted file mode 100644 index dc9dece0..00000000 --- a/lib/presentation/chat/chat_screen/bloc/chat_state.dart +++ /dev/null @@ -1,53 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'chat_bloc.dart'; - -/// Represents the state of Chat in the application. -/// - -class ChatState extends Equatable { - ChatState({ - this.chatModelObj, - }); - - ChatModel? chatModelObj; - - @override - List get props => [chatModelObj]; - - ChatState copyWith({ChatModel? chatModelObj}) { - return ChatState( - chatModelObj: chatModelObj ?? this.chatModelObj, - ); - } -} - -class ChatLoadedState extends ChatState { - ChatLoadedState({this.chatModelObj, this.messages}); - - ChatModel? chatModelObj; - List? messages; - - @override - List get props => [chatModelObj, messages]; - - ChatLoadedState copyWith({ChatModel? chatModelObj, List? messages}) { - return ChatLoadedState( - chatModelObj: chatModelObj ?? this.chatModelObj, - messages: messages ?? this.messages, - ); - } -} - -class ChatErrorState extends ChatState { - final String errorMessage; - - ChatErrorState(this.errorMessage); - - @override - List get props => [errorMessage]; -} - -class ChatInitialState extends ChatState { - ChatInitialState({required ChatModel chatModelObj}) : super(chatModelObj: chatModelObj); -} diff --git a/lib/presentation/chat/chat_screen/chat_screen.dart b/lib/presentation/chat/chat_screen/chat_screen.dart deleted file mode 100644 index 3aadd095..00000000 --- a/lib/presentation/chat/chat_screen/chat_screen.dart +++ /dev/null @@ -1,186 +0,0 @@ -import 'package:go_router/go_router.dart'; - -import 'bloc/chat_bloc.dart'; -import 'models/chat_model.dart'; -import 'package:eatvio_app/core/app_export.dart'; -import 'package:flutter/material.dart'; -import 'package:eatvio_app/widgets/app_bar/custom_app_bar.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_subtitle.dart'; -import 'package:eatvio_app/widgets/app_bar/appbar_leading_image.dart'; - -class ChatScreen extends StatelessWidget { - const ChatScreen({Key? key}) : super(key: key); - - static Widget builder(BuildContext context, chatID) { - return BlocProvider( - create: (context) => ChatBloc(ChatState(chatModelObj: ChatModel(chatID: chatID.toString()))) - ..add( - ChatInitialEvent(), - ), - child: ChatScreen(), - ); - } - - Widget build(BuildContext context) { - return BlocBuilder( - builder: (context, state) { - if (state is ChatInitialState) { - return Scaffold( - body: Center( - child: CircularProgressIndicator(), - ), - ); - } else if (state is ChatLoadedState) { - // Данные загружены, можно строить экран. - return _buildChat(context, state); - } else if (state is ChatErrorState) { - // Произошла ошибка при загрузке данных. - return Center(child: Text(state.errorMessage)); - } else { - return Scaffold( - body: Center( - child: CircularProgressIndicator(), - ), - ); - } - }, - ); - } - - _buildChat(BuildContext context, ChatLoadedState state) { - mediaQueryData = MediaQuery.of(context); - return Scaffold( - resizeToAvoidBottomInset: true, - appBar: _buildAppbar(context, state), - body: SizedBox( - width: double.maxFinite, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - width: double.maxFinite, - decoration: AppDecoration.fillGray, - child: ListView( - shrinkWrap: true, - children: [ - for (int i = 0; i < state.messages!.length; i++) ...[Text(state.messages![i].data)] - ], - ), - ), - const Spacer(), - Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - SizedBox(width: 8), - InkWell( - onTap: () {}, - borderRadius: BorderRadius.circular(16), - child: Ink( - height: 32, - width: 32, - child: Icon( - Icons.attach_file_rounded, - size: 28, - ), - ), - ), - SizedBox(width: 8), - SizedBox( - width: mediaQueryData.size.width - 96, - child: TextFormField( - maxLines: 5, - minLines: 1, - keyboardType: TextInputType.multiline, - decoration: InputDecoration( - contentPadding: EdgeInsets.symmetric(horizontal: 8, vertical: 0), - hintText: 'Сообщение', - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(16), - borderSide: BorderSide( - color: Color(0xFFD1D1D6), - width: 1, - ), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(16), - borderSide: BorderSide( - color: Color(0xFFD1D1D6), - width: 1, - ), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(16), - borderSide: BorderSide( - color: Color(0xFFD1D1D6), - width: 1, - ), - ), - ), - ), - ), - SizedBox(width: 8), - InkWell( - borderRadius: BorderRadius.circular(16), - onTap: () {}, - child: Ink( - height: 32, - width: 32, - child: Icon( - Icons.send, - size: 28, - ), - ), - ), - SizedBox(width: 8), - ], - ), - ], - ), - ), - ); - } - - /// Section Widget - _buildAppbar(BuildContext context, ChatLoadedState state) { - return CustomAppBar( - leadingWidth: 26.h, - leading: AppbarLeadingImage( - imagePath: ImageConstant.imgArrowLeft, - margin: EdgeInsets.only( - left: 16.h, - top: 18.v, - bottom: 25.v, - ), - onTap: () => onTapArrowleftone(context), - ), - title: Padding( - padding: EdgeInsets.only(left: 12.h), - child: Row( - children: [ - Padding( - padding: EdgeInsets.only( - left: 12.h, - top: 2.v, - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - AppbarSubtitle( - text: 'username', - ), - SizedBox(height: 3.v), - Text("Был в сети вчера", style: theme.textTheme.bodySmall!) - ], - ), - ) - ], - ), - ), - ); - } - - /// Navigates to the previous screen. - onTapArrowleftone(BuildContext context) { - GoRouter.of(context).pop(); - } -} diff --git a/lib/presentation/chat/chat_screen/models/chat_message_model.dart b/lib/presentation/chat/chat_screen/models/chat_message_model.dart deleted file mode 100644 index e91596f3..00000000 --- a/lib/presentation/chat/chat_screen/models/chat_message_model.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'package:equatable/equatable.dart'; - -class ChatMessageModel extends Equatable { - final int id; - final String data; - final List mediaData; - final int authorId; - final String updatedAt; - - ChatMessageModel({ - required this.id, - required this.data, - required this.mediaData, - required this.authorId, - required this.updatedAt, - }); - - ChatMessageModel copyWith({ - int? id, - String? data, - List? mediaData, - int? authorId, - String? updatedAt, - }) { - return ChatMessageModel( - id: id ?? this.id, - data: data ?? this.data, - mediaData: mediaData ?? this.mediaData, - authorId: authorId ?? this.authorId, - updatedAt: updatedAt ?? this.updatedAt, - ); - } - - @override - List get props => [id, data, mediaData, authorId, updatedAt]; -} diff --git a/lib/presentation/chat/chat_screen/models/chat_model.dart b/lib/presentation/chat/chat_screen/models/chat_model.dart deleted file mode 100644 index 970b9ada..00000000 --- a/lib/presentation/chat/chat_screen/models/chat_model.dart +++ /dev/null @@ -1,19 +0,0 @@ -// ignore_for_file: must_be_immutable - -import 'package:equatable/equatable.dart'; - -/// This class defines the variables used in the [chat_screen], -/// and is typically used to hold data that is passed between different parts of the application. - -class ChatModel extends Equatable { - final String chatID; - - ChatModel({required String chatID}) : chatID = chatID; - - ChatModel copyWith(String chatID) { - return ChatModel(chatID: chatID); - } - - @override - List get props => [chatID]; -} diff --git a/lib/theme/custom_text_style.dart b/lib/theme/custom_text_style.dart index ff969f92..de3bee78 100644 --- a/lib/theme/custom_text_style.dart +++ b/lib/theme/custom_text_style.dart @@ -8,155 +8,171 @@ import '../core/app_export.dart'; class CustomTextStyles { // Headline style static get headlineSmallMulish => theme.textTheme.headlineSmall!.mulish; + // Title text style - static get titleMediumSegoeUI => - theme.textTheme.titleMedium!.segoeUI.copyWith( + static get titleMediumSegoeUI => theme.textTheme.titleMedium!.segoeUI.copyWith( fontWeight: FontWeight.w600, ); + static get bodyMediumBlack900 => theme.textTheme.bodyMedium!.copyWith( color: appTheme.black900, ); + static get bodyMediumBlack90013 => theme.textTheme.bodyMedium!.copyWith( color: appTheme.black900, fontSize: 13.fSize, ); + static get bodyMediumBluegray800 => theme.textTheme.bodyMedium!.copyWith( color: appTheme.blueGray800, ); + static get bodyMediumBluegray800_1 => theme.textTheme.bodyMedium!.copyWith( color: appTheme.blueGray800, ); + static get bodyMediumBluegray800_2 => theme.textTheme.bodyMedium!.copyWith( color: appTheme.blueGray800, ); + static get bodyMediumWhiteA700 => theme.textTheme.bodyMedium!.copyWith( color: appTheme.whiteA700, ); - static get bodySmallMulishBlack900 => - theme.textTheme.bodySmall!.mulish.copyWith( + + static get bodySmallMulishBlack900 => theme.textTheme.bodySmall!.mulish.copyWith( color: appTheme.black900, fontSize: 12.fSize, ); - static get bodySmallMulishBluegray800 => - theme.textTheme.bodySmall!.mulish.copyWith( + + static get bodySmallMulishBluegray800 => theme.textTheme.bodySmall!.mulish.copyWith( color: appTheme.blueGray800, fontSize: 12.fSize, ); - static get bodySmallMulishBluegray80012 => - theme.textTheme.bodySmall!.mulish.copyWith( + + static get bodySmallMulishBluegray80012 => theme.textTheme.bodySmall!.mulish.copyWith( color: appTheme.blueGray800, fontSize: 12.fSize, ); - static get bodySmallMulishBluegray80012_1 => - theme.textTheme.bodySmall!.mulish.copyWith( + + static get bodySmallMulishBluegray80012_1 => theme.textTheme.bodySmall!.mulish.copyWith( color: appTheme.blueGray800, fontSize: 12.fSize, ); - static get bodySmallMulishBluegray900 => - theme.textTheme.bodySmall!.mulish.copyWith( + + static get bodySmallMulishBluegray900 => theme.textTheme.bodySmall!.mulish.copyWith( color: appTheme.blueGray900, fontSize: 12.fSize, ); - static get bodySmallMulishGray600 => - theme.textTheme.bodySmall!.mulish.copyWith( + + static get bodySmallMulishGray600 => theme.textTheme.bodySmall!.mulish.copyWith( color: appTheme.gray600, ); - static get bodySmallMulishPrimary => - theme.textTheme.bodySmall!.mulish.copyWith( + + static get bodySmallMulishPrimary => theme.textTheme.bodySmall!.mulish.copyWith( color: theme.colorScheme.primary, fontSize: 12.fSize, ); - static get bodySmallSegoeUIBlack900 => - theme.textTheme.bodySmall!.segoeUI.copyWith( + + static get bodySmallSegoeUIBlack900 => theme.textTheme.bodySmall!.segoeUI.copyWith( color: appTheme.black900, fontSize: 12.fSize, ); + // Label text style static get labelLargeGray60003 => theme.textTheme.labelLarge!.copyWith( color: appTheme.gray60003, ); + static get labelLargeWhiteA700 => theme.textTheme.labelLarge!.copyWith( color: appTheme.whiteA700, ); + // Title text style static get titleMedium16 => theme.textTheme.titleMedium!.copyWith( fontSize: 16.fSize, ); + static get titleMediumBlack => theme.textTheme.titleMedium!.copyWith( fontSize: 17.fSize, fontWeight: FontWeight.w900, ); + static get titleMediumBlack900 => theme.textTheme.titleMedium!.copyWith( color: appTheme.black900, ); + static get titleMediumSemiBold => theme.textTheme.titleMedium!.copyWith( fontWeight: FontWeight.w600, ); + static get titleMediumWhiteA700 => theme.textTheme.titleMedium!.copyWith( color: appTheme.whiteA700, fontWeight: FontWeight.w600, ); + static get titleSmallBlue800 => theme.textTheme.titleSmall!.copyWith( color: appTheme.blue800, fontWeight: FontWeight.w800, ); + static get titleSmallBluegray800 => theme.textTheme.titleSmall!.copyWith( color: appTheme.blueGray800, ); + static get titleSmallBluegray800Bold => theme.textTheme.titleSmall!.copyWith( color: appTheme.blueGray800, fontWeight: FontWeight.w700, ); - static get titleSmallBluegray800ExtraBold => - theme.textTheme.titleSmall!.copyWith( + + static get titleSmallBluegray800ExtraBold => theme.textTheme.titleSmall!.copyWith( color: appTheme.blueGray800, fontWeight: FontWeight.w800, ); + static get titleSmallBold => theme.textTheme.titleSmall!.copyWith( fontSize: 15.fSize, fontWeight: FontWeight.w700, ); + static get titleSmallGreenA70001 => theme.textTheme.titleSmall!.copyWith( color: appTheme.greenA70001, ); - static get titleSmallGreenA70001ExtraBold => - theme.textTheme.titleSmall!.copyWith( + + static get titleSmallGreenA70001ExtraBold => theme.textTheme.titleSmall!.copyWith( color: appTheme.greenA70001, fontWeight: FontWeight.w800, ); + static get titleSmallLightgreen300 => theme.textTheme.titleSmall!.copyWith( color: appTheme.lightGreen300, fontWeight: FontWeight.w800, ); + static get titleSmallRed200 => theme.textTheme.titleSmall!.copyWith( color: appTheme.red200, fontWeight: FontWeight.w800, ); - static get titleSmallSecondaryContainer => - theme.textTheme.titleSmall!.copyWith( + + static get titleSmallSecondaryContainer => theme.textTheme.titleSmall!.copyWith( color: theme.colorScheme.secondaryContainer, fontWeight: FontWeight.w800, ); - static get titleSmallSecondaryContainer_1 => - theme.textTheme.titleSmall!.copyWith( + + static get titleSmallSecondaryContainer_1 => theme.textTheme.titleSmall!.copyWith( color: theme.colorScheme.secondaryContainer, ); - static get titleSmallSegoeUIOnPrimary => - theme.textTheme.titleSmall!.segoeUI.copyWith( + + static get titleSmallSegoeUIOnPrimary => theme.textTheme.titleSmall!.segoeUI.copyWith( color: theme.colorScheme.onPrimary, ); } extension on TextStyle { TextStyle get mulish { - return copyWith( - fontFamily: 'Mulish', - ); + return copyWith(); } TextStyle get segoeUI { - return copyWith( - fontFamily: 'Segoe UI', - ); + return copyWith(); } } diff --git a/lib/theme/theme_helper.dart b/lib/theme/theme_helper.dart index 68aa928a..7226e373 100644 --- a/lib/theme/theme_helper.dart +++ b/lib/theme/theme_helper.dart @@ -195,6 +195,8 @@ class PrimaryColors { // White Color get whiteA700 => Color(0XFFFFFFFF); + + Color get backgroundAvatar => Color(0xFFEBF4FF); } PrimaryColors get appTheme => ThemeHelper().themeColor(); diff --git a/pubspec.yaml b/pubspec.yaml index 1cc0d440..281a964a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -31,9 +31,20 @@ dependencies: go_router: ^14.1.4 keyboard_dismisser: ^3.0.0 + freezed_annotation: ^2.4.1 + json_annotation: ^4.9.0 + retrofit: ^4.1.0 + get_it: ^7.7.0 + dio: ^5.4.3+1 + dev_dependencies: dart_code_metrics: ^5.7.6 dart_code_metrics_presets: ^1.8.0 + build_runner: ^2.4.9 + freezed: ^2.5.2 + json_serializable: ^6.8.0 + retrofit_generator: ^8.1.0 + flutter_test: sdk: flutter @@ -43,13 +54,13 @@ flutter: - assets/ - assets/images/ - .env - fonts: + fonts: - family: Segoe UI - fonts: + fonts: - asset: assets/fonts/SegoeUISemibold.ttf weight: 600 - family: Mulish - fonts: + fonts: - asset: assets/fonts/MulishBold.ttf weight: 700 - asset: assets/fonts/MulishRegular.ttf