From 7e8fcfc24a0290542e50ece2daa718c0422b6680 Mon Sep 17 00:00:00 2001 From: YaAndreyIgorevich Date: Sat, 7 Mar 2026 03:42:50 +0700 Subject: [PATCH] Init --- .gitignore | 15 + .idea/.gitignore | 3 + .idea/AndroidProjectSystem.xml | 6 + .idea/compiler.xml | 6 + .idea/deploymentTargetSelector.xml | 18 + .idea/deviceManager.xml | 13 + .idea/gradle.xml | 19 + .idea/migrations.xml | 10 + .idea/misc.xml | 9 + .idea/runConfigurations.xml | 17 + .idea/vcs.xml | 6 + app/.gitignore | 1 + app/build.gradle.kts | 106 +++++ app/google-services.json | 29 ++ app/proguard-rules.pro | 21 + .../messenger/ExampleInstrumentedTest.kt | 24 + app/src/main/AndroidManifest.xml | 38 ++ app/src/main/ic_launcher-playstore.png | Bin 0 -> 202120 bytes .../java/org/yobble/messenger/MainActivity.kt | 65 +++ .../java/org/yobble/messenger/YobbleApp.kt | 56 +++ .../messenger/data/local/PushTokenManager.kt | 28 ++ .../messenger/data/local/SessionManager.kt | 85 ++++ .../messenger/data/remote/NetworkResult.kt | 46 ++ .../messenger/data/remote/api/AuthApi.kt | 57 +++ .../data/remote/api/ChatPrivateApi.kt | 36 ++ .../messenger/data/remote/api/FeedApi.kt | 14 + .../messenger/data/remote/api/ProfileApi.kt | 21 + .../messenger/data/remote/api/StorageApi.kt | 17 + .../messenger/data/remote/api/UserApi.kt | 52 ++ .../data/remote/dto/AuthRequestDto.kt | 40 ++ .../data/remote/dto/AuthResponseDto.kt | 64 +++ .../data/remote/dto/ChatPrivateDto.kt | 110 +++++ .../messenger/data/remote/dto/ContactDto.kt | 116 +++++ .../messenger/data/remote/dto/FeedDto.kt | 22 + .../messenger/data/remote/dto/ProfileDto.kt | 158 ++++++ .../messenger/data/remote/dto/SessionDto.kt | 27 ++ .../messenger/data/remote/dto/StorageDto.kt | 15 + .../data/remote/fcm/YobbleFcmService.kt | 83 ++++ .../remote/interceptor/AuthInterceptor.kt | 27 ++ .../remote/interceptor/TokenAuthenticator.kt | 64 +++ .../data/remote/socket/SocketManager.kt | 171 +++++++ .../data/repository/AuthRepositoryImpl.kt | 99 ++++ .../data/repository/ChatRepositoryImpl.kt | 39 ++ .../data/repository/FeedRepositoryImpl.kt | 19 + .../data/repository/ProfileRepositoryImpl.kt | 44 ++ .../data/repository/UserRepositoryImpl.kt | 47 ++ .../org/yobble/messenger/di/NetworkModule.kt | 101 ++++ .../yobble/messenger/di/RepositoryModule.kt | 42 ++ .../domain/repository/AuthRepository.kt | 21 + .../domain/repository/ChatRepository.kt | 12 + .../domain/repository/FeedRepository.kt | 8 + .../domain/repository/ProfileRepository.kt | 16 + .../domain/repository/UserRepository.kt | 18 + .../domain/validation/AuthValidator.kt | 45 ++ .../auth/code/CodeVerificationScreen.kt | 150 ++++++ .../auth/code/CodeVerificationViewModel.kt | 101 ++++ .../presentation/auth/login/LoginScreen.kt | 195 ++++++++ .../presentation/auth/login/LoginViewModel.kt | 121 +++++ .../auth/register/RegisterScreen.kt | 235 +++++++++ .../auth/register/RegisterViewModel.kt | 113 +++++ .../messenger/presentation/chat/ChatScreen.kt | 374 +++++++++++++++ .../presentation/chat/ChatViewModel.kt | 222 +++++++++ .../common/FullScreenImageViewer.kt | 88 ++++ .../presentation/common/UserAvatar.kt | 82 ++++ .../presentation/contacts/ContactsScreen.kt | 430 +++++++++++++++++ .../contacts/ContactsViewModel.kt | 233 +++++++++ .../messenger/presentation/main/HomeScreen.kt | 448 +++++++++++++++++ .../presentation/main/HomeViewModel.kt | 132 +++++ .../presentation/navigation/AppNavGraph.kt | 174 +++++++ .../presentation/profile/ProfileScreen.kt | 449 ++++++++++++++++++ .../presentation/profile/ProfileViewModel.kt | 258 ++++++++++ .../presentation/search/SearchScreen.kt | 222 +++++++++ .../presentation/search/SearchViewModel.kt | 64 +++ .../presentation/settings/BlacklistScreen.kt | 246 ++++++++++ .../settings/BlacklistViewModel.kt | 134 ++++++ .../settings/ChangePasswordScreen.kt | 147 ++++++ .../presentation/settings/PrivacyScreen.kt | 306 ++++++++++++ .../presentation/settings/SessionsScreen.kt | 211 ++++++++ .../presentation/settings/SettingsScreen.kt | 119 +++++ .../settings/SettingsViewModel.kt | 221 +++++++++ .../org/yobble/messenger/ui/theme/Color.kt | 31 ++ .../org/yobble/messenger/ui/theme/Theme.kt | 69 +++ .../org/yobble/messenger/ui/theme/Type.kt | 74 +++ .../org/yobble/messenger/util/TimeUtils.kt | 15 + .../res/drawable/ic_launcher_background.xml | 74 +++ .../res/drawable/ic_launcher_foreground.xml | 30 ++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + app/src/main/res/mipmap-hdpi/ic_launcher.webp | Bin 0 -> 5356 bytes .../mipmap-hdpi/ic_launcher_foreground.webp | Bin 0 -> 14852 bytes .../res/mipmap-hdpi/ic_launcher_round.webp | Bin 0 -> 7088 bytes app/src/main/res/mipmap-mdpi/ic_launcher.webp | Bin 0 -> 3196 bytes .../mipmap-mdpi/ic_launcher_foreground.webp | Bin 0 -> 8100 bytes .../res/mipmap-mdpi/ic_launcher_round.webp | Bin 0 -> 3946 bytes .../main/res/mipmap-xhdpi/ic_launcher.webp | Bin 0 -> 8130 bytes .../mipmap-xhdpi/ic_launcher_foreground.webp | Bin 0 -> 22882 bytes .../res/mipmap-xhdpi/ic_launcher_round.webp | Bin 0 -> 10610 bytes .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin 0 -> 14424 bytes .../mipmap-xxhdpi/ic_launcher_foreground.webp | Bin 0 -> 35962 bytes .../res/mipmap-xxhdpi/ic_launcher_round.webp | Bin 0 -> 18736 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin 0 -> 17650 bytes .../ic_launcher_foreground.webp | Bin 0 -> 58160 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.webp | Bin 0 -> 23018 bytes app/src/main/res/values/colors.xml | 10 + app/src/main/res/values/strings.xml | 3 + app/src/main/res/values/themes.xml | 5 + app/src/main/res/xml/backup_rules.xml | 13 + .../main/res/xml/data_extraction_rules.xml | 19 + .../org/yobble/messenger/ExampleUnitTest.kt | 17 + build.gradle.kts | 10 + gradle.properties | 23 + gradle/libs.versions.toml | 73 +++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 45457 bytes gradle/wrapper/gradle-wrapper.properties | 8 + gradlew | 251 ++++++++++ gradlew.bat | 94 ++++ settings.gradle.kts | 24 + 117 files changed, 8554 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.gitignore create mode 100644 .idea/AndroidProjectSystem.xml create mode 100644 .idea/compiler.xml create mode 100644 .idea/deploymentTargetSelector.xml create mode 100644 .idea/deviceManager.xml create mode 100644 .idea/gradle.xml create mode 100644 .idea/migrations.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/runConfigurations.xml create mode 100644 .idea/vcs.xml create mode 100644 app/.gitignore create mode 100644 app/build.gradle.kts create mode 100644 app/google-services.json create mode 100644 app/proguard-rules.pro create mode 100644 app/src/androidTest/java/org/yobble/messenger/ExampleInstrumentedTest.kt create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/ic_launcher-playstore.png create mode 100644 app/src/main/java/org/yobble/messenger/MainActivity.kt create mode 100644 app/src/main/java/org/yobble/messenger/YobbleApp.kt create mode 100644 app/src/main/java/org/yobble/messenger/data/local/PushTokenManager.kt create mode 100644 app/src/main/java/org/yobble/messenger/data/local/SessionManager.kt create mode 100644 app/src/main/java/org/yobble/messenger/data/remote/NetworkResult.kt create mode 100644 app/src/main/java/org/yobble/messenger/data/remote/api/AuthApi.kt create mode 100644 app/src/main/java/org/yobble/messenger/data/remote/api/ChatPrivateApi.kt create mode 100644 app/src/main/java/org/yobble/messenger/data/remote/api/FeedApi.kt create mode 100644 app/src/main/java/org/yobble/messenger/data/remote/api/ProfileApi.kt create mode 100644 app/src/main/java/org/yobble/messenger/data/remote/api/StorageApi.kt create mode 100644 app/src/main/java/org/yobble/messenger/data/remote/api/UserApi.kt create mode 100644 app/src/main/java/org/yobble/messenger/data/remote/dto/AuthRequestDto.kt create mode 100644 app/src/main/java/org/yobble/messenger/data/remote/dto/AuthResponseDto.kt create mode 100644 app/src/main/java/org/yobble/messenger/data/remote/dto/ChatPrivateDto.kt create mode 100644 app/src/main/java/org/yobble/messenger/data/remote/dto/ContactDto.kt create mode 100644 app/src/main/java/org/yobble/messenger/data/remote/dto/FeedDto.kt create mode 100644 app/src/main/java/org/yobble/messenger/data/remote/dto/ProfileDto.kt create mode 100644 app/src/main/java/org/yobble/messenger/data/remote/dto/SessionDto.kt create mode 100644 app/src/main/java/org/yobble/messenger/data/remote/dto/StorageDto.kt create mode 100644 app/src/main/java/org/yobble/messenger/data/remote/fcm/YobbleFcmService.kt create mode 100644 app/src/main/java/org/yobble/messenger/data/remote/interceptor/AuthInterceptor.kt create mode 100644 app/src/main/java/org/yobble/messenger/data/remote/interceptor/TokenAuthenticator.kt create mode 100644 app/src/main/java/org/yobble/messenger/data/remote/socket/SocketManager.kt create mode 100644 app/src/main/java/org/yobble/messenger/data/repository/AuthRepositoryImpl.kt create mode 100644 app/src/main/java/org/yobble/messenger/data/repository/ChatRepositoryImpl.kt create mode 100644 app/src/main/java/org/yobble/messenger/data/repository/FeedRepositoryImpl.kt create mode 100644 app/src/main/java/org/yobble/messenger/data/repository/ProfileRepositoryImpl.kt create mode 100644 app/src/main/java/org/yobble/messenger/data/repository/UserRepositoryImpl.kt create mode 100644 app/src/main/java/org/yobble/messenger/di/NetworkModule.kt create mode 100644 app/src/main/java/org/yobble/messenger/di/RepositoryModule.kt create mode 100644 app/src/main/java/org/yobble/messenger/domain/repository/AuthRepository.kt create mode 100644 app/src/main/java/org/yobble/messenger/domain/repository/ChatRepository.kt create mode 100644 app/src/main/java/org/yobble/messenger/domain/repository/FeedRepository.kt create mode 100644 app/src/main/java/org/yobble/messenger/domain/repository/ProfileRepository.kt create mode 100644 app/src/main/java/org/yobble/messenger/domain/repository/UserRepository.kt create mode 100644 app/src/main/java/org/yobble/messenger/domain/validation/AuthValidator.kt create mode 100644 app/src/main/java/org/yobble/messenger/presentation/auth/code/CodeVerificationScreen.kt create mode 100644 app/src/main/java/org/yobble/messenger/presentation/auth/code/CodeVerificationViewModel.kt create mode 100644 app/src/main/java/org/yobble/messenger/presentation/auth/login/LoginScreen.kt create mode 100644 app/src/main/java/org/yobble/messenger/presentation/auth/login/LoginViewModel.kt create mode 100644 app/src/main/java/org/yobble/messenger/presentation/auth/register/RegisterScreen.kt create mode 100644 app/src/main/java/org/yobble/messenger/presentation/auth/register/RegisterViewModel.kt create mode 100644 app/src/main/java/org/yobble/messenger/presentation/chat/ChatScreen.kt create mode 100644 app/src/main/java/org/yobble/messenger/presentation/chat/ChatViewModel.kt create mode 100644 app/src/main/java/org/yobble/messenger/presentation/common/FullScreenImageViewer.kt create mode 100644 app/src/main/java/org/yobble/messenger/presentation/common/UserAvatar.kt create mode 100644 app/src/main/java/org/yobble/messenger/presentation/contacts/ContactsScreen.kt create mode 100644 app/src/main/java/org/yobble/messenger/presentation/contacts/ContactsViewModel.kt create mode 100644 app/src/main/java/org/yobble/messenger/presentation/main/HomeScreen.kt create mode 100644 app/src/main/java/org/yobble/messenger/presentation/main/HomeViewModel.kt create mode 100644 app/src/main/java/org/yobble/messenger/presentation/navigation/AppNavGraph.kt create mode 100644 app/src/main/java/org/yobble/messenger/presentation/profile/ProfileScreen.kt create mode 100644 app/src/main/java/org/yobble/messenger/presentation/profile/ProfileViewModel.kt create mode 100644 app/src/main/java/org/yobble/messenger/presentation/search/SearchScreen.kt create mode 100644 app/src/main/java/org/yobble/messenger/presentation/search/SearchViewModel.kt create mode 100644 app/src/main/java/org/yobble/messenger/presentation/settings/BlacklistScreen.kt create mode 100644 app/src/main/java/org/yobble/messenger/presentation/settings/BlacklistViewModel.kt create mode 100644 app/src/main/java/org/yobble/messenger/presentation/settings/ChangePasswordScreen.kt create mode 100644 app/src/main/java/org/yobble/messenger/presentation/settings/PrivacyScreen.kt create mode 100644 app/src/main/java/org/yobble/messenger/presentation/settings/SessionsScreen.kt create mode 100644 app/src/main/java/org/yobble/messenger/presentation/settings/SettingsScreen.kt create mode 100644 app/src/main/java/org/yobble/messenger/presentation/settings/SettingsViewModel.kt create mode 100644 app/src/main/java/org/yobble/messenger/ui/theme/Color.kt create mode 100644 app/src/main/java/org/yobble/messenger/ui/theme/Theme.kt create mode 100644 app/src/main/java/org/yobble/messenger/ui/theme/Type.kt create mode 100644 app/src/main/java/org/yobble/messenger/util/TimeUtils.kt create mode 100644 app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 app/src/main/res/drawable/ic_launcher_foreground.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/values/colors.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/themes.xml create mode 100644 app/src/main/res/xml/backup_rules.xml create mode 100644 app/src/main/res/xml/data_extraction_rules.xml create mode 100644 app/src/test/java/org/yobble/messenger/ExampleUnitTest.kt create mode 100644 build.gradle.kts create mode 100644 gradle.properties create mode 100644 gradle/libs.versions.toml create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle.kts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/AndroidProjectSystem.xml b/.idea/AndroidProjectSystem.xml new file mode 100644 index 0000000..4a53bee --- /dev/null +++ b/.idea/AndroidProjectSystem.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..b86273d --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000..368ad42 --- /dev/null +++ b/.idea/deploymentTargetSelector.xml @@ -0,0 +1,18 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/deviceManager.xml b/.idea/deviceManager.xml new file mode 100644 index 0000000..91f9558 --- /dev/null +++ b/.idea/deviceManager.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..639c779 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..b2c751a --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..16660f1 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..a1f0900 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,106 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.compose) + alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.hilt) + alias(libs.plugins.ksp) + alias(libs.plugins.google.services) +} + +android { + namespace = "org.yobble.messenger" + compileSdk { + version = release(36) + } + + defaultConfig { + applicationId = "org.yobble.messenger" + minSdk = 28 + targetSdk = 36 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + + buildConfigField("String", "BASE_URL", "\"https://dev.api.yobble.org/\"") + buildConfigField("String", "USER_AGENT", "\"yobble android/${versionName}\"") + buildConfigField("String", "SOCKET_PATH", "\"/socket.io/\"") + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + kotlinOptions { + jvmTarget = "11" + } + buildFeatures { + compose = true + buildConfig = true + } +} + +dependencies { + // Core + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.lifecycle.runtime.ktx) + implementation(libs.androidx.lifecycle.runtime.compose) + implementation(libs.androidx.lifecycle.viewmodel.compose) + implementation(libs.kotlinx.coroutines.android) + + // Compose + implementation(libs.androidx.activity.compose) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.compose.ui) + implementation(libs.androidx.compose.ui.graphics) + implementation(libs.androidx.compose.ui.tooling.preview) + implementation(libs.androidx.compose.material3) + implementation(libs.androidx.compose.material.icons.extended) + + // Navigation + implementation(libs.androidx.navigation.compose) + + // Hilt + implementation(libs.hilt.android) + ksp(libs.hilt.android.compiler) + implementation(libs.hilt.navigation.compose) + + // Network + implementation(libs.retrofit) + implementation(libs.okhttp) + implementation(libs.okhttp.logging.interceptor) + implementation(libs.retrofit.kotlinx.serialization) + implementation(libs.kotlinx.serialization.json) + + // Firebase + implementation(platform(libs.firebase.bom)) + implementation(libs.firebase.messaging) + + // Socket.IO + implementation(libs.socket.io.client) + + // Image loading + implementation(libs.coil.compose) + + // Security + implementation(libs.androidx.security.crypto) + + // Test + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) + androidTestImplementation(platform(libs.androidx.compose.bom)) + androidTestImplementation(libs.androidx.compose.ui.test.junit4) + debugImplementation(libs.androidx.compose.ui.tooling) + debugImplementation(libs.androidx.compose.ui.test.manifest) +} diff --git a/app/google-services.json b/app/google-services.json new file mode 100644 index 0000000..35f214a --- /dev/null +++ b/app/google-services.json @@ -0,0 +1,29 @@ +{ + "project_info": { + "project_number": "1058456897662", + "project_id": "yobble", + "storage_bucket": "yobble.firebasestorage.app" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:1058456897662:android:0c9ec958c52ba6df09f02f", + "android_client_info": { + "package_name": "org.yobble.messenger" + } + }, + "oauth_client": [], + "api_key": [ + { + "current_key": "AIzaSyBhP8fd4Vbj-2lheoQpwf4KubGHerwR6eU" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/androidTest/java/org/yobble/messenger/ExampleInstrumentedTest.kt b/app/src/androidTest/java/org/yobble/messenger/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..72951f8 --- /dev/null +++ b/app/src/androidTest/java/org/yobble/messenger/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package org.yobble.messenger + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("ru.cardinalnsk.yobble", appContext.packageName) + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..3440126 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png new file mode 100644 index 0000000000000000000000000000000000000000..d4bb84ea649440223254f5f6d293717fdb372c02 GIT binary patch literal 202120 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 literal 0 HcmV?d00001 diff --git a/app/src/main/java/org/yobble/messenger/MainActivity.kt b/app/src/main/java/org/yobble/messenger/MainActivity.kt new file mode 100644 index 0000000..1fa18a3 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/MainActivity.kt @@ -0,0 +1,65 @@ +package org.yobble.messenger + +import android.Manifest +import android.content.pm.PackageManager +import android.os.Build +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.runtime.Composable +import androidx.core.content.ContextCompat +import androidx.navigation.compose.rememberNavController +import dagger.hilt.android.AndroidEntryPoint +import org.yobble.messenger.data.local.SessionManager +import org.yobble.messenger.presentation.navigation.AppNavGraph +import org.yobble.messenger.presentation.navigation.Routes +import org.yobble.messenger.ui.theme.YobbleTheme +import javax.inject.Inject + +@AndroidEntryPoint +class MainActivity : ComponentActivity() { + + @Inject + lateinit var sessionManager: SessionManager + + private val notificationPermissionLauncher = registerForActivityResult( + ActivityResultContracts.RequestPermission() + ) { _ -> } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + requestNotificationPermission() + + val startDestination = if (sessionManager.isLoggedIn) Routes.HOME else Routes.LOGIN + + setContent { + YobbleTheme { + YobbleAppContent(startDestination = startDestination) + } + } + } + + private fun requestNotificationPermission() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + if (ContextCompat.checkSelfPermission( + this, + Manifest.permission.POST_NOTIFICATIONS + ) != PackageManager.PERMISSION_GRANTED + ) { + notificationPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS) + } + } + } +} + +@Composable +private fun YobbleAppContent(startDestination: String) { + val navController = rememberNavController() + AppNavGraph( + navController = navController, + startDestination = startDestination + ) +} diff --git a/app/src/main/java/org/yobble/messenger/YobbleApp.kt b/app/src/main/java/org/yobble/messenger/YobbleApp.kt new file mode 100644 index 0000000..ca824ae --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/YobbleApp.kt @@ -0,0 +1,56 @@ +package org.yobble.messenger + +import android.app.Application +import android.app.NotificationChannel +import android.app.NotificationManager +import coil.ImageLoader +import coil.ImageLoaderFactory +import dagger.hilt.android.HiltAndroidApp +import okhttp3.OkHttpClient +import javax.inject.Inject + +@HiltAndroidApp +class YobbleApp : Application(), ImageLoaderFactory { + + @Inject + lateinit var okHttpClient: OkHttpClient + + override fun onCreate() { + super.onCreate() + createNotificationChannels() + } + + override fun newImageLoader(): ImageLoader { + return ImageLoader.Builder(this) + .okHttpClient(okHttpClient) + .crossfade(true) + .build() + } + + private fun createNotificationChannels() { + val manager = getSystemService(NotificationManager::class.java) + + val messagesChannel = NotificationChannel( + CHANNEL_MESSAGES, + "Messages", + NotificationManager.IMPORTANCE_HIGH + ).apply { + description = "New message notifications" + } + + val generalChannel = NotificationChannel( + CHANNEL_GENERAL, + "General", + NotificationManager.IMPORTANCE_DEFAULT + ).apply { + description = "General notifications" + } + + manager.createNotificationChannels(listOf(messagesChannel, generalChannel)) + } + + companion object { + const val CHANNEL_MESSAGES = "messages" + const val CHANNEL_GENERAL = "general" + } +} diff --git a/app/src/main/java/org/yobble/messenger/data/local/PushTokenManager.kt b/app/src/main/java/org/yobble/messenger/data/local/PushTokenManager.kt new file mode 100644 index 0000000..bbac1cd --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/data/local/PushTokenManager.kt @@ -0,0 +1,28 @@ +package org.yobble.messenger.data.local + +import com.google.firebase.messaging.FirebaseMessaging +import kotlinx.coroutines.tasks.await +import org.yobble.messenger.data.remote.NetworkResult +import org.yobble.messenger.data.remote.api.AuthApi +import org.yobble.messenger.data.remote.safeApiCall +import kotlinx.serialization.json.Json +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class PushTokenManager @Inject constructor( + private val authApi: AuthApi, + private val sessionManager: SessionManager, + private val json: Json +) { + suspend fun registerPushToken() { + if (!sessionManager.isLoggedIn) return + + try { + val token = FirebaseMessaging.getInstance().token.await() + safeApiCall(json) { authApi.updatePushToken(token) } + } catch (_: Exception) { + // Firebase not available or network error — silently ignore + } + } +} diff --git a/app/src/main/java/org/yobble/messenger/data/local/SessionManager.kt b/app/src/main/java/org/yobble/messenger/data/local/SessionManager.kt new file mode 100644 index 0000000..849fea3 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/data/local/SessionManager.kt @@ -0,0 +1,85 @@ +package org.yobble.messenger.data.local + +import android.content.Context +import android.content.SharedPreferences +import androidx.security.crypto.EncryptedSharedPreferences +import androidx.security.crypto.MasterKey +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject +import javax.inject.Singleton +import androidx.core.content.edit + +@Singleton +class SessionManager @Inject constructor( + @ApplicationContext context: Context +) { + private val masterKey = MasterKey.Builder(context) + .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) + .build() + + private val prefs: SharedPreferences = EncryptedSharedPreferences.create( + context, + "yobble_session_prefs", + masterKey, + EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, + EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM + ) + + private val localPrefs: SharedPreferences = context.getSharedPreferences( + "yobble_local_prefs", Context.MODE_PRIVATE + ) + + var accessToken: String? + get() = prefs.getString(KEY_ACCESS_TOKEN, null) + set(value) = prefs.edit { putString(KEY_ACCESS_TOKEN, value) } + + var refreshToken: String? + get() = prefs.getString(KEY_REFRESH_TOKEN, null) + set(value) = prefs.edit { putString(KEY_REFRESH_TOKEN, value) } + + var userId: String? + get() = prefs.getString(KEY_USER_ID, null) + set(value) = prefs.edit { putString(KEY_USER_ID, value) } + + val isLoggedIn: Boolean + get() = accessToken != null + + fun saveSession(accessToken: String, refreshToken: String, userId: String) { + prefs.edit { + putString(KEY_ACCESS_TOKEN, accessToken) + .putString(KEY_REFRESH_TOKEN, refreshToken) + .putString(KEY_USER_ID, userId) + } + } + + fun clearSession() { + prefs.edit { clear() } + localPrefs.edit { clear() } + } + + fun saveLastReadMessageId(chatId: String, messageId: String) { + localPrefs.edit { putString("last_read_$chatId", messageId) } + } + + fun getLastReadMessageId(chatId: String): String? { + return localPrefs.getString("last_read_$chatId", null) + } + + fun saveDraft(chatId: String, text: String) { + if (text.isBlank()) { + localPrefs.edit { remove("draft_$chatId") } + } else { + localPrefs.edit { putString("draft_$chatId", text) } + } + } + + fun getDraft(chatId: String): String { + return localPrefs.getString("draft_$chatId", null) ?: "" + } + + companion object { + private const val KEY_ACCESS_TOKEN = "access_token" + private const val KEY_REFRESH_TOKEN = "refresh_token" + private const val KEY_USER_ID = "user_id" + } +} diff --git a/app/src/main/java/org/yobble/messenger/data/remote/NetworkResult.kt b/app/src/main/java/org/yobble/messenger/data/remote/NetworkResult.kt new file mode 100644 index 0000000..fc2d5e1 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/data/remote/NetworkResult.kt @@ -0,0 +1,46 @@ +package org.yobble.messenger.data.remote + +import kotlinx.serialization.json.Json +import org.yobble.messenger.data.remote.dto.ErrorResponseDto +import retrofit2.Response + +sealed class NetworkResult { + data class Success(val data: T) : NetworkResult() + data class Error( + val code: Int, + val errors: List = emptyList(), + val message: String? = null + ) : NetworkResult() + data class Exception(val throwable: Throwable) : NetworkResult() +} + +data class FieldError(val field: String, val message: String) + +suspend fun safeApiCall(json: Json, apiCall: suspend () -> Response): NetworkResult { + return try { + val response = apiCall() + if (response.isSuccessful) { + val body = response.body() + if (body != null) { + NetworkResult.Success(body) + } else { + NetworkResult.Error(response.code(), message = "Empty response body") + } + } else { + val errorBody = response.errorBody()?.string() + val errors = if (errorBody != null) { + try { + val errorResponse = json.decodeFromString(errorBody) + errorResponse.errors.map { FieldError(it.field, it.message) } + } catch (e: kotlin.Exception) { + emptyList() + } + } else { + emptyList() + } + NetworkResult.Error(response.code(), errors, response.message()) + } + } catch (e: kotlin.Exception) { + NetworkResult.Exception(e) + } +} diff --git a/app/src/main/java/org/yobble/messenger/data/remote/api/AuthApi.kt b/app/src/main/java/org/yobble/messenger/data/remote/api/AuthApi.kt new file mode 100644 index 0000000..724b6d1 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/data/remote/api/AuthApi.kt @@ -0,0 +1,57 @@ +package org.yobble.messenger.data.remote.api + +import org.yobble.messenger.data.remote.dto.* +import retrofit2.Response +import retrofit2.http.* + +interface AuthApi { + + @POST("v1/auth/login/password") + suspend fun login( + @Body request: LoginRequestDto, + @Header("X-Client-Type") clientType: String = "android" + ): Response + + @POST("v1/auth/login/code") + suspend fun requestLoginCode( + @Body request: LoginCodeRequestDto, + @Header("X-Client-Type") clientType: String = "android" + ): Response + + @POST("v1/auth/login/verify_code") + suspend fun verifyCode( + @Body request: VerifyCodeRequestDto, + @Header("X-Client-Type") clientType: String = "android" + ): Response + + @POST("v1/auth/register") + suspend fun register( + @Body request: RegisterRequestDto + ): Response + + @POST("v1/auth/token/refresh") + suspend fun refreshToken( + @Body request: TokenRefreshRequestDto + ): Response + + @POST("v1/auth/password/change") + suspend fun changePassword( + @Body request: ChangePasswordRequestDto + ): Response + + @POST("v1/auth/sessions/update_push_token") + suspend fun updatePushToken( + @Query("fcm_token") fcmToken: String + ): Response + + @GET("v1/auth/sessions/list") + suspend fun getSessionsList(): Response + + @POST("v1/auth/sessions/revoke/{session_id}") + suspend fun revokeSession( + @Path("session_id") sessionId: String + ): Response + + @POST("v1/auth/sessions/revoke_all_except_current") + suspend fun revokeAllExceptCurrent(): Response +} diff --git a/app/src/main/java/org/yobble/messenger/data/remote/api/ChatPrivateApi.kt b/app/src/main/java/org/yobble/messenger/data/remote/api/ChatPrivateApi.kt new file mode 100644 index 0000000..2deead2 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/data/remote/api/ChatPrivateApi.kt @@ -0,0 +1,36 @@ +package org.yobble.messenger.data.remote.api + +import org.yobble.messenger.data.remote.dto.* +import retrofit2.Response +import retrofit2.http.* + +interface ChatPrivateApi { + + @GET("v1/chat/private/list") + suspend fun getChatList( + @Query("offset") offset: Int = 0, + @Query("limit") limit: Int = 20 + ): Response + + @GET("v1/chat/private/history") + suspend fun getChatHistory( + @Query("chat_id") chatId: String, + @Query("before_message_id") beforeMessageId: Int? = null, + @Query("limit") limit: Int = 30 + ): Response + + @POST("v1/chat/private/create") + suspend fun createChat( + @Query("target_user_id") targetUserId: String + ): Response + + @POST("v1/chat/private/send") + suspend fun sendMessage( + @Body request: PrivateMessageSendRequestDto + ): Response + + @HTTP(method = "DELETE", path = "v1/chat/private/delete", hasBody = true) + suspend fun deleteChat( + @Body request: PrivateChatDeleteRequestDto + ): Response +} diff --git a/app/src/main/java/org/yobble/messenger/data/remote/api/FeedApi.kt b/app/src/main/java/org/yobble/messenger/data/remote/api/FeedApi.kt new file mode 100644 index 0000000..389c146 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/data/remote/api/FeedApi.kt @@ -0,0 +1,14 @@ +package org.yobble.messenger.data.remote.api + +import org.yobble.messenger.data.remote.dto.UserSearchResponseDto +import retrofit2.Response +import retrofit2.http.GET +import retrofit2.http.Query + +interface FeedApi { + + @GET("v1/feed/user/search") + suspend fun searchUsers( + @Query("query") query: String + ): Response +} diff --git a/app/src/main/java/org/yobble/messenger/data/remote/api/ProfileApi.kt b/app/src/main/java/org/yobble/messenger/data/remote/api/ProfileApi.kt new file mode 100644 index 0000000..58c9d77 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/data/remote/api/ProfileApi.kt @@ -0,0 +1,21 @@ +package org.yobble.messenger.data.remote.api + +import org.yobble.messenger.data.remote.dto.* +import retrofit2.Response +import retrofit2.http.* + +interface ProfileApi { + + @GET("v1/profile/me") + suspend fun getMyProfile(): Response + + @PUT("v1/profile/edit") + suspend fun editProfile( + @Body request: ProfileUpdateRequestDto + ): Response + + @GET("v1/profile/{user_id}") + suspend fun getUserProfile( + @Path("user_id") userId: String + ): Response +} diff --git a/app/src/main/java/org/yobble/messenger/data/remote/api/StorageApi.kt b/app/src/main/java/org/yobble/messenger/data/remote/api/StorageApi.kt new file mode 100644 index 0000000..53879a9 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/data/remote/api/StorageApi.kt @@ -0,0 +1,17 @@ +package org.yobble.messenger.data.remote.api + +import okhttp3.MultipartBody +import org.yobble.messenger.data.remote.dto.UploadAvatarResponseDto +import retrofit2.Response +import retrofit2.http.Multipart +import retrofit2.http.POST +import retrofit2.http.Part + +interface StorageApi { + + @Multipart + @POST("v1/storage/upload/avatar") + suspend fun uploadAvatar( + @Part file: MultipartBody.Part + ): Response +} diff --git a/app/src/main/java/org/yobble/messenger/data/remote/api/UserApi.kt b/app/src/main/java/org/yobble/messenger/data/remote/api/UserApi.kt new file mode 100644 index 0000000..0b10d18 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/data/remote/api/UserApi.kt @@ -0,0 +1,52 @@ +package org.yobble.messenger.data.remote.api + +import org.yobble.messenger.data.remote.dto.* +import retrofit2.Response +import retrofit2.http.* + +interface UserApi { + + // Contacts + + @GET("v1/user/contact/list") + suspend fun getContacts( + @Query("offset") offset: Int = 0, + @Query("limit") limit: Int = 20 + ): Response + + @GET("v1/user/contact/count") + suspend fun getContactCount(): Response + + @POST("v1/user/contact/add") + suspend fun addContact( + @Body request: ContactCreateRequestDto + ): Response + + @PATCH("v1/user/contact/update") + suspend fun updateContact( + @Body request: ContactUpdateRequestDto + ): Response + + @HTTP(method = "DELETE", path = "v1/user/contact/remove", hasBody = true) + suspend fun removeContact( + @Body request: ContactDeleteRequestDto + ): Response + + // Blacklist + + @GET("v1/user/blacklist/list") + suspend fun getBlacklist( + @Query("offset") offset: Int = 0, + @Query("limit") limit: Int = 20 + ): Response + + @POST("v1/user/blacklist/add") + suspend fun addToBlacklist( + @Body request: BlacklistCreateRequestDto + ): Response + + @HTTP(method = "DELETE", path = "v1/user/blacklist/remove", hasBody = true) + suspend fun removeFromBlacklist( + @Body request: BlacklistDeleteRequestDto + ): Response +} diff --git a/app/src/main/java/org/yobble/messenger/data/remote/dto/AuthRequestDto.kt b/app/src/main/java/org/yobble/messenger/data/remote/dto/AuthRequestDto.kt new file mode 100644 index 0000000..c855118 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/data/remote/dto/AuthRequestDto.kt @@ -0,0 +1,40 @@ +package org.yobble.messenger.data.remote.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class LoginRequestDto( + @SerialName("login") val login: String, + @SerialName("password") val password: String +) + +@Serializable +data class LoginCodeRequestDto( + @SerialName("login") val login: String +) + +@Serializable +data class VerifyCodeRequestDto( + @SerialName("login") val login: String, + @SerialName("otp") val otp: String +) + +@Serializable +data class RegisterRequestDto( + @SerialName("login") val login: String, + @SerialName("password") val password: String, + @SerialName("invite") val invite: String? = null +) + +@Serializable +data class TokenRefreshRequestDto( + @SerialName("access_token") val accessToken: String, + @SerialName("refresh_token") val refreshToken: String? = null +) + +@Serializable +data class ChangePasswordRequestDto( + @SerialName("old_password") val oldPassword: String, + @SerialName("new_password") val newPassword: String +) diff --git a/app/src/main/java/org/yobble/messenger/data/remote/dto/AuthResponseDto.kt b/app/src/main/java/org/yobble/messenger/data/remote/dto/AuthResponseDto.kt new file mode 100644 index 0000000..2ccec49 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/data/remote/dto/AuthResponseDto.kt @@ -0,0 +1,64 @@ +package org.yobble.messenger.data.remote.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class BaseResponseDto( + @SerialName("status") val status: String, + @SerialName("data") val data: MessageDataDto +) + +@Serializable +data class MessageDataDto( + @SerialName("message") val message: String +) + +@Serializable +data class LoginResponseDto( + @SerialName("status") val status: String = "fine", + @SerialName("data") val data: LoginDataDto +) + +@Serializable +data class LoginDataDto( + @SerialName("access_token") val accessToken: String, + @SerialName("refresh_token") val refreshToken: String, + @SerialName("user_id") val userId: String +) + +@Serializable +data class RegisterResponseDto( + @SerialName("status") val status: String, + @SerialName("data") val data: RegisterDataDto +) + +@Serializable +data class RegisterDataDto( + @SerialName("message") val message: String, + @SerialName("user_id") val userId: String +) + +@Serializable +data class TokenRefreshResponseDto( + @SerialName("status") val status: String = "fine", + @SerialName("data") val data: TokenDataDto +) + +@Serializable +data class TokenDataDto( + @SerialName("access_token") val accessToken: String, + @SerialName("refresh_token") val refreshToken: String +) + +@Serializable +data class ErrorResponseDto( + @SerialName("status") val status: String, + @SerialName("errors") val errors: List +) + +@Serializable +data class ErrorItemDto( + @SerialName("field") val field: String, + @SerialName("message") val message: String +) diff --git a/app/src/main/java/org/yobble/messenger/data/remote/dto/ChatPrivateDto.kt b/app/src/main/java/org/yobble/messenger/data/remote/dto/ChatPrivateDto.kt new file mode 100644 index 0000000..e5c6186 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/data/remote/dto/ChatPrivateDto.kt @@ -0,0 +1,110 @@ +package org.yobble.messenger.data.remote.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonObject + +// region Requests + +@Serializable +data class PrivateMessageSendRequestDto( + @SerialName("chat_id") val chatId: String, + @SerialName("content") val content: String? = null, + @SerialName("message_type") val messageType: List = listOf("text") +) + +@Serializable +data class PrivateChatDeleteRequestDto( + @SerialName("chat_id") val chatId: String, + @SerialName("delete_for_both") val deleteForBoth: Boolean = false +) + +// endregion + +// region Responses + +@Serializable +data class PrivateChatListResponseDto( + @SerialName("status") val status: String, + @SerialName("data") val data: PrivateChatListDataDto +) + +@Serializable +data class PrivateChatListDataDto( + @SerialName("items") val items: List, + @SerialName("has_more") val hasMore: Boolean +) + +@Serializable +data class PrivateChatListItemDto( + @SerialName("chat_id") val chatId: String, + @SerialName("chat_type") val chatType: String, + @SerialName("chat_data") val chatData: ProfileByUserIdDataDto? = null, + @SerialName("last_message") val lastMessage: MessageItemDto? = null, + @SerialName("created_at") val createdAt: String, + @SerialName("unread_count") val unreadCount: Int +) + +@Serializable +data class MessageItemDto( + @SerialName("message_id") val messageId: Int, + @SerialName("message_type") val messageType: List, + @SerialName("forward_metadata") val forwardMetadata: MessageForwardDto? = null, + @SerialName("chat_id") val chatId: String, + @SerialName("sender_id") val senderId: String, + @SerialName("sender_data") val senderData: ProfileByUserIdDataDto? = null, + @SerialName("content") val content: String? = null, + @SerialName("media_link") val mediaLink: JsonObject? = null, + @SerialName("is_viewed") val isViewed: Boolean, + @SerialName("viewed_at") val viewedAt: String? = null, + @SerialName("created_at") val createdAt: String, + @SerialName("updated_at") val updatedAt: String? = null +) + +@Serializable +data class MessageForwardDto( + @SerialName("forward_type") val forwardType: String? = null, + @SerialName("forward_sender_id") val forwardSenderId: String? = null, + @SerialName("forward_message_id") val forwardMessageId: Int? = null +) + +@Serializable +data class PrivateChatHistoryResponseDto( + @SerialName("status") val status: String, + @SerialName("data") val data: PrivateChatHistoryDataDto +) + +@Serializable +data class PrivateChatHistoryDataDto( + @SerialName("items") val items: List, + @SerialName("has_more") val hasMore: Boolean +) + +@Serializable +data class PrivateChatCreateResponseDto( + @SerialName("status") val status: String, + @SerialName("data") val data: PrivateChatCreateDataDto +) + +@Serializable +data class PrivateChatCreateDataDto( + @SerialName("chat_id") val chatId: String, + @SerialName("chat_type") val chatType: String, + @SerialName("status") val status: String, + @SerialName("message") val message: String +) + +@Serializable +data class PrivateMessageSendResponseDto( + @SerialName("status") val status: String, + @SerialName("data") val data: PrivateMessageSendDataDto +) + +@Serializable +data class PrivateMessageSendDataDto( + @SerialName("message_id") val messageId: Int, + @SerialName("chat_id") val chatId: String, + @SerialName("created_at") val createdAt: String +) + +// endregion diff --git a/app/src/main/java/org/yobble/messenger/data/remote/dto/ContactDto.kt b/app/src/main/java/org/yobble/messenger/data/remote/dto/ContactDto.kt new file mode 100644 index 0000000..8afd871 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/data/remote/dto/ContactDto.kt @@ -0,0 +1,116 @@ +package org.yobble.messenger.data.remote.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +// region Contact Requests + +@Serializable +data class ContactCreateRequestDto( + @SerialName("user_id") val userId: String? = null, + @SerialName("login") val login: String? = null, + @SerialName("friend_code") val friendCode: String? = null, + @SerialName("custom_name") val customName: String? = null +) + +@Serializable +data class ContactUpdateRequestDto( + @SerialName("user_id") val userId: String, + @SerialName("custom_name") val customName: String? = null +) + +@Serializable +data class ContactDeleteRequestDto( + @SerialName("user_id") val userId: String +) + +// endregion + +// region Contact Responses + +@Serializable +data class ContactListResponseDto( + @SerialName("status") val status: String, + @SerialName("data") val data: ContactListDataDto +) + +@Serializable +data class ContactListDataDto( + @SerialName("items") val items: List, + @SerialName("has_more") val hasMore: Boolean +) + +@Serializable +data class ContactInfoDto( + @SerialName("user_id") val userId: String, + @SerialName("login") val login: String? = null, + @SerialName("full_name") val fullName: String? = null, + @SerialName("custom_name") val customName: String? = null, + @SerialName("friend_code") val friendCode: Boolean = false, + @SerialName("created_at") val createdAt: String, + @SerialName("last_seen_at") val lastSeenAt: String? = null +) + +@Serializable +data class ContactCreateResponseDto( + @SerialName("status") val status: String, + @SerialName("data") val data: ContactInfoDto +) + +@Serializable +data class ContactCountResponseDto( + @SerialName("status") val status: String, + @SerialName("data") val data: ContactCountDataDto +) + +@Serializable +data class ContactCountDataDto( + @SerialName("count") val count: Int +) + +// endregion + +// region Blacklist Requests + +@Serializable +data class BlacklistCreateRequestDto( + @SerialName("user_id") val userId: String? = null, + @SerialName("login") val login: String? = null +) + +@Serializable +data class BlacklistDeleteRequestDto( + @SerialName("user_id") val userId: String +) + +// endregion + +// region Blacklist Responses + +@Serializable +data class BlacklistListResponseDto( + @SerialName("status") val status: String, + @SerialName("data") val data: BlacklistListDataDto +) + +@Serializable +data class BlacklistListDataDto( + @SerialName("items") val items: List, + @SerialName("has_more") val hasMore: Boolean +) + +@Serializable +data class BlacklistInfoDto( + @SerialName("user_id") val userId: String, + @SerialName("login") val login: String? = null, + @SerialName("full_name") val fullName: String? = null, + @SerialName("created_at") val createdAt: String +) + +@Serializable +data class BlacklistCreateResponseDto( + @SerialName("status") val status: String, + @SerialName("data") val data: BlacklistInfoDto +) + +// endregion diff --git a/app/src/main/java/org/yobble/messenger/data/remote/dto/FeedDto.kt b/app/src/main/java/org/yobble/messenger/data/remote/dto/FeedDto.kt new file mode 100644 index 0000000..f4a4995 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/data/remote/dto/FeedDto.kt @@ -0,0 +1,22 @@ +package org.yobble.messenger.data.remote.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonObject + +@Serializable +data class UserSearchResponseDto( + @SerialName("status") val status: String, + @SerialName("data") val data: UserSearchDataDto +) + +@Serializable +data class UserSearchDataDto( + @SerialName("users") val users: List +) + +@Serializable +data class UserSearchResultDto( + @SerialName("user_id") val userId: String, + @SerialName("profile") val profile: ProfileByUserIdDataDto? = null +) diff --git a/app/src/main/java/org/yobble/messenger/data/remote/dto/ProfileDto.kt b/app/src/main/java/org/yobble/messenger/data/remote/dto/ProfileDto.kt new file mode 100644 index 0000000..fd80c06 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/data/remote/dto/ProfileDto.kt @@ -0,0 +1,158 @@ +package org.yobble.messenger.data.remote.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +// region Requests + +@Serializable +data class ProfileUpdateRequestDto( + @SerialName("full_name") val fullName: String? = null, + @SerialName("bio") val bio: String? = null, + @SerialName("profile_permissions") val profilePermissions: ProfilePermissionsRequestDto? = null +) + +@Serializable +data class ProfilePermissionsRequestDto( + @SerialName("is_searchable") val isSearchable: Boolean? = null, + @SerialName("allow_message_forwarding") val allowMessageForwarding: Boolean? = null, + @SerialName("allow_messages_from_non_contacts") val allowMessagesFromNonContacts: Boolean? = null, + @SerialName("show_profile_photo_to_non_contacts") val showProfilePhotoToNonContacts: Boolean? = null, + @SerialName("last_seen_visibility") val lastSeenVisibility: Int? = null, + @SerialName("show_bio_to_non_contacts") val showBioToNonContacts: Boolean? = null, + @SerialName("show_stories_to_non_contacts") val showStoriesToNonContacts: Boolean? = null, + @SerialName("allow_server_chats") val allowServerChats: Boolean? = null, + @SerialName("public_invite_permission") val publicInvitePermission: Int? = null, + @SerialName("group_invite_permission") val groupInvitePermission: Int? = null, + @SerialName("call_permission") val callPermission: Int? = null, + @SerialName("force_auto_delete_messages_in_private") val forceAutoDeleteMessagesInPrivate: Boolean? = null, + @SerialName("max_message_auto_delete_seconds") val maxMessageAutoDeleteSeconds: Int? = null, + @SerialName("auto_delete_after_days") val autoDeleteAfterDays: Int? = null +) + +// endregion + +// region Responses + +@Serializable +data class ProfileResponseDto( + @SerialName("status") val status: String, + @SerialName("data") val data: ProfileDataDto +) + +@Serializable +data class ProfileDataDto( + @SerialName("user_id") val userId: String, + @SerialName("login") val login: String, + @SerialName("full_name") val fullName: String? = null, + @SerialName("bio") val bio: String? = null, + @SerialName("is_verified") val isVerified: Boolean? = false, + @SerialName("rating") val rating: RatingDataDto, + @SerialName("balances") val balances: List, + @SerialName("created_at") val createdAt: String, + @SerialName("avatars") val avatars: AvatarsBlockDto? = null, + @SerialName("profile_permissions") val profilePermissions: MyProfilePermissionsDto +) + +@Serializable +data class ProfileByUserIdResponseDto( + @SerialName("status") val status: String, + @SerialName("data") val data: ProfileByUserIdDataDto +) + +@Serializable +data class ProfileByUserIdDataDto( + @SerialName("user_id") val userId: String, + @SerialName("login") val login: String? = null, + @SerialName("full_name") val fullName: String? = null, + @SerialName("custom_name") val customName: String? = null, + @SerialName("bio") val bio: String? = null, + @SerialName("is_verified") val isVerified: Boolean? = false, + @SerialName("is_system") val isSystem: Boolean? = false, + @SerialName("rating") val rating: RatingDataDto, + @SerialName("last_seen") val lastSeen: Int? = null, + @SerialName("created_at") val createdAt: String, + @SerialName("avatars") val avatars: AvatarsBlockDto? = null, + @SerialName("permissions") val permissions: PermissionsResponseDto, + @SerialName("profile_permissions") val profilePermissions: UserProfilePermissionsDto, + @SerialName("relationship") val relationship: RelationshipStatusDto +) + +// endregion + +// region Shared models + +@Serializable +data class RatingDataDto( + @SerialName("rating") val rating: Double? = null, + @SerialName("status") val status: String = "unavailable" +) + +@Serializable +data class WalletBalanceDto( + @SerialName("currency") val currency: String, + @SerialName("balance") val balance: String, + @SerialName("display_balance") val displayBalance: Double? = null +) + +@Serializable +data class AvatarsBlockDto( + @SerialName("current") val current: AvatarItemDto? = null, + @SerialName("history") val history: List = emptyList() +) + +@Serializable +data class AvatarItemDto( + @SerialName("file_id") val fileId: String? = null, + @SerialName("mime") val mime: String? = null, + @SerialName("size") val size: Int? = null, + @SerialName("width") val width: Int? = null, + @SerialName("height") val height: Int? = null, + @SerialName("created_at") val createdAt: String? = null +) + +@Serializable +data class PermissionsResponseDto( + @SerialName("you_can_send_message") val youCanSendMessage: Boolean, + @SerialName("you_can_public_invite_permission") val youCanPublicInvite: Boolean, + @SerialName("you_can_group_invite_permission") val youCanGroupInvite: Boolean, + @SerialName("you_can_call_permission") val youCanCall: Boolean +) + +@Serializable +data class RelationshipStatusDto( + @SerialName("is_target_in_contacts_of_current_user") val isTargetInContacts: Boolean, + @SerialName("is_current_user_in_contacts_of_target") val isCurrentInTargetContacts: Boolean, + @SerialName("is_target_user_blocked_by_current_user") val isTargetBlocked: Boolean, + @SerialName("is_current_user_in_blacklist_of_target") val isCurrentInBlacklist: Boolean +) + +@Serializable +data class MyProfilePermissionsDto( + @SerialName("is_searchable") val isSearchable: Boolean, + @SerialName("allow_message_forwarding") val allowMessageForwarding: Boolean, + @SerialName("allow_messages_from_non_contacts") val allowMessagesFromNonContacts: Boolean, + @SerialName("show_profile_photo_to_non_contacts") val showProfilePhotoToNonContacts: Boolean, + @SerialName("last_seen_visibility") val lastSeenVisibility: Int, + @SerialName("show_bio_to_non_contacts") val showBioToNonContacts: Boolean, + @SerialName("show_stories_to_non_contacts") val showStoriesToNonContacts: Boolean, + @SerialName("allow_server_chats") val allowServerChats: Boolean, + @SerialName("public_invite_permission") val publicInvitePermission: Int, + @SerialName("group_invite_permission") val groupInvitePermission: Int, + @SerialName("call_permission") val callPermission: Int, + @SerialName("force_auto_delete_messages_in_private") val forceAutoDeleteMessagesInPrivate: Boolean, + @SerialName("max_message_auto_delete_seconds") val maxMessageAutoDeleteSeconds: Int? = null, + @SerialName("auto_delete_after_days") val autoDeleteAfterDays: Int? = null +) + +@Serializable +data class UserProfilePermissionsDto( + @SerialName("is_searchable") val isSearchable: Boolean? = null, + @SerialName("allow_message_forwarding") val allowMessageForwarding: Boolean, + @SerialName("allow_messages_from_non_contacts") val allowMessagesFromNonContacts: Boolean, + @SerialName("allow_server_chats") val allowServerChats: Boolean, + @SerialName("force_auto_delete_messages_in_private") val forceAutoDeleteMessagesInPrivate: Boolean, + @SerialName("max_message_auto_delete_seconds") val maxMessageAutoDeleteSeconds: Int? = null +) + +// endregion diff --git a/app/src/main/java/org/yobble/messenger/data/remote/dto/SessionDto.kt b/app/src/main/java/org/yobble/messenger/data/remote/dto/SessionDto.kt new file mode 100644 index 0000000..81180fc --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/data/remote/dto/SessionDto.kt @@ -0,0 +1,27 @@ +package org.yobble.messenger.data.remote.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class SessionsListResponseDto( + @SerialName("status") val status: String, + @SerialName("data") val data: SessionsListDataDto +) + +@Serializable +data class SessionsListDataDto( + @SerialName("sessions") val sessions: List +) + +@Serializable +data class UserSessionItemDto( + @SerialName("id") val id: String, + @SerialName("ip_address") val ipAddress: String? = null, + @SerialName("user_agent") val userAgent: String? = null, + @SerialName("client_type") val clientType: String, + @SerialName("is_active") val isActive: Boolean, + @SerialName("created_at") val createdAt: String, + @SerialName("last_refresh_at") val lastRefreshAt: String, + @SerialName("is_current") val isCurrent: Boolean +) diff --git a/app/src/main/java/org/yobble/messenger/data/remote/dto/StorageDto.kt b/app/src/main/java/org/yobble/messenger/data/remote/dto/StorageDto.kt new file mode 100644 index 0000000..d08e16a --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/data/remote/dto/StorageDto.kt @@ -0,0 +1,15 @@ +package org.yobble.messenger.data.remote.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class UploadAvatarResponseDto( + @SerialName("status") val status: String, + @SerialName("data") val data: UploadAvatarDataDto +) + +@Serializable +data class UploadAvatarDataDto( + @SerialName("file_id") val fileId: String +) diff --git a/app/src/main/java/org/yobble/messenger/data/remote/fcm/YobbleFcmService.kt b/app/src/main/java/org/yobble/messenger/data/remote/fcm/YobbleFcmService.kt new file mode 100644 index 0000000..94fb46a --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/data/remote/fcm/YobbleFcmService.kt @@ -0,0 +1,83 @@ +package org.yobble.messenger.data.remote.fcm + +import android.app.PendingIntent +import android.content.Intent +import androidx.core.app.NotificationCompat +import androidx.core.app.NotificationManagerCompat +import com.google.firebase.messaging.FirebaseMessagingService +import com.google.firebase.messaging.RemoteMessage +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch +import org.yobble.messenger.MainActivity +import org.yobble.messenger.R +import org.yobble.messenger.YobbleApp +import org.yobble.messenger.data.local.PushTokenManager +import javax.inject.Inject + +@AndroidEntryPoint +class YobbleFcmService : FirebaseMessagingService() { + + @Inject + lateinit var pushTokenManager: PushTokenManager + + private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO) + + override fun onNewToken(token: String) { + super.onNewToken(token) + scope.launch { + pushTokenManager.registerPushToken() + } + } + + override fun onMessageReceived(message: RemoteMessage) { + super.onMessageReceived(message) + + val title = message.notification?.title + ?: message.data["title"] + ?: "Yobble" + val body = message.notification?.body + ?: message.data["body"] + ?: return + + showNotification(title, body, message.data) + } + + private fun showNotification( + title: String, + body: String, + data: Map + ) { + val intent = Intent(this, MainActivity::class.java).apply { + flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP + data.forEach { (key, value) -> putExtra(key, value) } + } + + val pendingIntent = PendingIntent.getActivity( + this, + System.currentTimeMillis().toInt(), + intent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE + ) + + val channelId = data["channel"] ?: YobbleApp.CHANNEL_MESSAGES + + val notification = NotificationCompat.Builder(this, channelId) + .setSmallIcon(R.drawable.ic_launcher_foreground) + .setContentTitle(title) + .setContentText(body) + .setAutoCancel(true) + .setContentIntent(pendingIntent) + .setPriority(NotificationCompat.PRIORITY_HIGH) + .build() + + try { + NotificationManagerCompat.from(this) + .notify(System.currentTimeMillis().toInt(), notification) + } catch (_: SecurityException) { + // POST_NOTIFICATIONS permission not granted + } + } +} diff --git a/app/src/main/java/org/yobble/messenger/data/remote/interceptor/AuthInterceptor.kt b/app/src/main/java/org/yobble/messenger/data/remote/interceptor/AuthInterceptor.kt new file mode 100644 index 0000000..2ed7d60 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/data/remote/interceptor/AuthInterceptor.kt @@ -0,0 +1,27 @@ +package org.yobble.messenger.data.remote.interceptor + +import okhttp3.Interceptor +import okhttp3.Response +import org.yobble.messenger.BuildConfig +import org.yobble.messenger.data.local.SessionManager +import javax.inject.Inject + +class AuthInterceptor @Inject constructor( + private val sessionManager: SessionManager +) : Interceptor { + override fun intercept(chain: Interceptor.Chain): Response { + val request = chain.request() + val token = sessionManager.accessToken + + val newRequest = request.newBuilder() + .header("User-Agent", BuildConfig.USER_AGENT) + .apply { + if (token != null) { + header("Authorization", "Bearer $token") + } + } + .build() + + return chain.proceed(newRequest) + } +} diff --git a/app/src/main/java/org/yobble/messenger/data/remote/interceptor/TokenAuthenticator.kt b/app/src/main/java/org/yobble/messenger/data/remote/interceptor/TokenAuthenticator.kt new file mode 100644 index 0000000..f0b047e --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/data/remote/interceptor/TokenAuthenticator.kt @@ -0,0 +1,64 @@ +package org.yobble.messenger.data.remote.interceptor + +import kotlinx.coroutines.runBlocking +import okhttp3.Authenticator +import okhttp3.Request +import okhttp3.Response +import okhttp3.Route +import org.yobble.messenger.data.local.SessionManager +import org.yobble.messenger.data.remote.api.AuthApi +import org.yobble.messenger.data.remote.dto.TokenRefreshRequestDto +import javax.inject.Inject +import javax.inject.Provider + +class TokenAuthenticator @Inject constructor( + private val sessionManager: SessionManager, + private val authApiProvider: Provider +) : Authenticator { + + override fun authenticate(route: Route?, response: Response): Request? { + val accessToken = sessionManager.accessToken ?: return null + val refreshToken = sessionManager.refreshToken ?: return null + + synchronized(this) { + val currentToken = sessionManager.accessToken + if (currentToken != null && currentToken != accessToken) { + return response.request.newBuilder() + .header("Authorization", "Bearer $currentToken") + .build() + } + + val newTokens = runBlocking { + try { + val refreshResponse = authApiProvider.get().refreshToken( + TokenRefreshRequestDto( + accessToken = accessToken, + refreshToken = refreshToken + ) + ) + if (refreshResponse.isSuccessful) { + refreshResponse.body()?.data + } else { + null + } + } catch (e: Exception) { + null + } + } + + return if (newTokens != null) { + sessionManager.saveSession( + accessToken = newTokens.accessToken, + refreshToken = newTokens.refreshToken, + userId = sessionManager.userId ?: "" + ) + response.request.newBuilder() + .header("Authorization", "Bearer ${newTokens.accessToken}") + .build() + } else { + sessionManager.clearSession() + null + } + } + } +} diff --git a/app/src/main/java/org/yobble/messenger/data/remote/socket/SocketManager.kt b/app/src/main/java/org/yobble/messenger/data/remote/socket/SocketManager.kt new file mode 100644 index 0000000..fc1d29e --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/data/remote/socket/SocketManager.kt @@ -0,0 +1,171 @@ +package org.yobble.messenger.data.remote.socket + +import android.util.Log +import io.socket.client.IO +import io.socket.client.Socket +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.asSharedFlow +import okhttp3.OkHttpClient +import org.json.JSONObject +import org.yobble.messenger.BuildConfig +import org.yobble.messenger.data.local.SessionManager +import javax.inject.Inject +import javax.inject.Singleton + +sealed class SocketEvent { + data class NewMessage(val data: JSONObject) : SocketEvent() + data class Connected(val data: JSONObject?) : SocketEvent() + data object Disconnected : SocketEvent() +} + +@Singleton +class SocketManager @Inject constructor( + private val sessionManager: SessionManager +) { + private var socket: Socket? = null + + private val _events = MutableSharedFlow(extraBufferCapacity = 64) + val events: SharedFlow = _events.asSharedFlow() + + val isConnected: Boolean + get() = socket?.connected() == true + + fun connect() { + if (socket?.connected() == true) { + Log.d(TAG, "Already connected, skipping") + return + } + + val token = sessionManager.accessToken + if (token == null) { + Log.w(TAG, "No access token, cannot connect socket") + return + } + + // Disconnect old socket if exists + socket?.let { + Log.d(TAG, "Cleaning up old socket") + it.disconnect() + it.off() + socket = null + } + + try { + val baseUrl = BuildConfig.BASE_URL.trimEnd('/') + Log.i(TAG, "Connecting to: $baseUrl") + + // OkHttpClient for socket.io (no auth interceptor — we pass token manually) + val okHttpClient = OkHttpClient.Builder().build() + IO.setDefaultOkHttpCallFactory(okHttpClient) + IO.setDefaultOkHttpWebSocketFactory(okHttpClient) + + val options = IO.Options().apply { + // Auth map (socket.io v4 handshake) + auth = mapOf("token" to token) + // Also pass token as query param (like iOS connectParams) + query = "token=$token" + // Extra headers (like iOS) + extraHeaders = mapOf( + "Authorization" to listOf("Bearer $token"), + "User-Agent" to listOf(BuildConfig.USER_AGENT) + ) + path = "/socket.io/" + transports = arrayOf("websocket", "polling") + reconnection = true + reconnectionAttempts = Int.MAX_VALUE + reconnectionDelay = 2000 + reconnectionDelayMax = 5000 + timeout = 20000 + } + + socket = IO.socket(baseUrl, options).apply { + // Debug: log ALL incoming events + onAnyIncoming { args -> + Log.d(TAG, "<<< event: ${args.joinToString()}") + } + + on(Socket.EVENT_CONNECT) { + Log.i(TAG, "===== CONNECTED ===== SID: ${id()}") + val data = if (it.isNotEmpty()) it[0] as? JSONObject else null + _events.tryEmit(SocketEvent.Connected(data)) + } + + on(Socket.EVENT_DISCONNECT) { args -> + val reason = if (args.isNotEmpty()) args[0] else "unknown" + Log.w(TAG, "===== DISCONNECTED ===== reason: $reason") + _events.tryEmit(SocketEvent.Disconnected) + } + + on(Socket.EVENT_CONNECT_ERROR) { args -> + val error = if (args.isNotEmpty()) args[0] else "Unknown" + Log.e(TAG, "===== CONNECT ERROR ===== $error") + if (error is Exception) { + Log.e(TAG, "Error details:", error) + } + } + + // Server confirms connection + on("connected") { args -> + Log.i(TAG, "Server 'connected' event: ${args.firstOrNull()}") + } + + // Heartbeat: server responds with "pong" via "message" event + on("message") { args -> + Log.d(TAG, "message event: ${args.firstOrNull()}") + } + + // Private chat new message (matches iOS: chat_private:new_message) + on("chat_private:new_message") { args -> + Log.i(TAG, "chat_private:new_message, args: ${args.size}") + handleNewMessage(args) + } + + // Also listen to chat:new_message (from web example) + on("chat:new_message") { args -> + Log.i(TAG, "chat:new_message, args: ${args.size}") + handleNewMessage(args) + } + + on("achievement:received") { args -> + Log.i(TAG, "achievement:received: ${args.firstOrNull()}") + } + + on("achievement:progress") { args -> + Log.i(TAG, "achievement:progress: ${args.firstOrNull()}") + } + + Log.d(TAG, "Calling socket.connect()...") + connect() + Log.d(TAG, "socket.connect() called, connected=${connected()}") + } + } catch (e: Exception) { + Log.e(TAG, "Socket connection failed", e) + } + } + + private fun handleNewMessage(args: Array) { + if (args.isEmpty()) return + val raw = args[0] + val data = when (raw) { + is JSONObject -> raw + is String -> try { JSONObject(raw) } catch (_: Exception) { null } + else -> null + } + if (data != null) { + Log.i(TAG, "New message data: $data") + _events.tryEmit(SocketEvent.NewMessage(data)) + } + } + + fun disconnect() { + Log.d(TAG, "Disconnecting socket") + socket?.disconnect() + socket?.off() + socket = null + } + + companion object { + private const val TAG = "SocketManager" + } +} diff --git a/app/src/main/java/org/yobble/messenger/data/repository/AuthRepositoryImpl.kt b/app/src/main/java/org/yobble/messenger/data/repository/AuthRepositoryImpl.kt new file mode 100644 index 0000000..8821ab0 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/data/repository/AuthRepositoryImpl.kt @@ -0,0 +1,99 @@ +package org.yobble.messenger.data.repository + +import kotlinx.serialization.json.Json +import org.yobble.messenger.data.local.PushTokenManager +import org.yobble.messenger.data.local.SessionManager +import org.yobble.messenger.data.remote.NetworkResult +import org.yobble.messenger.data.remote.api.AuthApi +import org.yobble.messenger.data.remote.dto.* +import org.yobble.messenger.data.remote.safeApiCall +import org.yobble.messenger.domain.repository.AuthRepository +import javax.inject.Inject + +class AuthRepositoryImpl @Inject constructor( + private val authApi: AuthApi, + private val sessionManager: SessionManager, + private val pushTokenManager: PushTokenManager, + private val json: Json +) : AuthRepository { + + override suspend fun login(login: String, password: String): NetworkResult { + val result = safeApiCall(json) { + authApi.login(LoginRequestDto(login, password)) + } + if (result is NetworkResult.Success) { + sessionManager.saveSession( + accessToken = result.data.data.accessToken, + refreshToken = result.data.data.refreshToken, + userId = result.data.data.userId + ) + pushTokenManager.registerPushToken() + } + return result + } + + override suspend fun requestLoginCode(login: String): NetworkResult { + return safeApiCall(json) { + authApi.requestLoginCode(LoginCodeRequestDto(login)) + } + } + + override suspend fun verifyCode(login: String, otp: String): NetworkResult { + val result = safeApiCall(json) { + authApi.verifyCode(VerifyCodeRequestDto(login, otp)) + } + if (result is NetworkResult.Success) { + sessionManager.saveSession( + accessToken = result.data.data.accessToken, + refreshToken = result.data.data.refreshToken, + userId = result.data.data.userId + ) + pushTokenManager.registerPushToken() + } + return result + } + + override suspend fun register(login: String, password: String, invite: String?): NetworkResult { + return safeApiCall(json) { + authApi.register(RegisterRequestDto(login, password, invite)) + } + } + + override suspend fun updatePushToken(fcmToken: String): NetworkResult { + return safeApiCall(json) { + authApi.updatePushToken(fcmToken) + } + } + + override suspend fun changePassword(oldPassword: String, newPassword: String): NetworkResult { + return safeApiCall(json) { + authApi.changePassword(ChangePasswordRequestDto(oldPassword, newPassword)) + } + } + + override suspend fun getSessionsList(): NetworkResult { + return safeApiCall(json) { + authApi.getSessionsList() + } + } + + override suspend fun revokeSession(sessionId: String): NetworkResult { + return safeApiCall(json) { + authApi.revokeSession(sessionId) + } + } + + override suspend fun revokeAllExceptCurrent(): NetworkResult { + return safeApiCall(json) { + authApi.revokeAllExceptCurrent() + } + } + + override suspend fun isLoggedIn(): Boolean { + return sessionManager.isLoggedIn + } + + override fun logout() { + sessionManager.clearSession() + } +} diff --git a/app/src/main/java/org/yobble/messenger/data/repository/ChatRepositoryImpl.kt b/app/src/main/java/org/yobble/messenger/data/repository/ChatRepositoryImpl.kt new file mode 100644 index 0000000..b09390a --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/data/repository/ChatRepositoryImpl.kt @@ -0,0 +1,39 @@ +package org.yobble.messenger.data.repository + +import kotlinx.serialization.json.Json +import org.yobble.messenger.data.remote.NetworkResult +import org.yobble.messenger.data.remote.api.ChatPrivateApi +import org.yobble.messenger.data.remote.dto.* +import org.yobble.messenger.data.remote.safeApiCall +import org.yobble.messenger.domain.repository.ChatRepository +import javax.inject.Inject + +class ChatRepositoryImpl @Inject constructor( + private val chatApi: ChatPrivateApi, + private val json: Json +) : ChatRepository { + + override suspend fun getChatList(offset: Int, limit: Int): NetworkResult { + return safeApiCall(json) { chatApi.getChatList(offset, limit) } + } + + override suspend fun getChatHistory(chatId: String, beforeMessageId: Int?, limit: Int): NetworkResult { + return safeApiCall(json) { chatApi.getChatHistory(chatId, beforeMessageId, limit) } + } + + override suspend fun createChat(targetUserId: String): NetworkResult { + return safeApiCall(json) { chatApi.createChat(targetUserId) } + } + + override suspend fun sendMessage(chatId: String, content: String): NetworkResult { + return safeApiCall(json) { + chatApi.sendMessage(PrivateMessageSendRequestDto(chatId = chatId, content = content)) + } + } + + override suspend fun deleteChat(chatId: String, deleteForBoth: Boolean): NetworkResult { + return safeApiCall(json) { + chatApi.deleteChat(PrivateChatDeleteRequestDto(chatId = chatId, deleteForBoth = deleteForBoth)) + } + } +} diff --git a/app/src/main/java/org/yobble/messenger/data/repository/FeedRepositoryImpl.kt b/app/src/main/java/org/yobble/messenger/data/repository/FeedRepositoryImpl.kt new file mode 100644 index 0000000..3de81c9 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/data/repository/FeedRepositoryImpl.kt @@ -0,0 +1,19 @@ +package org.yobble.messenger.data.repository + +import kotlinx.serialization.json.Json +import org.yobble.messenger.data.remote.NetworkResult +import org.yobble.messenger.data.remote.api.FeedApi +import org.yobble.messenger.data.remote.dto.UserSearchResponseDto +import org.yobble.messenger.data.remote.safeApiCall +import org.yobble.messenger.domain.repository.FeedRepository +import javax.inject.Inject + +class FeedRepositoryImpl @Inject constructor( + private val feedApi: FeedApi, + private val json: Json +) : FeedRepository { + + override suspend fun searchUsers(query: String): NetworkResult { + return safeApiCall(json) { feedApi.searchUsers(query) } + } +} diff --git a/app/src/main/java/org/yobble/messenger/data/repository/ProfileRepositoryImpl.kt b/app/src/main/java/org/yobble/messenger/data/repository/ProfileRepositoryImpl.kt new file mode 100644 index 0000000..4c63624 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/data/repository/ProfileRepositoryImpl.kt @@ -0,0 +1,44 @@ +package org.yobble.messenger.data.repository + +import kotlinx.serialization.json.Json +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.MultipartBody +import okhttp3.RequestBody.Companion.asRequestBody +import org.yobble.messenger.data.remote.NetworkResult +import org.yobble.messenger.data.remote.api.ProfileApi +import org.yobble.messenger.data.remote.api.StorageApi +import org.yobble.messenger.data.remote.dto.BaseResponseDto +import org.yobble.messenger.data.remote.dto.ProfileByUserIdResponseDto +import org.yobble.messenger.data.remote.dto.ProfileResponseDto +import org.yobble.messenger.data.remote.dto.ProfileUpdateRequestDto +import org.yobble.messenger.data.remote.dto.UploadAvatarResponseDto +import org.yobble.messenger.data.remote.safeApiCall +import org.yobble.messenger.domain.repository.ProfileRepository +import java.io.File +import javax.inject.Inject + +class ProfileRepositoryImpl @Inject constructor( + private val profileApi: ProfileApi, + private val storageApi: StorageApi, + private val json: Json +) : ProfileRepository { + + override suspend fun getMyProfile(): NetworkResult { + return safeApiCall(json) { profileApi.getMyProfile() } + } + + override suspend fun editProfile(request: ProfileUpdateRequestDto): NetworkResult { + return safeApiCall(json) { profileApi.editProfile(request) } + } + + override suspend fun getUserProfile(userId: String): NetworkResult { + return safeApiCall(json) { profileApi.getUserProfile(userId) } + } + + override suspend fun uploadAvatar(file: File, mimeType: String): NetworkResult { + val mediaType = mimeType.toMediaType() + val requestBody = file.asRequestBody(mediaType) + val part = MultipartBody.Part.createFormData("file", file.name, requestBody) + return safeApiCall(json) { storageApi.uploadAvatar(part) } + } +} diff --git a/app/src/main/java/org/yobble/messenger/data/repository/UserRepositoryImpl.kt b/app/src/main/java/org/yobble/messenger/data/repository/UserRepositoryImpl.kt new file mode 100644 index 0000000..24847c0 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/data/repository/UserRepositoryImpl.kt @@ -0,0 +1,47 @@ +package org.yobble.messenger.data.repository + +import kotlinx.serialization.json.Json +import org.yobble.messenger.data.remote.NetworkResult +import org.yobble.messenger.data.remote.api.UserApi +import org.yobble.messenger.data.remote.dto.* +import org.yobble.messenger.data.remote.safeApiCall +import org.yobble.messenger.domain.repository.UserRepository +import javax.inject.Inject + +class UserRepositoryImpl @Inject constructor( + private val userApi: UserApi, + private val json: Json +) : UserRepository { + + override suspend fun getContacts(offset: Int, limit: Int): NetworkResult { + return safeApiCall(json) { userApi.getContacts(offset, limit) } + } + + override suspend fun getContactCount(): NetworkResult { + return safeApiCall(json) { userApi.getContactCount() } + } + + override suspend fun addContact(request: ContactCreateRequestDto): NetworkResult { + return safeApiCall(json) { userApi.addContact(request) } + } + + override suspend fun updateContact(request: ContactUpdateRequestDto): NetworkResult { + return safeApiCall(json) { userApi.updateContact(request) } + } + + override suspend fun removeContact(userId: String): NetworkResult { + return safeApiCall(json) { userApi.removeContact(ContactDeleteRequestDto(userId)) } + } + + override suspend fun getBlacklist(offset: Int, limit: Int): NetworkResult { + return safeApiCall(json) { userApi.getBlacklist(offset, limit) } + } + + override suspend fun addToBlacklist(request: BlacklistCreateRequestDto): NetworkResult { + return safeApiCall(json) { userApi.addToBlacklist(request) } + } + + override suspend fun removeFromBlacklist(userId: String): NetworkResult { + return safeApiCall(json) { userApi.removeFromBlacklist(BlacklistDeleteRequestDto(userId)) } + } +} diff --git a/app/src/main/java/org/yobble/messenger/di/NetworkModule.kt b/app/src/main/java/org/yobble/messenger/di/NetworkModule.kt new file mode 100644 index 0000000..e554a61 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/di/NetworkModule.kt @@ -0,0 +1,101 @@ +package org.yobble.messenger.di + +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import kotlinx.serialization.json.Json +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor +import org.yobble.messenger.BuildConfig +import org.yobble.messenger.data.remote.api.AuthApi +import org.yobble.messenger.data.remote.api.ChatPrivateApi +import org.yobble.messenger.data.remote.api.FeedApi +import org.yobble.messenger.data.remote.api.ProfileApi +import org.yobble.messenger.data.remote.api.StorageApi +import org.yobble.messenger.data.remote.api.UserApi +import org.yobble.messenger.data.remote.interceptor.AuthInterceptor +import org.yobble.messenger.data.remote.interceptor.TokenAuthenticator +import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory +import retrofit2.Retrofit +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object NetworkModule { + + @Provides + @Singleton + fun provideJson(): Json = Json { + ignoreUnknownKeys = true + coerceInputValues = true + isLenient = true + encodeDefaults = true + explicitNulls = false + } + + @Provides + @Singleton + fun provideOkHttpClient( + authInterceptor: AuthInterceptor, + tokenAuthenticator: TokenAuthenticator + ): OkHttpClient { + return OkHttpClient.Builder() + .addInterceptor(authInterceptor) + .addInterceptor( + HttpLoggingInterceptor().apply { + level = HttpLoggingInterceptor.Level.BODY + } + ) + .authenticator(tokenAuthenticator) + .build() + } + + @Provides + @Singleton + fun provideRetrofit(okHttpClient: OkHttpClient, json: Json): Retrofit { + val contentType = "application/json".toMediaType() + return Retrofit.Builder() + .baseUrl(BuildConfig.BASE_URL) + .client(okHttpClient) + .addConverterFactory(json.asConverterFactory(contentType)) + .build() + } + + @Provides + @Singleton + fun provideAuthApi(retrofit: Retrofit): AuthApi { + return retrofit.create(AuthApi::class.java) + } + + @Provides + @Singleton + fun provideProfileApi(retrofit: Retrofit): ProfileApi { + return retrofit.create(ProfileApi::class.java) + } + + @Provides + @Singleton + fun provideChatPrivateApi(retrofit: Retrofit): ChatPrivateApi { + return retrofit.create(ChatPrivateApi::class.java) + } + + @Provides + @Singleton + fun provideStorageApi(retrofit: Retrofit): StorageApi { + return retrofit.create(StorageApi::class.java) + } + + @Provides + @Singleton + fun provideUserApi(retrofit: Retrofit): UserApi { + return retrofit.create(UserApi::class.java) + } + + @Provides + @Singleton + fun provideFeedApi(retrofit: Retrofit): FeedApi { + return retrofit.create(FeedApi::class.java) + } +} diff --git a/app/src/main/java/org/yobble/messenger/di/RepositoryModule.kt b/app/src/main/java/org/yobble/messenger/di/RepositoryModule.kt new file mode 100644 index 0000000..964f3a0 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/di/RepositoryModule.kt @@ -0,0 +1,42 @@ +package org.yobble.messenger.di + +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import org.yobble.messenger.data.repository.AuthRepositoryImpl +import org.yobble.messenger.data.repository.ChatRepositoryImpl +import org.yobble.messenger.data.repository.FeedRepositoryImpl +import org.yobble.messenger.data.repository.ProfileRepositoryImpl +import org.yobble.messenger.data.repository.UserRepositoryImpl +import org.yobble.messenger.domain.repository.AuthRepository +import org.yobble.messenger.domain.repository.ChatRepository +import org.yobble.messenger.domain.repository.FeedRepository +import org.yobble.messenger.domain.repository.ProfileRepository +import org.yobble.messenger.domain.repository.UserRepository +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +abstract class RepositoryModule { + + @Binds + @Singleton + abstract fun bindAuthRepository(impl: AuthRepositoryImpl): AuthRepository + + @Binds + @Singleton + abstract fun bindProfileRepository(impl: ProfileRepositoryImpl): ProfileRepository + + @Binds + @Singleton + abstract fun bindChatRepository(impl: ChatRepositoryImpl): ChatRepository + + @Binds + @Singleton + abstract fun bindUserRepository(impl: UserRepositoryImpl): UserRepository + + @Binds + @Singleton + abstract fun bindFeedRepository(impl: FeedRepositoryImpl): FeedRepository +} diff --git a/app/src/main/java/org/yobble/messenger/domain/repository/AuthRepository.kt b/app/src/main/java/org/yobble/messenger/domain/repository/AuthRepository.kt new file mode 100644 index 0000000..cbd821a --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/domain/repository/AuthRepository.kt @@ -0,0 +1,21 @@ +package org.yobble.messenger.domain.repository + +import org.yobble.messenger.data.remote.NetworkResult +import org.yobble.messenger.data.remote.dto.BaseResponseDto +import org.yobble.messenger.data.remote.dto.LoginResponseDto +import org.yobble.messenger.data.remote.dto.RegisterResponseDto +import org.yobble.messenger.data.remote.dto.SessionsListResponseDto + +interface AuthRepository { + suspend fun login(login: String, password: String): NetworkResult + suspend fun requestLoginCode(login: String): NetworkResult + suspend fun verifyCode(login: String, otp: String): NetworkResult + suspend fun register(login: String, password: String, invite: String? = null): NetworkResult + suspend fun updatePushToken(fcmToken: String): NetworkResult + suspend fun changePassword(oldPassword: String, newPassword: String): NetworkResult + suspend fun getSessionsList(): NetworkResult + suspend fun revokeSession(sessionId: String): NetworkResult + suspend fun revokeAllExceptCurrent(): NetworkResult + suspend fun isLoggedIn(): Boolean + fun logout() +} diff --git a/app/src/main/java/org/yobble/messenger/domain/repository/ChatRepository.kt b/app/src/main/java/org/yobble/messenger/domain/repository/ChatRepository.kt new file mode 100644 index 0000000..5c04e89 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/domain/repository/ChatRepository.kt @@ -0,0 +1,12 @@ +package org.yobble.messenger.domain.repository + +import org.yobble.messenger.data.remote.NetworkResult +import org.yobble.messenger.data.remote.dto.* + +interface ChatRepository { + suspend fun getChatList(offset: Int = 0, limit: Int = 20): NetworkResult + suspend fun getChatHistory(chatId: String, beforeMessageId: Int? = null, limit: Int = 30): NetworkResult + suspend fun createChat(targetUserId: String): NetworkResult + suspend fun sendMessage(chatId: String, content: String): NetworkResult + suspend fun deleteChat(chatId: String, deleteForBoth: Boolean = false): NetworkResult +} diff --git a/app/src/main/java/org/yobble/messenger/domain/repository/FeedRepository.kt b/app/src/main/java/org/yobble/messenger/domain/repository/FeedRepository.kt new file mode 100644 index 0000000..40317f3 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/domain/repository/FeedRepository.kt @@ -0,0 +1,8 @@ +package org.yobble.messenger.domain.repository + +import org.yobble.messenger.data.remote.NetworkResult +import org.yobble.messenger.data.remote.dto.UserSearchResponseDto + +interface FeedRepository { + suspend fun searchUsers(query: String): NetworkResult +} diff --git a/app/src/main/java/org/yobble/messenger/domain/repository/ProfileRepository.kt b/app/src/main/java/org/yobble/messenger/domain/repository/ProfileRepository.kt new file mode 100644 index 0000000..300a1d5 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/domain/repository/ProfileRepository.kt @@ -0,0 +1,16 @@ +package org.yobble.messenger.domain.repository + +import org.yobble.messenger.data.remote.NetworkResult +import org.yobble.messenger.data.remote.dto.BaseResponseDto +import org.yobble.messenger.data.remote.dto.ProfileByUserIdResponseDto +import org.yobble.messenger.data.remote.dto.ProfileResponseDto +import org.yobble.messenger.data.remote.dto.ProfileUpdateRequestDto +import org.yobble.messenger.data.remote.dto.UploadAvatarResponseDto +import java.io.File + +interface ProfileRepository { + suspend fun getMyProfile(): NetworkResult + suspend fun editProfile(request: ProfileUpdateRequestDto): NetworkResult + suspend fun getUserProfile(userId: String): NetworkResult + suspend fun uploadAvatar(file: File, mimeType: String): NetworkResult +} diff --git a/app/src/main/java/org/yobble/messenger/domain/repository/UserRepository.kt b/app/src/main/java/org/yobble/messenger/domain/repository/UserRepository.kt new file mode 100644 index 0000000..571ad87 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/domain/repository/UserRepository.kt @@ -0,0 +1,18 @@ +package org.yobble.messenger.domain.repository + +import org.yobble.messenger.data.remote.NetworkResult +import org.yobble.messenger.data.remote.dto.* + +interface UserRepository { + // Contacts + suspend fun getContacts(offset: Int = 0, limit: Int = 20): NetworkResult + suspend fun getContactCount(): NetworkResult + suspend fun addContact(request: ContactCreateRequestDto): NetworkResult + suspend fun updateContact(request: ContactUpdateRequestDto): NetworkResult + suspend fun removeContact(userId: String): NetworkResult + + // Blacklist + suspend fun getBlacklist(offset: Int = 0, limit: Int = 20): NetworkResult + suspend fun addToBlacklist(request: BlacklistCreateRequestDto): NetworkResult + suspend fun removeFromBlacklist(userId: String): NetworkResult +} diff --git a/app/src/main/java/org/yobble/messenger/domain/validation/AuthValidator.kt b/app/src/main/java/org/yobble/messenger/domain/validation/AuthValidator.kt new file mode 100644 index 0000000..849a2ed --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/domain/validation/AuthValidator.kt @@ -0,0 +1,45 @@ +package org.yobble.messenger.domain.validation + +object AuthValidator { + + fun validateLogin(login: String): ValidationResult { + return when { + login.isBlank() -> ValidationResult.Error("Login must not be empty") + login.contains(" ") -> ValidationResult.Error("Login must not contain whitespace characters") + login.length < 3 -> ValidationResult.Error("Login must be at least 3 characters") + login.length > 64 -> ValidationResult.Error("Login must not exceed 64 characters") + else -> ValidationResult.Valid + } + } + + fun validatePassword(password: String): ValidationResult { + return when { + password.isBlank() -> ValidationResult.Error("Password must not be empty") + password.length < 8 -> ValidationResult.Error("Password must be at least 8 characters") + password.length > 128 -> ValidationResult.Error("Password must not exceed 128 characters") + else -> ValidationResult.Valid + } + } + + fun validatePasswordConfirmation(password: String, confirmation: String): ValidationResult { + return when { + confirmation.isBlank() -> ValidationResult.Error("Please confirm your password") + password != confirmation -> ValidationResult.Error("Passwords do not match") + else -> ValidationResult.Valid + } + } + + fun validateOtp(otp: String): ValidationResult { + return when { + otp.isBlank() -> ValidationResult.Error("Code must not be empty") + otp.length < 4 -> ValidationResult.Error("Code must be at least 4 characters") + otp.length > 8 -> ValidationResult.Error("Code must not exceed 8 characters") + else -> ValidationResult.Valid + } + } +} + +sealed class ValidationResult { + data object Valid : ValidationResult() + data class Error(val message: String) : ValidationResult() +} diff --git a/app/src/main/java/org/yobble/messenger/presentation/auth/code/CodeVerificationScreen.kt b/app/src/main/java/org/yobble/messenger/presentation/auth/code/CodeVerificationScreen.kt new file mode 100644 index 0000000..adc5591 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/presentation/auth/code/CodeVerificationScreen.kt @@ -0,0 +1,150 @@ +package org.yobble.messenger.presentation.auth.code + +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import kotlinx.coroutines.flow.collectLatest + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun CodeVerificationScreen( + login: String, + onNavigateBack: () -> Unit, + onVerifySuccess: () -> Unit, + viewModel: CodeVerificationViewModel = hiltViewModel() +) { + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val snackbarHostState = remember { SnackbarHostState() } + val focusManager = LocalFocusManager.current + + LaunchedEffect(Unit) { + viewModel.events.collectLatest { event -> + when (event) { + is CodeVerificationEvent.VerifySuccess -> onVerifySuccess() + is CodeVerificationEvent.ShowError -> snackbarHostState.showSnackbar(event.message) + } + } + } + + Scaffold( + snackbarHost = { SnackbarHost(snackbarHostState) }, + topBar = { + TopAppBar( + title = { Text("Verification") }, + navigationIcon = { + IconButton(onClick = onNavigateBack) { + Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back") + } + } + ) + } + ) { padding -> + Column( + modifier = Modifier + .fillMaxSize() + .padding(padding) + .padding(horizontal = 32.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Spacer(modifier = Modifier.height(48.dp)) + + Text( + text = "Enter the code", + style = MaterialTheme.typography.headlineSmall, + color = MaterialTheme.colorScheme.onBackground + ) + + Spacer(modifier = Modifier.height(8.dp)) + + Text( + text = "We sent a verification code to\n$login", + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, + textAlign = TextAlign.Center + ) + + Spacer(modifier = Modifier.height(40.dp)) + + OutlinedTextField( + value = uiState.code, + onValueChange = viewModel::onCodeChange, + label = { Text("Code") }, + singleLine = true, + isError = uiState.codeError != null, + supportingText = uiState.codeError?.let { error -> { Text(error) } }, + textStyle = LocalTextStyle.current.copy( + textAlign = TextAlign.Center, + fontSize = 24.sp, + letterSpacing = 8.sp + ), + keyboardOptions = KeyboardOptions( + keyboardType = KeyboardType.Number, + imeAction = ImeAction.Done + ), + keyboardActions = KeyboardActions( + onDone = { + focusManager.clearFocus() + viewModel.verifyCode() + } + ), + modifier = Modifier.fillMaxWidth(), + shape = RoundedCornerShape(12.dp) + ) + + Spacer(modifier = Modifier.height(24.dp)) + + Button( + onClick = viewModel::verifyCode, + modifier = Modifier + .fillMaxWidth() + .height(48.dp), + shape = RoundedCornerShape(12.dp), + colors = ButtonDefaults.buttonColors( + containerColor = MaterialTheme.colorScheme.primary + ), + enabled = !uiState.isLoading + ) { + if (uiState.isLoading) { + CircularProgressIndicator( + modifier = Modifier.size(24.dp), + color = MaterialTheme.colorScheme.onPrimary, + strokeWidth = 2.dp + ) + } else { + Text( + "Verify", + style = MaterialTheme.typography.labelLarge + ) + } + } + + Spacer(modifier = Modifier.height(16.dp)) + + TextButton( + onClick = viewModel::resendCode, + enabled = !uiState.isLoading + ) { + Text( + "Resend Code", + style = MaterialTheme.typography.labelMedium, + color = MaterialTheme.colorScheme.primary + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/yobble/messenger/presentation/auth/code/CodeVerificationViewModel.kt b/app/src/main/java/org/yobble/messenger/presentation/auth/code/CodeVerificationViewModel.kt new file mode 100644 index 0000000..747024e --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/presentation/auth/code/CodeVerificationViewModel.kt @@ -0,0 +1,101 @@ +package org.yobble.messenger.presentation.auth.code + +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import org.yobble.messenger.data.remote.NetworkResult +import org.yobble.messenger.domain.repository.AuthRepository +import org.yobble.messenger.domain.validation.AuthValidator +import org.yobble.messenger.domain.validation.ValidationResult +import javax.inject.Inject + +data class CodeVerificationUiState( + val login: String = "", + val code: String = "", + val codeError: String? = null, + val isLoading: Boolean = false +) + +sealed class CodeVerificationEvent { + data object VerifySuccess : CodeVerificationEvent() + data class ShowError(val message: String) : CodeVerificationEvent() +} + +@HiltViewModel +class CodeVerificationViewModel @Inject constructor( + savedStateHandle: SavedStateHandle, + private val authRepository: AuthRepository +) : ViewModel() { + + private val _uiState = MutableStateFlow( + CodeVerificationUiState( + login = savedStateHandle.get("login") ?: "" + ) + ) + val uiState: StateFlow = _uiState.asStateFlow() + + private val _events = MutableSharedFlow() + val events: SharedFlow = _events.asSharedFlow() + + fun onCodeChange(value: String) { + if (value.length <= 8) { + _uiState.update { it.copy(code = value, codeError = null) } + } + } + + fun verifyCode() { + val state = _uiState.value + val otpValidation = AuthValidator.validateOtp(state.code) + + if (otpValidation is ValidationResult.Error) { + _uiState.update { it.copy(codeError = otpValidation.message) } + return + } + + viewModelScope.launch { + _uiState.update { it.copy(isLoading = true) } + when (val result = authRepository.verifyCode(state.login, state.code)) { + is NetworkResult.Success -> { + _events.emit(CodeVerificationEvent.VerifySuccess) + } + is NetworkResult.Error -> { + val errorMessage = result.errors.firstOrNull()?.message + ?: result.message + ?: "Verification failed" + _events.emit(CodeVerificationEvent.ShowError(errorMessage)) + } + is NetworkResult.Exception -> { + _events.emit(CodeVerificationEvent.ShowError("Connection error. Please try again.")) + } + } + _uiState.update { it.copy(isLoading = false) } + } + } + + fun resendCode() { + viewModelScope.launch { + _uiState.update { it.copy(isLoading = true) } + when (authRepository.requestLoginCode(_uiState.value.login)) { + is NetworkResult.Success -> { + _events.emit(CodeVerificationEvent.ShowError("Code sent successfully")) + } + is NetworkResult.Error -> { + _events.emit(CodeVerificationEvent.ShowError("Failed to resend code")) + } + is NetworkResult.Exception -> { + _events.emit(CodeVerificationEvent.ShowError("Connection error")) + } + } + _uiState.update { it.copy(isLoading = false) } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/yobble/messenger/presentation/auth/login/LoginScreen.kt b/app/src/main/java/org/yobble/messenger/presentation/auth/login/LoginScreen.kt new file mode 100644 index 0000000..efa3251 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/presentation/auth/login/LoginScreen.kt @@ -0,0 +1,195 @@ +package org.yobble.messenger.presentation.auth.login + +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ChatBubble +import androidx.compose.material.icons.filled.Visibility +import androidx.compose.material.icons.filled.VisibilityOff +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusDirection +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.input.PasswordVisualTransformation +import androidx.compose.ui.text.input.VisualTransformation +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import kotlinx.coroutines.flow.collectLatest + +@Composable +fun LoginScreen( + onNavigateToRegister: () -> Unit, + onNavigateToCodeLogin: (String) -> Unit, + onLoginSuccess: () -> Unit, + viewModel: LoginViewModel = hiltViewModel() +) { + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val snackbarHostState = remember { SnackbarHostState() } + val focusManager = LocalFocusManager.current + + LaunchedEffect(Unit) { + viewModel.events.collectLatest { event -> + when (event) { + is LoginEvent.LoginSuccess -> onLoginSuccess() + is LoginEvent.CodeRequested -> onNavigateToCodeLogin(event.login) + is LoginEvent.ShowError -> snackbarHostState.showSnackbar(event.message) + } + } + } + + Scaffold( + snackbarHost = { SnackbarHost(snackbarHostState) } + ) { padding -> + Column( + modifier = Modifier + .fillMaxSize() + .padding(padding) + .verticalScroll(rememberScrollState()) + .padding(horizontal = 32.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Spacer(modifier = Modifier.height(80.dp)) + + Icon( + imageVector = Icons.Default.ChatBubble, + contentDescription = null, + modifier = Modifier.size(80.dp), + tint = MaterialTheme.colorScheme.primary + ) + + Spacer(modifier = Modifier.height(16.dp)) + + Text( + text = "Yobble", + style = MaterialTheme.typography.headlineLarge, + color = MaterialTheme.colorScheme.onBackground + ) + + Spacer(modifier = Modifier.height(8.dp)) + + Text( + text = "Sign in to your account", + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + + Spacer(modifier = Modifier.height(40.dp)) + + OutlinedTextField( + value = uiState.login, + onValueChange = viewModel::onLoginChange, + label = { Text("Login") }, + singleLine = true, + isError = uiState.loginError != null, + supportingText = uiState.loginError?.let { error -> { Text(error) } }, + keyboardOptions = KeyboardOptions( + keyboardType = KeyboardType.Text, + imeAction = ImeAction.Next + ), + keyboardActions = KeyboardActions( + onNext = { focusManager.moveFocus(FocusDirection.Down) } + ), + modifier = Modifier.fillMaxWidth(), + shape = RoundedCornerShape(12.dp) + ) + + Spacer(modifier = Modifier.height(8.dp)) + + OutlinedTextField( + value = uiState.password, + onValueChange = viewModel::onPasswordChange, + label = { Text("Password") }, + singleLine = true, + isError = uiState.passwordError != null, + supportingText = uiState.passwordError?.let { error -> { Text(error) } }, + visualTransformation = if (uiState.isPasswordVisible) VisualTransformation.None else PasswordVisualTransformation(), + keyboardOptions = KeyboardOptions( + keyboardType = KeyboardType.Password, + imeAction = ImeAction.Done + ), + keyboardActions = KeyboardActions( + onDone = { + focusManager.clearFocus() + viewModel.login() + } + ), + trailingIcon = { + IconButton(onClick = viewModel::togglePasswordVisibility) { + Icon( + imageVector = if (uiState.isPasswordVisible) Icons.Default.VisibilityOff else Icons.Default.Visibility, + contentDescription = if (uiState.isPasswordVisible) "Hide password" else "Show password" + ) + } + }, + modifier = Modifier.fillMaxWidth(), + shape = RoundedCornerShape(12.dp) + ) + + Spacer(modifier = Modifier.height(24.dp)) + + Button( + onClick = viewModel::login, + modifier = Modifier + .fillMaxWidth() + .height(48.dp), + shape = RoundedCornerShape(12.dp), + colors = ButtonDefaults.buttonColors( + containerColor = MaterialTheme.colorScheme.primary + ), + enabled = !uiState.isLoading + ) { + if (uiState.isLoading) { + CircularProgressIndicator( + modifier = Modifier.size(24.dp), + color = MaterialTheme.colorScheme.onPrimary, + strokeWidth = 2.dp + ) + } else { + Text( + "Log In", + style = MaterialTheme.typography.labelLarge + ) + } + } + + Spacer(modifier = Modifier.height(16.dp)) + + TextButton(onClick = viewModel::requestLoginCode) { + Text( + "Login with Code", + style = MaterialTheme.typography.labelMedium, + color = MaterialTheme.colorScheme.primary + ) + } + + Spacer(modifier = Modifier.weight(1f)) + + Row( + modifier = Modifier.padding(bottom = 32.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + "Don't have an account?", + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + TextButton(onClick = onNavigateToRegister) { + Text( + "Register", + style = MaterialTheme.typography.labelMedium, + color = MaterialTheme.colorScheme.primary + ) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/yobble/messenger/presentation/auth/login/LoginViewModel.kt b/app/src/main/java/org/yobble/messenger/presentation/auth/login/LoginViewModel.kt new file mode 100644 index 0000000..201c089 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/presentation/auth/login/LoginViewModel.kt @@ -0,0 +1,121 @@ +package org.yobble.messenger.presentation.auth.login + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import org.yobble.messenger.data.remote.NetworkResult +import org.yobble.messenger.domain.repository.AuthRepository +import org.yobble.messenger.domain.validation.AuthValidator +import org.yobble.messenger.domain.validation.ValidationResult +import javax.inject.Inject + +data class LoginUiState( + val login: String = "", + val password: String = "", + val loginError: String? = null, + val passwordError: String? = null, + val isLoading: Boolean = false, + val isPasswordVisible: Boolean = false +) + +sealed class LoginEvent { + data object LoginSuccess : LoginEvent() + data class CodeRequested(val login: String) : LoginEvent() + data class ShowError(val message: String) : LoginEvent() +} + +@HiltViewModel +class LoginViewModel @Inject constructor( + private val authRepository: AuthRepository +) : ViewModel() { + + private val _uiState = MutableStateFlow(LoginUiState()) + val uiState: StateFlow = _uiState.asStateFlow() + + private val _events = MutableSharedFlow() + val events: SharedFlow = _events.asSharedFlow() + + fun onLoginChange(value: String) { + _uiState.update { it.copy(login = value, loginError = null) } + } + + fun onPasswordChange(value: String) { + _uiState.update { it.copy(password = value, passwordError = null) } + } + + fun togglePasswordVisibility() { + _uiState.update { it.copy(isPasswordVisible = !it.isPasswordVisible) } + } + + fun login() { + val state = _uiState.value + val loginValidation = AuthValidator.validateLogin(state.login) + val passwordValidation = AuthValidator.validatePassword(state.password) + + if (loginValidation is ValidationResult.Error || passwordValidation is ValidationResult.Error) { + _uiState.update { + it.copy( + loginError = (loginValidation as? ValidationResult.Error)?.message, + passwordError = (passwordValidation as? ValidationResult.Error)?.message + ) + } + return + } + + viewModelScope.launch { + _uiState.update { it.copy(isLoading = true) } + when (val result = authRepository.login(state.login, state.password)) { + is NetworkResult.Success -> { + _events.emit(LoginEvent.LoginSuccess) + } + is NetworkResult.Error -> { + val errorMessage = result.errors.firstOrNull()?.message + ?: result.message + ?: "Login failed" + _events.emit(LoginEvent.ShowError(errorMessage)) + } + is NetworkResult.Exception -> { + _events.emit(LoginEvent.ShowError("Connection error. Please try again.")) + } + } + _uiState.update { it.copy(isLoading = false) } + } + } + + fun requestLoginCode() { + val state = _uiState.value + val loginValidation = AuthValidator.validateLogin(state.login) + + if (loginValidation is ValidationResult.Error) { + _uiState.update { it.copy(loginError = loginValidation.message) } + return + } + + viewModelScope.launch { + _uiState.update { it.copy(isLoading = true) } + when (val result = authRepository.requestLoginCode(state.login)) { + is NetworkResult.Success -> { + _events.emit(LoginEvent.CodeRequested(state.login)) + } + is NetworkResult.Error -> { + val errorMessage = result.errors.firstOrNull()?.message + ?: result.message + ?: "Failed to send code" + _events.emit(LoginEvent.ShowError(errorMessage)) + } + is NetworkResult.Exception -> { + _events.emit(LoginEvent.ShowError("Connection error. Please try again.")) + } + } + _uiState.update { it.copy(isLoading = false) } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/yobble/messenger/presentation/auth/register/RegisterScreen.kt b/app/src/main/java/org/yobble/messenger/presentation/auth/register/RegisterScreen.kt new file mode 100644 index 0000000..d3e06b4 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/presentation/auth/register/RegisterScreen.kt @@ -0,0 +1,235 @@ +package org.yobble.messenger.presentation.auth.register + +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.filled.Visibility +import androidx.compose.material.icons.filled.VisibilityOff +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusDirection +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.input.PasswordVisualTransformation +import androidx.compose.ui.text.input.VisualTransformation +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import kotlinx.coroutines.flow.collectLatest + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun RegisterScreen( + onNavigateBack: () -> Unit, + onRegisterSuccess: () -> Unit, + viewModel: RegisterViewModel = hiltViewModel() +) { + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val snackbarHostState = remember { SnackbarHostState() } + val focusManager = LocalFocusManager.current + + LaunchedEffect(Unit) { + viewModel.events.collectLatest { event -> + when (event) { + is RegisterEvent.RegisterSuccess -> { + snackbarHostState.showSnackbar("Registration successful! Please log in.") + onRegisterSuccess() + } + is RegisterEvent.ShowError -> snackbarHostState.showSnackbar(event.message) + } + } + } + + Scaffold( + snackbarHost = { SnackbarHost(snackbarHostState) }, + topBar = { + TopAppBar( + title = { Text("Register") }, + navigationIcon = { + IconButton(onClick = onNavigateBack) { + Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back") + } + } + ) + } + ) { padding -> + Column( + modifier = Modifier + .fillMaxSize() + .padding(padding) + .verticalScroll(rememberScrollState()) + .padding(horizontal = 32.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Spacer(modifier = Modifier.height(24.dp)) + + Text( + text = "Create your account", + style = MaterialTheme.typography.headlineSmall, + color = MaterialTheme.colorScheme.onBackground + ) + + Spacer(modifier = Modifier.height(8.dp)) + + Text( + text = "Enter your details to get started", + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + + Spacer(modifier = Modifier.height(32.dp)) + + OutlinedTextField( + value = uiState.login, + onValueChange = viewModel::onLoginChange, + label = { Text("Login") }, + singleLine = true, + isError = uiState.loginError != null, + supportingText = uiState.loginError?.let { error -> { Text(error) } }, + keyboardOptions = KeyboardOptions( + keyboardType = KeyboardType.Text, + imeAction = ImeAction.Next + ), + keyboardActions = KeyboardActions( + onNext = { focusManager.moveFocus(FocusDirection.Down) } + ), + modifier = Modifier.fillMaxWidth(), + shape = RoundedCornerShape(12.dp) + ) + + Spacer(modifier = Modifier.height(8.dp)) + + OutlinedTextField( + value = uiState.password, + onValueChange = viewModel::onPasswordChange, + label = { Text("Password") }, + singleLine = true, + isError = uiState.passwordError != null, + supportingText = uiState.passwordError?.let { error -> { Text(error) } }, + visualTransformation = if (uiState.isPasswordVisible) VisualTransformation.None else PasswordVisualTransformation(), + keyboardOptions = KeyboardOptions( + keyboardType = KeyboardType.Password, + imeAction = ImeAction.Next + ), + keyboardActions = KeyboardActions( + onNext = { focusManager.moveFocus(FocusDirection.Down) } + ), + trailingIcon = { + IconButton(onClick = viewModel::togglePasswordVisibility) { + Icon( + imageVector = if (uiState.isPasswordVisible) Icons.Default.VisibilityOff else Icons.Default.Visibility, + contentDescription = if (uiState.isPasswordVisible) "Hide password" else "Show password" + ) + } + }, + modifier = Modifier.fillMaxWidth(), + shape = RoundedCornerShape(12.dp) + ) + + Spacer(modifier = Modifier.height(8.dp)) + + OutlinedTextField( + value = uiState.confirmPassword, + onValueChange = viewModel::onConfirmPasswordChange, + label = { Text("Confirm Password") }, + singleLine = true, + isError = uiState.confirmPasswordError != null, + supportingText = uiState.confirmPasswordError?.let { error -> { Text(error) } }, + visualTransformation = if (uiState.isConfirmPasswordVisible) VisualTransformation.None else PasswordVisualTransformation(), + keyboardOptions = KeyboardOptions( + keyboardType = KeyboardType.Password, + imeAction = ImeAction.Next + ), + keyboardActions = KeyboardActions( + onNext = { focusManager.moveFocus(FocusDirection.Down) } + ), + trailingIcon = { + IconButton(onClick = viewModel::toggleConfirmPasswordVisibility) { + Icon( + imageVector = if (uiState.isConfirmPasswordVisible) Icons.Default.VisibilityOff else Icons.Default.Visibility, + contentDescription = if (uiState.isConfirmPasswordVisible) "Hide password" else "Show password" + ) + } + }, + modifier = Modifier.fillMaxWidth(), + shape = RoundedCornerShape(12.dp) + ) + + Spacer(modifier = Modifier.height(8.dp)) + + OutlinedTextField( + value = uiState.invite, + onValueChange = viewModel::onInviteChange, + label = { Text("Invite Code (optional)") }, + singleLine = true, + keyboardOptions = KeyboardOptions( + keyboardType = KeyboardType.Text, + imeAction = ImeAction.Done + ), + keyboardActions = KeyboardActions( + onDone = { + focusManager.clearFocus() + viewModel.register() + } + ), + modifier = Modifier.fillMaxWidth(), + shape = RoundedCornerShape(12.dp) + ) + + Spacer(modifier = Modifier.height(24.dp)) + + Button( + onClick = viewModel::register, + modifier = Modifier + .fillMaxWidth() + .height(48.dp), + shape = RoundedCornerShape(12.dp), + colors = ButtonDefaults.buttonColors( + containerColor = MaterialTheme.colorScheme.primary + ), + enabled = !uiState.isLoading + ) { + if (uiState.isLoading) { + CircularProgressIndicator( + modifier = Modifier.size(24.dp), + color = MaterialTheme.colorScheme.onPrimary, + strokeWidth = 2.dp + ) + } else { + Text( + "Register", + style = MaterialTheme.typography.labelLarge + ) + } + } + + Spacer(modifier = Modifier.weight(1f)) + + Row( + modifier = Modifier.padding(bottom = 32.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + "Already have an account?", + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + TextButton(onClick = onNavigateBack) { + Text( + "Log In", + style = MaterialTheme.typography.labelMedium, + color = MaterialTheme.colorScheme.primary + ) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/yobble/messenger/presentation/auth/register/RegisterViewModel.kt b/app/src/main/java/org/yobble/messenger/presentation/auth/register/RegisterViewModel.kt new file mode 100644 index 0000000..831eacd --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/presentation/auth/register/RegisterViewModel.kt @@ -0,0 +1,113 @@ +package org.yobble.messenger.presentation.auth.register + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import org.yobble.messenger.data.remote.NetworkResult +import org.yobble.messenger.domain.repository.AuthRepository +import org.yobble.messenger.domain.validation.AuthValidator +import org.yobble.messenger.domain.validation.ValidationResult +import javax.inject.Inject + +data class RegisterUiState( + val login: String = "", + val password: String = "", + val confirmPassword: String = "", + val invite: String = "", + val loginError: String? = null, + val passwordError: String? = null, + val confirmPasswordError: String? = null, + val isLoading: Boolean = false, + val isPasswordVisible: Boolean = false, + val isConfirmPasswordVisible: Boolean = false +) + +sealed class RegisterEvent { + data object RegisterSuccess : RegisterEvent() + data class ShowError(val message: String) : RegisterEvent() +} + +@HiltViewModel +class RegisterViewModel @Inject constructor( + private val authRepository: AuthRepository +) : ViewModel() { + + private val _uiState = MutableStateFlow(RegisterUiState()) + val uiState: StateFlow = _uiState.asStateFlow() + + private val _events = MutableSharedFlow() + val events: SharedFlow = _events.asSharedFlow() + + fun onLoginChange(value: String) { + _uiState.update { it.copy(login = value, loginError = null) } + } + + fun onPasswordChange(value: String) { + _uiState.update { it.copy(password = value, passwordError = null) } + } + + fun onConfirmPasswordChange(value: String) { + _uiState.update { it.copy(confirmPassword = value, confirmPasswordError = null) } + } + + fun onInviteChange(value: String) { + _uiState.update { it.copy(invite = value) } + } + + fun togglePasswordVisibility() { + _uiState.update { it.copy(isPasswordVisible = !it.isPasswordVisible) } + } + + fun toggleConfirmPasswordVisibility() { + _uiState.update { it.copy(isConfirmPasswordVisible = !it.isConfirmPasswordVisible) } + } + + fun register() { + val state = _uiState.value + val loginValidation = AuthValidator.validateLogin(state.login) + val passwordValidation = AuthValidator.validatePassword(state.password) + val confirmValidation = AuthValidator.validatePasswordConfirmation(state.password, state.confirmPassword) + + if (loginValidation is ValidationResult.Error || + passwordValidation is ValidationResult.Error || + confirmValidation is ValidationResult.Error + ) { + _uiState.update { + it.copy( + loginError = (loginValidation as? ValidationResult.Error)?.message, + passwordError = (passwordValidation as? ValidationResult.Error)?.message, + confirmPasswordError = (confirmValidation as? ValidationResult.Error)?.message + ) + } + return + } + + viewModelScope.launch { + _uiState.update { it.copy(isLoading = true) } + val invite = state.invite.ifBlank { null } + when (val result = authRepository.register(state.login, state.password, invite)) { + is NetworkResult.Success -> { + _events.emit(RegisterEvent.RegisterSuccess) + } + is NetworkResult.Error -> { + val errorMessage = result.errors.firstOrNull()?.message + ?: result.message + ?: "Registration failed" + _events.emit(RegisterEvent.ShowError(errorMessage)) + } + is NetworkResult.Exception -> { + _events.emit(RegisterEvent.ShowError("Connection error. Please try again.")) + } + } + _uiState.update { it.copy(isLoading = false) } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/yobble/messenger/presentation/chat/ChatScreen.kt b/app/src/main/java/org/yobble/messenger/presentation/chat/ChatScreen.kt new file mode 100644 index 0000000..1652ba7 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/presentation/chat/ChatScreen.kt @@ -0,0 +1,374 @@ +package org.yobble.messenger.presentation.chat + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.automirrored.filled.Send +import androidx.compose.material.icons.filled.KeyboardArrowDown +import androidx.compose.material.icons.filled.Star +import androidx.compose.material.icons.filled.Verified +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.launch +import org.yobble.messenger.data.remote.dto.MessageItemDto +import org.yobble.messenger.util.formatUtcToLocalTime + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun ChatScreen( + onNavigateBack: () -> Unit, + onNavigateToProfile: (userId: String) -> Unit = {}, + viewModel: ChatViewModel = hiltViewModel() +) { + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val snackbarHostState = remember { SnackbarHostState() } + val listState = rememberLazyListState() + val coroutineScope = rememberCoroutineScope() + + // Save scroll position when leaving the chat + DisposableEffect(Unit) { + onDispose { + val messages = viewModel.uiState.value.messages + if (messages.isNotEmpty()) { + val firstVisibleIndex = listState.firstVisibleItemIndex + val reversed = messages.asReversed() + val messageId = reversed.getOrNull(firstVisibleIndex)?.messageId + if (messageId != null) { + viewModel.saveScrollPosition(messageId) + } + } + } + } + + // Scroll to saved position after initial load + LaunchedEffect(uiState.scrollToMessageId) { + val targetId = uiState.scrollToMessageId ?: return@LaunchedEffect + val targetInt = targetId.toIntOrNull() ?: return@LaunchedEffect + val reversed = uiState.messages.asReversed() + val index = reversed.indexOfFirst { it.messageId == targetInt } + if (index >= 0) { + listState.scrollToItem(index) + } + viewModel.clearScrollTarget() + } + + LaunchedEffect(Unit) { + viewModel.events.collectLatest { event -> + when (event) { + is ChatEvent.ShowError -> snackbarHostState.showSnackbar(event.message) + } + } + } + + // Show scroll-to-bottom button when scrolled up more than 15 messages + val showScrollToBottom by remember { + derivedStateOf { + listState.firstVisibleItemIndex > 15 + } + } + + // Load more when scrolled near the top (high indices in reversed layout) + val shouldLoadMore by remember { + derivedStateOf { + val lastVisible = listState.layoutInfo.visibleItemsInfo.lastOrNull()?.index ?: 0 + val totalItems = listState.layoutInfo.totalItemsCount + lastVisible >= totalItems - 3 && uiState.hasMore && !uiState.isLoading + } + } + LaunchedEffect(shouldLoadMore) { + if (shouldLoadMore) viewModel.loadMore() + } + + Scaffold( + modifier = Modifier.imePadding(), + contentWindowInsets = WindowInsets(0), + snackbarHost = { SnackbarHost(snackbarHostState) }, + topBar = { + TopAppBar( + title = { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.clickable { + uiState.otherUserId?.let { onNavigateToProfile(it) } + } + ) { + Text(uiState.chatTitle, fontWeight = FontWeight.Bold) + if (uiState.isVerified) { + Spacer(modifier = Modifier.width(4.dp)) + Icon( + Icons.Default.Verified, + contentDescription = "Verified", + tint = MaterialTheme.colorScheme.onPrimary, + modifier = Modifier.size(18.dp) + ) + } + if (uiState.rating != null) { + Spacer(modifier = Modifier.width(8.dp)) + Icon( + Icons.Default.Star, + contentDescription = "Rating", + tint = Color(0xFFFFC107), + modifier = Modifier.size(16.dp) + ) + Text( + text = String.format("%.1f", uiState.rating), + fontSize = 13.sp, + color = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.8f) + ) + } + } + }, + navigationIcon = { + IconButton(onClick = onNavigateBack) { + Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back") + } + }, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = MaterialTheme.colorScheme.primary, + titleContentColor = MaterialTheme.colorScheme.onPrimary, + navigationIconContentColor = MaterialTheme.colorScheme.onPrimary + ) + ) + }, + bottomBar = { + if (uiState.canSendMessage) { + MessageInputBar( + text = uiState.messageText, + onTextChange = viewModel::onMessageTextChange, + onSend = viewModel::sendMessage, + isSending = uiState.isSending + ) + } else { + Surface( + shadowElevation = 8.dp, + color = MaterialTheme.colorScheme.surfaceVariant + ) { + Text( + text = "You can't send messages to this user", + modifier = Modifier + .fillMaxWidth() + .padding(16.dp) + .navigationBarsPadding(), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, + textAlign = TextAlign.Center + ) + } + } + } + ) { padding -> + Box( + modifier = Modifier + .fillMaxSize() + .padding(padding) + ) { + if (uiState.isLoading && uiState.messages.isEmpty()) { + CircularProgressIndicator( + color = MaterialTheme.colorScheme.primary, + modifier = Modifier.align(Alignment.Center) + ) + } else { + LazyColumn( + modifier = Modifier + .fillMaxSize() + .padding(horizontal = 8.dp), + state = listState, + reverseLayout = true, + verticalArrangement = Arrangement.spacedBy(4.dp), + contentPadding = PaddingValues(vertical = 8.dp) + ) { + items(uiState.messages.asReversed(), key = { it.messageId }) { message -> + MessageBubble( + message = message, + isOutgoing = message.senderId == uiState.currentUserId + ) + } + if (uiState.isLoading && uiState.messages.isNotEmpty()) { + item { + Box( + modifier = Modifier + .fillMaxWidth() + .padding(8.dp), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator( + modifier = Modifier.size(24.dp), + strokeWidth = 2.dp, + color = MaterialTheme.colorScheme.primary + ) + } + } + } + } + } + + AnimatedVisibility( + visible = showScrollToBottom, + enter = fadeIn(), + exit = fadeOut(), + modifier = Modifier + .align(Alignment.BottomEnd) + .padding(16.dp) + ) { + SmallFloatingActionButton( + onClick = { + coroutineScope.launch { + listState.animateScrollToItem(0) + } + }, + containerColor = MaterialTheme.colorScheme.surface, + contentColor = MaterialTheme.colorScheme.primary + ) { + Icon( + Icons.Default.KeyboardArrowDown, + contentDescription = "Scroll to bottom" + ) + } + } + } + } +} + +@Composable +private fun MessageBubble( + message: MessageItemDto, + isOutgoing: Boolean +) { + val bubbleColor = if (isOutgoing) + MaterialTheme.colorScheme.primary + else + MaterialTheme.colorScheme.surfaceVariant + + val textColor = if (isOutgoing) + MaterialTheme.colorScheme.onPrimary + else + MaterialTheme.colorScheme.onSurface + + val timeColor = if (isOutgoing) + MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.7f) + else + MaterialTheme.colorScheme.onSurfaceVariant + + val alignment = if (isOutgoing) Arrangement.End else Arrangement.Start + val shape = if (isOutgoing) + RoundedCornerShape(16.dp, 16.dp, 4.dp, 16.dp) + else + RoundedCornerShape(16.dp, 16.dp, 16.dp, 4.dp) + + val time = formatUtcToLocalTime(message.createdAt) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = alignment + ) { + Box( + modifier = Modifier + .widthIn(max = 280.dp) + .clip(shape) + .background(bubbleColor) + .padding(horizontal = 12.dp, vertical = 8.dp) + ) { + Column { + if (!message.content.isNullOrBlank()) { + Text( + text = message.content, + color = textColor, + fontSize = 15.sp + ) + } + Spacer(modifier = Modifier.height(2.dp)) + Text( + text = time, + color = timeColor, + fontSize = 11.sp, + modifier = Modifier.align(Alignment.End) + ) + } + } + } +} + +@Composable +private fun MessageInputBar( + text: String, + onTextChange: (String) -> Unit, + onSend: () -> Unit, + isSending: Boolean +) { + Surface( + shadowElevation = 8.dp, + color = MaterialTheme.colorScheme.surface + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 8.dp, vertical = 8.dp) + .navigationBarsPadding(), + verticalAlignment = Alignment.CenterVertically + ) { + TextField( + value = text, + onValueChange = onTextChange, + modifier = Modifier.weight(1f), + placeholder = { Text("Message") }, + keyboardOptions = KeyboardOptions(imeAction = ImeAction.Send), + keyboardActions = KeyboardActions(onSend = { onSend() }), + maxLines = 4, + colors = TextFieldDefaults.colors( + focusedContainerColor = MaterialTheme.colorScheme.surfaceVariant, + unfocusedContainerColor = MaterialTheme.colorScheme.surfaceVariant, + focusedIndicatorColor = Color.Transparent, + unfocusedIndicatorColor = Color.Transparent + ), + shape = RoundedCornerShape(24.dp) + ) + Spacer(modifier = Modifier.width(8.dp)) + IconButton( + onClick = onSend, + enabled = text.isNotBlank() && !isSending, + modifier = Modifier + .size(48.dp) + .clip(CircleShape) + .background( + if (text.isNotBlank() && !isSending) + MaterialTheme.colorScheme.primary + else + MaterialTheme.colorScheme.surfaceVariant + ) + ) { + Icon( + Icons.AutoMirrored.Filled.Send, + contentDescription = "Send", + tint = if (text.isNotBlank() && !isSending) + MaterialTheme.colorScheme.onPrimary + else + MaterialTheme.colorScheme.onSurfaceVariant + ) + } + } + } +} diff --git a/app/src/main/java/org/yobble/messenger/presentation/chat/ChatViewModel.kt b/app/src/main/java/org/yobble/messenger/presentation/chat/ChatViewModel.kt new file mode 100644 index 0000000..82343c2 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/presentation/chat/ChatViewModel.kt @@ -0,0 +1,222 @@ +package org.yobble.messenger.presentation.chat + +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import android.util.Log +import kotlinx.serialization.json.Json +import org.yobble.messenger.data.local.SessionManager +import org.yobble.messenger.data.remote.NetworkResult +import org.yobble.messenger.data.remote.dto.MessageItemDto +import org.yobble.messenger.data.remote.socket.SocketEvent +import org.yobble.messenger.data.remote.socket.SocketManager +import org.yobble.messenger.domain.repository.ChatRepository +import javax.inject.Inject + +data class ChatUiState( + val chatId: String = "", + val chatTitle: String = "Chat", + val isVerified: Boolean = false, + val rating: Double? = null, + val canSendMessage: Boolean = true, + val messages: List = emptyList(), + val messageText: String = "", + val isLoading: Boolean = false, + val isSending: Boolean = false, + val hasMore: Boolean = false, + val currentUserId: String = "", + val otherUserId: String? = null, + val scrollToMessageId: String? = null +) + +sealed class ChatEvent { + data class ShowError(val message: String) : ChatEvent() +} + +@HiltViewModel +class ChatViewModel @Inject constructor( + savedStateHandle: SavedStateHandle, + private val chatRepository: ChatRepository, + private val sessionManager: SessionManager, + private val socketManager: SocketManager, + private val json: Json +) : ViewModel() { + + private val chatId = savedStateHandle.get("chatId") ?: "" + + private val _uiState = MutableStateFlow( + ChatUiState( + chatId = chatId, + currentUserId = sessionManager.userId ?: "", + messageText = sessionManager.getDraft(chatId) + ) + ) + val uiState: StateFlow = _uiState.asStateFlow() + + private val _events = MutableSharedFlow() + val events: SharedFlow = _events.asSharedFlow() + + private val savedMessageId = sessionManager.getLastReadMessageId(chatId) + + init { + loadMessages() + observeSocket() + } + + private fun observeSocket() { + viewModelScope.launch { + socketManager.events.collect { event -> + when (event) { + is SocketEvent.NewMessage -> { + val data = event.data + val payload = data.optJSONObject("payload") ?: data + val eventChatId = payload.optString("chat_id", "") + + if (eventChatId == _uiState.value.chatId) { + // Parse message from socket payload and insert instantly + try { + val message = json.decodeFromString(payload.toString()) + val current = _uiState.value.messages + if (current.none { it.messageId == message.messageId }) { + _uiState.update { it.copy(messages = current + message) } + } + } catch (e: Exception) { + Log.w("ChatViewModel", "Failed to parse socket message, reloading", e) + loadMessages() + } + } + } + else -> {} + } + } + } + } + + fun loadMessages() { + val chatId = _uiState.value.chatId + if (chatId.isBlank()) return + + viewModelScope.launch { + _uiState.update { it.copy(isLoading = true) } + when (val result = chatRepository.getChatHistory(chatId)) { + is NetworkResult.Success -> { + val items = result.data.data.items.reversed() + val otherMessage = items.firstOrNull { it.senderId != _uiState.value.currentUserId } + val otherUser = otherMessage?.senderData + val title = otherUser?.customName + ?: otherUser?.fullName + ?: otherUser?.login?.let { "@$it" } + ?: _uiState.value.chatTitle + val scrollTarget = if (_uiState.value.messages.isEmpty()) savedMessageId else null + _uiState.update { + it.copy( + messages = items, + chatTitle = title, + otherUserId = otherMessage?.senderId, + isVerified = otherUser?.isVerified == true, + rating = otherUser?.rating?.rating, + canSendMessage = otherUser?.permissions?.youCanSendMessage != false, + hasMore = result.data.data.hasMore, + isLoading = false, + scrollToMessageId = scrollTarget + ) + } + } + is NetworkResult.Error -> { + _uiState.update { it.copy(isLoading = false) } + _events.emit(ChatEvent.ShowError( + result.errors.firstOrNull()?.message ?: "Failed to load messages" + )) + } + is NetworkResult.Exception -> { + _uiState.update { it.copy(isLoading = false) } + _events.emit(ChatEvent.ShowError("Connection error")) + } + } + } + } + + fun loadMore() { + val state = _uiState.value + if (state.isLoading || !state.hasMore || state.messages.isEmpty()) return + + val oldestMessageId = state.messages.first().messageId + + viewModelScope.launch { + _uiState.update { it.copy(isLoading = true) } + when (val result = chatRepository.getChatHistory(state.chatId, beforeMessageId = oldestMessageId)) { + is NetworkResult.Success -> { + _uiState.update { + it.copy( + messages = result.data.data.items.reversed() + it.messages, + hasMore = result.data.data.hasMore, + isLoading = false + ) + } + } + is NetworkResult.Error -> { + _uiState.update { it.copy(isLoading = false) } + } + is NetworkResult.Exception -> { + _uiState.update { it.copy(isLoading = false) } + } + } + } + } + + fun saveScrollPosition(messageId: Int) { + val chatId = _uiState.value.chatId + if (chatId.isNotBlank()) { + sessionManager.saveLastReadMessageId(chatId, messageId.toString()) + } + } + + fun clearScrollTarget() { + _uiState.update { it.copy(scrollToMessageId = null) } + } + + override fun onCleared() { + super.onCleared() + sessionManager.saveDraft(chatId, _uiState.value.messageText) + } + + fun onMessageTextChange(text: String) { + _uiState.update { it.copy(messageText = text) } + } + + fun sendMessage() { + val state = _uiState.value + val text = state.messageText.trim() + if (text.isBlank() || state.isSending) return + + viewModelScope.launch { + _uiState.update { it.copy(isSending = true, messageText = "") } + when (val result = chatRepository.sendMessage(state.chatId, text)) { + is NetworkResult.Success -> { + sessionManager.saveDraft(chatId, "") + loadMessages() + } + is NetworkResult.Error -> { + _uiState.update { it.copy(isSending = false, messageText = text) } + _events.emit(ChatEvent.ShowError( + result.errors.firstOrNull()?.message ?: "Failed to send message" + )) + } + is NetworkResult.Exception -> { + _uiState.update { it.copy(isSending = false, messageText = text) } + _events.emit(ChatEvent.ShowError("Connection error")) + } + } + _uiState.update { it.copy(isSending = false) } + } + } +} diff --git a/app/src/main/java/org/yobble/messenger/presentation/common/FullScreenImageViewer.kt b/app/src/main/java/org/yobble/messenger/presentation/common/FullScreenImageViewer.kt new file mode 100644 index 0000000..6149515 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/presentation/common/FullScreenImageViewer.kt @@ -0,0 +1,88 @@ +package org.yobble.messenger.presentation.common + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.gestures.detectTransformGestures +import androidx.compose.foundation.layout.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Close +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import androidx.compose.ui.window.DialogProperties +import coil.compose.AsyncImage +import coil.request.ImageRequest + +@Composable +fun FullScreenImageViewer( + imageUrl: String, + onDismiss: () -> Unit +) { + var scale by remember { mutableFloatStateOf(1f) } + var offsetX by remember { mutableFloatStateOf(0f) } + var offsetY by remember { mutableFloatStateOf(0f) } + + Dialog( + onDismissRequest = onDismiss, + properties = DialogProperties(usePlatformDefaultWidth = false) + ) { + Box( + modifier = Modifier + .fillMaxSize() + .background(Color.Black) + .clickable(onClick = onDismiss) + ) { + AsyncImage( + model = ImageRequest.Builder(LocalContext.current) + .data(imageUrl) + .crossfade(true) + .build(), + contentDescription = "Avatar", + modifier = Modifier + .fillMaxSize() + .pointerInput(Unit) { + detectTransformGestures { _, pan, zoom, _ -> + scale = (scale * zoom).coerceIn(1f, 5f) + if (scale > 1f) { + offsetX += pan.x + offsetY += pan.y + } else { + offsetX = 0f + offsetY = 0f + } + } + } + .graphicsLayer( + scaleX = scale, + scaleY = scale, + translationX = offsetX, + translationY = offsetY + ), + contentScale = ContentScale.Fit + ) + + IconButton( + onClick = onDismiss, + modifier = Modifier + .align(Alignment.TopEnd) + .padding(16.dp) + .statusBarsPadding() + ) { + Icon( + Icons.Default.Close, + contentDescription = "Close", + tint = Color.White + ) + } + } + } +} diff --git a/app/src/main/java/org/yobble/messenger/presentation/common/UserAvatar.kt b/app/src/main/java/org/yobble/messenger/presentation/common/UserAvatar.kt new file mode 100644 index 0000000..489e0db --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/presentation/common/UserAvatar.kt @@ -0,0 +1,82 @@ +package org.yobble.messenger.presentation.common + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.TextUnit +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import coil.compose.SubcomposeAsyncImage +import coil.request.ImageRequest +import org.yobble.messenger.BuildConfig + +@Composable +fun UserAvatar( + userId: String?, + fileId: String?, + displayName: String, + size: Dp = 52.dp, + fontSize: TextUnit = 20.sp +) { + val avatarUrl = buildAvatarUrl(userId, fileId) + + if (avatarUrl != null) { + SubcomposeAsyncImage( + model = ImageRequest.Builder(LocalContext.current) + .data(avatarUrl) + .crossfade(true) + .build(), + contentDescription = "Avatar", + modifier = Modifier + .size(size) + .clip(CircleShape), + contentScale = ContentScale.Crop, + error = { + InitialsAvatar(displayName, size, fontSize) + }, + loading = { + InitialsAvatar(displayName, size, fontSize) + } + ) + } else { + InitialsAvatar(displayName, size, fontSize) + } +} + +@Composable +fun InitialsAvatar( + displayName: String, + size: Dp = 52.dp, + fontSize: TextUnit = 20.sp +) { + Box( + modifier = Modifier + .size(size) + .clip(CircleShape) + .background(MaterialTheme.colorScheme.primary), + contentAlignment = Alignment.Center + ) { + Text( + text = displayName.take(1).uppercase(), + color = MaterialTheme.colorScheme.onPrimary, + fontWeight = FontWeight.Bold, + fontSize = fontSize + ) + } +} + +fun buildAvatarUrl(userId: String?, fileId: String?): String? { + if (userId.isNullOrBlank() || fileId.isNullOrBlank()) return null + return "${BuildConfig.BASE_URL}v1/storage/download/avatar/$userId?file_id=$fileId" +} diff --git a/app/src/main/java/org/yobble/messenger/presentation/contacts/ContactsScreen.kt b/app/src/main/java/org/yobble/messenger/presentation/contacts/ContactsScreen.kt new file mode 100644 index 0000000..452f74a --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/presentation/contacts/ContactsScreen.kt @@ -0,0 +1,430 @@ +package org.yobble.messenger.presentation.contacts + +import androidx.compose.animation.core.Animatable +import androidx.compose.animation.core.tween +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.gestures.detectHorizontalDragGestures +import androidx.compose.foundation.layout.* +import androidx.compose.ui.draw.clipToBounds +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Delete +import androidx.compose.material.icons.filled.Edit +import androidx.compose.material.icons.filled.PersonAdd +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.launch +import org.yobble.messenger.data.remote.dto.ContactInfoDto +import org.yobble.messenger.presentation.common.UserAvatar +import kotlin.math.roundToInt + +@Composable +fun ContactsScreen( + onNavigateToChat: (chatId: String) -> Unit, + bottomPadding: androidx.compose.ui.unit.Dp, + viewModel: ContactsViewModel = hiltViewModel() +) { + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val snackbarHostState = remember { SnackbarHostState() } + + LaunchedEffect(Unit) { + viewModel.events.collectLatest { event -> + when (event) { + is ContactsEvent.ShowError -> snackbarHostState.showSnackbar(event.message) + is ContactsEvent.ShowSuccess -> snackbarHostState.showSnackbar(event.message) + is ContactsEvent.NavigateToChat -> onNavigateToChat(event.chatId) + } + } + } + + if (uiState.showAddDialog) { + AddContactDialog( + query = uiState.addContactQuery, + onQueryChange = viewModel::onAddContactQueryChange, + onAdd = viewModel::addContact, + onDismiss = viewModel::hideAddDialog, + isAdding = uiState.isAdding + ) + } + + if (uiState.showRenameDialog) { + RenameContactDialog( + currentName = uiState.renameQuery, + onNameChange = viewModel::onRenameQueryChange, + onSave = viewModel::saveRename, + onDismiss = viewModel::hideRenameDialog, + isSaving = uiState.isRenaming + ) + } + + Scaffold( + snackbarHost = { SnackbarHost(snackbarHostState) }, + floatingActionButton = { + FloatingActionButton( + onClick = viewModel::showAddDialog, + modifier = Modifier.padding(bottom = bottomPadding), + containerColor = MaterialTheme.colorScheme.primary, + contentColor = MaterialTheme.colorScheme.onPrimary + ) { + Icon(Icons.Default.PersonAdd, contentDescription = "Add contact") + } + } + ) { padding -> + if (uiState.isLoading && uiState.contacts.isEmpty()) { + Box( + modifier = Modifier + .fillMaxSize() + .padding(padding), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator(color = MaterialTheme.colorScheme.primary) + } + } else { + val listState = rememberLazyListState() + + val shouldLoadMore by remember { + derivedStateOf { + val lastVisible = listState.layoutInfo.visibleItemsInfo.lastOrNull()?.index ?: 0 + val totalItems = listState.layoutInfo.totalItemsCount + lastVisible >= totalItems - 3 && uiState.hasMore && !uiState.isLoading + } + } + LaunchedEffect(shouldLoadMore) { + if (shouldLoadMore) viewModel.loadMore() + } + + LazyColumn( + modifier = Modifier + .fillMaxSize() + .padding(padding), + state = listState, + contentPadding = PaddingValues(bottom = bottomPadding) + ) { + if (uiState.contacts.isEmpty() && !uiState.isLoading) { + item { + Box( + modifier = Modifier + .fillParentMaxSize(), + contentAlignment = Alignment.Center + ) { + Column(horizontalAlignment = Alignment.CenterHorizontally) { + Icon( + Icons.Default.PersonAdd, + contentDescription = null, + modifier = Modifier.size(48.dp), + tint = MaterialTheme.colorScheme.onSurfaceVariant + ) + Spacer(modifier = Modifier.height(8.dp)) + Text( + "No contacts yet", + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + Spacer(modifier = Modifier.height(4.dp)) + Text( + "Tap + to add someone", + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + } + } + } else { + items(uiState.contacts, key = { it.userId }) { contact -> + SwipeableContactItem( + contact = contact, + isCreatingChat = uiState.creatingChatForUserId == contact.userId, + onClick = { viewModel.createChatWithContact(contact.userId) }, + onRename = { viewModel.showRenameDialog(contact.userId, contact.customName ?: "") }, + onRemove = { viewModel.removeContact(contact.userId) } + ) + } + } + + if (uiState.isLoading && uiState.contacts.isNotEmpty()) { + item { + Box( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator( + modifier = Modifier.size(24.dp), + strokeWidth = 2.dp, + color = MaterialTheme.colorScheme.primary + ) + } + } + } + } + } + } +} + +@Composable +private fun SwipeableContactItem( + contact: ContactInfoDto, + isCreatingChat: Boolean, + onClick: () -> Unit, + onRename: () -> Unit, + onRemove: () -> Unit +) { + val coroutineScope = rememberCoroutineScope() + val offsetX = remember { Animatable(0f) } + val density = LocalDensity.current + val actionWidthPx = with(density) { 140.dp.toPx() } + + Box( + modifier = Modifier + .fillMaxWidth() + .clipToBounds() + ) { + // Action buttons behind + Row( + modifier = Modifier + .matchParentSize(), + horizontalArrangement = Arrangement.End + ) { + Box( + modifier = Modifier + .fillMaxHeight() + .width(70.dp) + .background(Color(0xFF5C6BC0)) + .clickable { + coroutineScope.launch { + offsetX.animateTo(0f, tween(200)) + } + onRename() + }, + contentAlignment = Alignment.Center + ) { + Icon( + Icons.Default.Edit, + contentDescription = "Rename", + tint = Color.White, + modifier = Modifier.size(22.dp) + ) + } + Box( + modifier = Modifier + .fillMaxHeight() + .width(70.dp) + .background(MaterialTheme.colorScheme.error) + .clickable { + coroutineScope.launch { + offsetX.animateTo(0f, tween(200)) + } + onRemove() + }, + contentAlignment = Alignment.Center + ) { + Icon( + Icons.Default.Delete, + contentDescription = "Remove", + tint = Color.White, + modifier = Modifier.size(22.dp) + ) + } + } + + // Foreground content + ContactItemContent( + contact = contact, + isCreatingChat = isCreatingChat, + onClick = onClick, + modifier = Modifier + .offset { IntOffset(offsetX.value.roundToInt(), 0) } + .pointerInput(Unit) { + detectHorizontalDragGestures( + onDragEnd = { + coroutineScope.launch { + val target = if (offsetX.value < -actionWidthPx / 2) -actionWidthPx else 0f + offsetX.animateTo(target, tween(200)) + } + }, + onHorizontalDrag = { change, dragAmount -> + change.consume() + coroutineScope.launch { + val newValue = (offsetX.value + dragAmount).coerceIn(-actionWidthPx, 0f) + offsetX.snapTo(newValue) + } + } + ) + } + ) + } + + HorizontalDivider( + modifier = Modifier.padding(start = 76.dp), + color = MaterialTheme.colorScheme.outlineVariant, + thickness = 0.5.dp + ) +} + +@Composable +private fun ContactItemContent( + contact: ContactInfoDto, + isCreatingChat: Boolean, + onClick: () -> Unit, + modifier: Modifier = Modifier +) { + val displayName = contact.customName + ?: contact.fullName + ?: contact.login?.let { "@$it" } + ?: "User" + + Row( + modifier = modifier + .fillMaxWidth() + .background(MaterialTheme.colorScheme.surface) + .clickable(enabled = !isCreatingChat, onClick = onClick) + .padding(horizontal = 16.dp, vertical = 10.dp), + verticalAlignment = Alignment.CenterVertically + ) { + UserAvatar( + userId = contact.userId, + fileId = null, + displayName = displayName, + size = 48.dp, + fontSize = 18.sp + ) + + Spacer(modifier = Modifier.width(12.dp)) + + Column(modifier = Modifier.weight(1f)) { + Text( + text = displayName, + style = MaterialTheme.typography.bodyLarge, + fontWeight = FontWeight.Medium, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + if (contact.login != null) { + Text( + text = "@${contact.login}", + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + maxLines = 1 + ) + } + } + + if (isCreatingChat) { + CircularProgressIndicator( + modifier = Modifier.size(24.dp), + strokeWidth = 2.dp, + color = MaterialTheme.colorScheme.primary + ) + } + } +} + +@Composable +private fun AddContactDialog( + query: String, + onQueryChange: (String) -> Unit, + onAdd: () -> Unit, + onDismiss: () -> Unit, + isAdding: Boolean +) { + AlertDialog( + onDismissRequest = onDismiss, + title = { Text("Add contact") }, + text = { + OutlinedTextField( + value = query, + onValueChange = onQueryChange, + label = { Text("Login") }, + placeholder = { Text("username") }, + singleLine = true, + modifier = Modifier.fillMaxWidth(), + shape = RoundedCornerShape(12.dp) + ) + }, + confirmButton = { + Button( + onClick = onAdd, + enabled = query.isNotBlank() && !isAdding + ) { + if (isAdding) { + CircularProgressIndicator( + modifier = Modifier.size(18.dp), + strokeWidth = 2.dp, + color = MaterialTheme.colorScheme.onPrimary + ) + } else { + Text("Add") + } + } + }, + dismissButton = { + TextButton(onClick = onDismiss) { + Text("Cancel") + } + } + ) +} + +@Composable +private fun RenameContactDialog( + currentName: String, + onNameChange: (String) -> Unit, + onSave: () -> Unit, + onDismiss: () -> Unit, + isSaving: Boolean +) { + AlertDialog( + onDismissRequest = onDismiss, + title = { Text("Rename contact") }, + text = { + OutlinedTextField( + value = currentName, + onValueChange = onNameChange, + label = { Text("Display name") }, + placeholder = { Text("Custom name") }, + singleLine = true, + modifier = Modifier.fillMaxWidth(), + shape = RoundedCornerShape(12.dp) + ) + }, + confirmButton = { + Button( + onClick = onSave, + enabled = !isSaving + ) { + if (isSaving) { + CircularProgressIndicator( + modifier = Modifier.size(18.dp), + strokeWidth = 2.dp, + color = MaterialTheme.colorScheme.onPrimary + ) + } else { + Text("Save") + } + } + }, + dismissButton = { + TextButton(onClick = onDismiss) { + Text("Cancel") + } + } + ) +} diff --git a/app/src/main/java/org/yobble/messenger/presentation/contacts/ContactsViewModel.kt b/app/src/main/java/org/yobble/messenger/presentation/contacts/ContactsViewModel.kt new file mode 100644 index 0000000..1dc1280 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/presentation/contacts/ContactsViewModel.kt @@ -0,0 +1,233 @@ +package org.yobble.messenger.presentation.contacts + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import org.yobble.messenger.data.remote.NetworkResult +import org.yobble.messenger.data.remote.dto.ContactCreateRequestDto +import org.yobble.messenger.data.remote.dto.ContactInfoDto +import org.yobble.messenger.data.remote.dto.ContactUpdateRequestDto +import org.yobble.messenger.domain.repository.ChatRepository +import org.yobble.messenger.domain.repository.UserRepository +import javax.inject.Inject + +data class ContactsUiState( + val contacts: List = emptyList(), + val isLoading: Boolean = false, + val hasMore: Boolean = false, + val addContactQuery: String = "", + val isAdding: Boolean = false, + val showAddDialog: Boolean = false, + val creatingChatForUserId: String? = null, + val showRenameDialog: Boolean = false, + val renameUserId: String? = null, + val renameQuery: String = "", + val isRenaming: Boolean = false +) + +sealed class ContactsEvent { + data class ShowError(val message: String) : ContactsEvent() + data class ShowSuccess(val message: String) : ContactsEvent() + data class NavigateToChat(val chatId: String) : ContactsEvent() +} + +@HiltViewModel +class ContactsViewModel @Inject constructor( + private val userRepository: UserRepository, + private val chatRepository: ChatRepository +) : ViewModel() { + + private val _uiState = MutableStateFlow(ContactsUiState()) + val uiState: StateFlow = _uiState.asStateFlow() + + private val _events = MutableSharedFlow() + val events: SharedFlow = _events.asSharedFlow() + + init { + loadContacts() + } + + fun loadContacts() { + viewModelScope.launch { + _uiState.update { it.copy(isLoading = true) } + when (val result = userRepository.getContacts()) { + is NetworkResult.Success -> { + _uiState.update { + it.copy( + contacts = result.data.data.items, + hasMore = result.data.data.hasMore, + isLoading = false + ) + } + } + is NetworkResult.Error -> { + _uiState.update { it.copy(isLoading = false) } + _events.emit(ContactsEvent.ShowError( + result.errors.firstOrNull()?.message ?: "Failed to load contacts" + )) + } + is NetworkResult.Exception -> { + _uiState.update { it.copy(isLoading = false) } + _events.emit(ContactsEvent.ShowError("Connection error")) + } + } + } + } + + fun loadMore() { + val state = _uiState.value + if (state.isLoading || !state.hasMore) return + + viewModelScope.launch { + _uiState.update { it.copy(isLoading = true) } + when (val result = userRepository.getContacts(offset = state.contacts.size)) { + is NetworkResult.Success -> { + _uiState.update { + it.copy( + contacts = it.contacts + result.data.data.items, + hasMore = result.data.data.hasMore, + isLoading = false + ) + } + } + is NetworkResult.Error -> _uiState.update { it.copy(isLoading = false) } + is NetworkResult.Exception -> _uiState.update { it.copy(isLoading = false) } + } + } + } + + fun showAddDialog() { + _uiState.update { it.copy(showAddDialog = true, addContactQuery = "") } + } + + fun hideAddDialog() { + _uiState.update { it.copy(showAddDialog = false) } + } + + fun onAddContactQueryChange(value: String) { + _uiState.update { it.copy(addContactQuery = value) } + } + + fun addContact() { + val query = _uiState.value.addContactQuery.trim() + if (query.isBlank() || _uiState.value.isAdding) return + + val request = if (query.startsWith("@")) { + ContactCreateRequestDto(login = query.removePrefix("@")) + } else { + ContactCreateRequestDto(login = query) + } + + viewModelScope.launch { + _uiState.update { it.copy(isAdding = true) } + when (val result = userRepository.addContact(request)) { + is NetworkResult.Success -> { + _uiState.update { it.copy(isAdding = false, showAddDialog = false) } + _events.emit(ContactsEvent.ShowSuccess("Contact added")) + loadContacts() + } + is NetworkResult.Error -> { + _uiState.update { it.copy(isAdding = false) } + _events.emit(ContactsEvent.ShowError( + result.errors.firstOrNull()?.message ?: "Failed to add contact" + )) + } + is NetworkResult.Exception -> { + _uiState.update { it.copy(isAdding = false) } + _events.emit(ContactsEvent.ShowError("Connection error")) + } + } + } + } + + fun removeContact(userId: String) { + viewModelScope.launch { + when (val result = userRepository.removeContact(userId)) { + is NetworkResult.Success -> { + _events.emit(ContactsEvent.ShowSuccess("Contact removed")) + loadContacts() + } + is NetworkResult.Error -> { + _events.emit(ContactsEvent.ShowError( + result.errors.firstOrNull()?.message ?: "Failed to remove contact" + )) + } + is NetworkResult.Exception -> { + _events.emit(ContactsEvent.ShowError("Connection error")) + } + } + } + } + + fun showRenameDialog(userId: String, currentName: String) { + _uiState.update { it.copy(showRenameDialog = true, renameUserId = userId, renameQuery = currentName) } + } + + fun hideRenameDialog() { + _uiState.update { it.copy(showRenameDialog = false, renameUserId = null) } + } + + fun onRenameQueryChange(value: String) { + _uiState.update { it.copy(renameQuery = value) } + } + + fun saveRename() { + val userId = _uiState.value.renameUserId ?: return + val name = _uiState.value.renameQuery.trim() + if (_uiState.value.isRenaming) return + + viewModelScope.launch { + _uiState.update { it.copy(isRenaming = true) } + when (val result = userRepository.updateContact( + ContactUpdateRequestDto(userId, name.ifBlank { null }) + )) { + is NetworkResult.Success -> { + _uiState.update { it.copy(isRenaming = false, showRenameDialog = false, renameUserId = null) } + _events.emit(ContactsEvent.ShowSuccess("Contact updated")) + loadContacts() + } + is NetworkResult.Error -> { + _uiState.update { it.copy(isRenaming = false) } + _events.emit(ContactsEvent.ShowError( + result.errors.firstOrNull()?.message ?: "Failed to update contact" + )) + } + is NetworkResult.Exception -> { + _uiState.update { it.copy(isRenaming = false) } + _events.emit(ContactsEvent.ShowError("Connection error")) + } + } + } + } + + fun createChatWithContact(userId: String) { + if (_uiState.value.creatingChatForUserId != null) return + viewModelScope.launch { + _uiState.update { it.copy(creatingChatForUserId = userId) } + when (val result = chatRepository.createChat(userId)) { + is NetworkResult.Success -> { + _uiState.update { it.copy(creatingChatForUserId = null) } + _events.emit(ContactsEvent.NavigateToChat(result.data.data.chatId)) + } + is NetworkResult.Error -> { + _uiState.update { it.copy(creatingChatForUserId = null) } + _events.emit(ContactsEvent.ShowError( + result.errors.firstOrNull()?.message ?: "Failed to create chat" + )) + } + is NetworkResult.Exception -> { + _uiState.update { it.copy(creatingChatForUserId = null) } + _events.emit(ContactsEvent.ShowError("Connection error")) + } + } + } + } +} diff --git a/app/src/main/java/org/yobble/messenger/presentation/main/HomeScreen.kt b/app/src/main/java/org/yobble/messenger/presentation/main/HomeScreen.kt new file mode 100644 index 0000000..4c1f119 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/presentation/main/HomeScreen.kt @@ -0,0 +1,448 @@ +package org.yobble.messenger.presentation.main + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.pager.HorizontalPager +import androidx.compose.foundation.pager.rememberPagerState +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.Chat +import androidx.compose.material.icons.filled.Contacts +import androidx.compose.material.icons.filled.Person +import androidx.compose.material.icons.filled.Search +import androidx.compose.material.icons.filled.Settings +import androidx.compose.material.icons.filled.Star +import androidx.compose.material.icons.filled.Verified +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.lifecycle.compose.LifecycleResumeEffect +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.launch +import org.yobble.messenger.data.remote.dto.PrivateChatListItemDto +import org.yobble.messenger.presentation.common.UserAvatar +import org.yobble.messenger.presentation.contacts.ContactsScreen +import org.yobble.messenger.presentation.profile.ProfileScreen +import org.yobble.messenger.presentation.settings.SettingsScreen +import org.yobble.messenger.util.formatUtcToLocalTime + +private const val SWIPE_NAVIGATION_ENABLED = true + +private enum class HomeTab(val label: String, val icon: ImageVector) { + CHATS("Chats", Icons.AutoMirrored.Filled.Chat), + CONTACTS("Contacts", Icons.Default.Contacts), + SETTINGS("Settings", Icons.Default.Settings), + PROFILE("Profile", Icons.Default.Person) +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun HomeScreen( + onNavigateToChat: (chatId: String) -> Unit, + onNavigateToPrivacy: () -> Unit, + onNavigateToSessions: () -> Unit, + onNavigateToChangePassword: () -> Unit, + onNavigateToBlacklist: () -> Unit, + onNavigateToUserProfile: (userId: String) -> Unit = {}, + onNavigateToSearch: () -> Unit, + onLogout: () -> Unit, + viewModel: HomeViewModel = hiltViewModel() +) { + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val snackbarHostState = remember { SnackbarHostState() } + val tabs = HomeTab.entries + val pagerState = rememberPagerState(pageCount = { tabs.size }) + val coroutineScope = rememberCoroutineScope() + val selectedTab = pagerState.currentPage + val density = LocalDensity.current + var navBarHeightDp by remember { mutableStateOf(0.dp) } + + LifecycleResumeEffect(Unit) { + viewModel.loadChats() + onPauseOrDispose { } + } + + LaunchedEffect(Unit) { + viewModel.events.collectLatest { event -> + when (event) { + is HomeEvent.ShowError -> snackbarHostState.showSnackbar(event.message) + } + } + } + + Scaffold( + snackbarHost = { + SnackbarHost( + hostState = snackbarHostState, + modifier = Modifier.padding(bottom = navBarHeightDp) + ) + }, + topBar = { + TopAppBar( + title = { + Text( + tabs[selectedTab].label, + fontWeight = FontWeight.Bold + ) + }, + actions = { + IconButton(onClick = onNavigateToSearch) { + Icon(Icons.Default.Search, contentDescription = "Search") + } + }, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = MaterialTheme.colorScheme.primary, + titleContentColor = MaterialTheme.colorScheme.onPrimary, + actionIconContentColor = MaterialTheme.colorScheme.onPrimary + ) + ) + }, + contentWindowInsets = WindowInsets(0) + ) { padding -> + Box( + modifier = Modifier + .fillMaxSize() + .padding(padding) + ) { + if (SWIPE_NAVIGATION_ENABLED) { + HorizontalPager( + state = pagerState, + modifier = Modifier.fillMaxSize(), + beyondViewportPageCount = 1 + ) { page -> + TabContent( + tab = tabs[page], + uiState = uiState, + onNavigateToChat = onNavigateToChat, + onLoadMore = viewModel::loadMore, + onNavigateToPrivacy = onNavigateToPrivacy, + onNavigateToSessions = onNavigateToSessions, + onNavigateToChangePassword = onNavigateToChangePassword, + onNavigateToBlacklist = onNavigateToBlacklist, + onNavigateToUserProfile = onNavigateToUserProfile, + onLogout = { + viewModel.logout() + onLogout() + }, + bottomPadding = navBarHeightDp + ) + } + } else { + TabContent( + tab = tabs[selectedTab], + uiState = uiState, + onNavigateToChat = onNavigateToChat, + onLoadMore = viewModel::loadMore, + onNavigateToPrivacy = onNavigateToPrivacy, + onNavigateToSessions = onNavigateToSessions, + onNavigateToChangePassword = onNavigateToChangePassword, + onNavigateToBlacklist = onNavigateToBlacklist, + onNavigateToUserProfile = onNavigateToUserProfile, + onLogout = { + viewModel.logout() + onLogout() + }, + bottomPadding = navBarHeightDp + ) + } + + // Floating bottom navigation bar + NavigationBar( + modifier = Modifier + .align(Alignment.BottomCenter) + .onGloballyPositioned { coordinates -> + val heightPx = coordinates.size.height + navBarHeightDp = with(density) { heightPx.toDp() } + } + .padding(horizontal = 16.dp, vertical = 12.dp) + .clip(RoundedCornerShape(24.dp)) + .navigationBarsPadding(), + containerColor = MaterialTheme.colorScheme.surface.copy(alpha = 0.85f), + tonalElevation = 8.dp + ) { + tabs.forEachIndexed { index, tab -> + NavigationBarItem( + selected = selectedTab == index, + onClick = { + coroutineScope.launch { + if (SWIPE_NAVIGATION_ENABLED) { + pagerState.animateScrollToPage(index) + } else { + pagerState.scrollToPage(index) + } + } + }, + icon = { Icon(tab.icon, contentDescription = null) }, + label = { Text(tab.label, fontSize = 11.sp) }, + colors = NavigationBarItemDefaults.colors( + indicatorColor = MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.6f) + ) + ) + } + } + } + } +} + +@Composable +private fun TabContent( + tab: HomeTab, + uiState: HomeUiState, + onNavigateToChat: (String) -> Unit, + onLoadMore: () -> Unit, + onNavigateToPrivacy: () -> Unit, + onNavigateToSessions: () -> Unit, + onNavigateToChangePassword: () -> Unit, + onNavigateToBlacklist: () -> Unit, + onNavigateToUserProfile: (String) -> Unit, + onLogout: () -> Unit, + bottomPadding: androidx.compose.ui.unit.Dp +) { + when (tab) { + HomeTab.CHATS -> ChatsContent( + uiState = uiState, + onNavigateToChat = onNavigateToChat, + onLoadMore = onLoadMore, + bottomPadding = bottomPadding + ) + HomeTab.CONTACTS -> ContactsScreen( + onNavigateToChat = onNavigateToChat, + bottomPadding = bottomPadding + ) + HomeTab.SETTINGS -> SettingsScreen( + onNavigateToPrivacy = onNavigateToPrivacy, + onNavigateToSessions = onNavigateToSessions, + onNavigateToChangePassword = onNavigateToChangePassword, + onNavigateToBlacklist = onNavigateToBlacklist, + onLogout = onLogout, + bottomPadding = bottomPadding + ) + HomeTab.PROFILE -> ProfileScreen( + onNavigateBack = { /* already on home, no-op */ }, + onNavigateToChat = onNavigateToChat, + showTopBar = false, + bottomPadding = bottomPadding + ) + } +} + +@Composable +private fun ChatsContent( + uiState: HomeUiState, + onNavigateToChat: (String) -> Unit, + onLoadMore: () -> Unit, + bottomPadding: androidx.compose.ui.unit.Dp +) { + if (uiState.isLoading && uiState.chats.isEmpty()) { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator(color = MaterialTheme.colorScheme.primary) + } + } else if (uiState.chats.isEmpty()) { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + Column(horizontalAlignment = Alignment.CenterHorizontally) { + Text( + "No chats yet", + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + Spacer(modifier = Modifier.height(8.dp)) + Text( + "Start a new conversation", + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + } + } else { + val listState = rememberLazyListState() + + val shouldLoadMore by remember { + derivedStateOf { + val lastVisible = listState.layoutInfo.visibleItemsInfo.lastOrNull()?.index ?: 0 + val totalItems = listState.layoutInfo.totalItemsCount + lastVisible >= totalItems - 3 && uiState.hasMore && !uiState.isLoading + } + } + LaunchedEffect(shouldLoadMore) { + if (shouldLoadMore) onLoadMore() + } + + LazyColumn( + modifier = Modifier.fillMaxSize(), + state = listState, + contentPadding = PaddingValues(bottom = bottomPadding) + ) { + items(uiState.chats, key = { it.chatId }) { chat -> + ChatListItem( + chat = chat, + onClick = { onNavigateToChat(chat.chatId) } + ) + } + if (uiState.isLoading && uiState.chats.isNotEmpty()) { + item { + Box( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator( + modifier = Modifier.size(24.dp), + strokeWidth = 2.dp, + color = MaterialTheme.colorScheme.primary + ) + } + } + } + } + } +} + +@Composable +private fun ChatListItem( + chat: PrivateChatListItemDto, + onClick: () -> Unit +) { + val chatData = chat.chatData + val displayName = chatData?.customName + ?: chatData?.fullName + ?: chatData?.login?.let { "@$it" } + ?: chat.chatType.replaceFirstChar { it.uppercase() } + val isVerified = chatData?.isVerified == true + val rating = chatData?.rating?.rating + val lastMessageText = chat.lastMessage?.content ?: "" + val time = formatUtcToLocalTime(chat.lastMessage?.createdAt) + + Row( + modifier = Modifier + .fillMaxWidth() + .clickable(onClick = onClick) + .padding(horizontal = 16.dp, vertical = 12.dp), + verticalAlignment = Alignment.CenterVertically + ) { + UserAvatar( + userId = chatData?.userId, + fileId = chatData?.avatars?.current?.fileId, + displayName = displayName + ) + + Spacer(modifier = Modifier.width(12.dp)) + + Column(modifier = Modifier.weight(1f)) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Row( + modifier = Modifier.weight(1f), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = displayName, + style = MaterialTheme.typography.bodyLarge, + fontWeight = FontWeight.Medium, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + modifier = Modifier.weight(1f, fill = false) + ) + if (isVerified) { + Spacer(modifier = Modifier.width(4.dp)) + Icon( + Icons.Default.Verified, + contentDescription = "Verified", + tint = MaterialTheme.colorScheme.primary, + modifier = Modifier.size(16.dp) + ) + } + if (rating != null) { + Spacer(modifier = Modifier.width(6.dp)) + Icon( + Icons.Default.Star, + contentDescription = "Rating", + tint = Color(0xFFFFC107), + modifier = Modifier.size(14.dp) + ) + Text( + text = String.format("%.1f", rating), + fontSize = 12.sp, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + } + Spacer(modifier = Modifier.width(8.dp)) + Text( + text = time, + style = MaterialTheme.typography.bodySmall, + color = if (chat.unreadCount > 0) + MaterialTheme.colorScheme.primary + else + MaterialTheme.colorScheme.onSurfaceVariant + ) + } + + Spacer(modifier = Modifier.height(4.dp)) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = lastMessageText, + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + modifier = Modifier.weight(1f) + ) + if (chat.unreadCount > 0) { + Spacer(modifier = Modifier.width(8.dp)) + Box( + modifier = Modifier + .clip(CircleShape) + .background(MaterialTheme.colorScheme.primary) + .padding(horizontal = 6.dp, vertical = 2.dp), + contentAlignment = Alignment.Center + ) { + Text( + text = if (chat.unreadCount > 99) "99+" else chat.unreadCount.toString(), + color = MaterialTheme.colorScheme.onPrimary, + fontSize = 12.sp, + fontWeight = FontWeight.Bold + ) + } + } + } + } + } + + HorizontalDivider( + modifier = Modifier.padding(start = 80.dp), + color = MaterialTheme.colorScheme.outlineVariant, + thickness = 0.5.dp + ) +} diff --git a/app/src/main/java/org/yobble/messenger/presentation/main/HomeViewModel.kt b/app/src/main/java/org/yobble/messenger/presentation/main/HomeViewModel.kt new file mode 100644 index 0000000..e0b247d --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/presentation/main/HomeViewModel.kt @@ -0,0 +1,132 @@ +package org.yobble.messenger.presentation.main + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import org.yobble.messenger.data.remote.NetworkResult +import org.yobble.messenger.data.remote.dto.PrivateChatListItemDto +import org.yobble.messenger.data.remote.socket.SocketEvent +import org.yobble.messenger.data.remote.socket.SocketManager +import org.yobble.messenger.domain.repository.AuthRepository +import org.yobble.messenger.domain.repository.ChatRepository +import javax.inject.Inject + +data class HomeUiState( + val chats: List = emptyList(), + val isLoading: Boolean = false, + val hasMore: Boolean = false +) + +sealed class HomeEvent { + data class ShowError(val message: String) : HomeEvent() +} + +@HiltViewModel +class HomeViewModel @Inject constructor( + private val chatRepository: ChatRepository, + private val authRepository: AuthRepository, + private val socketManager: SocketManager +) : ViewModel() { + + private val _uiState = MutableStateFlow(HomeUiState()) + val uiState: StateFlow = _uiState.asStateFlow() + + private val _events = MutableSharedFlow() + val events: SharedFlow = _events.asSharedFlow() + + private var refreshJob: Job? = null + + init { + socketManager.connect() + loadChats() + observeSocket() + } + + private fun observeSocket() { + viewModelScope.launch { + socketManager.events.collect { event -> + when (event) { + is SocketEvent.NewMessage -> debouncedRefresh() + is SocketEvent.Connected -> loadChats() + is SocketEvent.Disconnected -> {} + } + } + } + } + + private fun debouncedRefresh() { + refreshJob?.cancel() + refreshJob = viewModelScope.launch { + delay(300) + loadChats() + } + } + + fun loadChats() { + viewModelScope.launch { + _uiState.update { it.copy(isLoading = true) } + when (val result = chatRepository.getChatList()) { + is NetworkResult.Success -> { + _uiState.update { + it.copy( + chats = result.data.data.items, + hasMore = result.data.data.hasMore, + isLoading = false + ) + } + } + is NetworkResult.Error -> { + _uiState.update { it.copy(isLoading = false) } + _events.emit(HomeEvent.ShowError( + result.errors.firstOrNull()?.message ?: "Failed to load chats" + )) + } + is NetworkResult.Exception -> { + _uiState.update { it.copy(isLoading = false) } + _events.emit(HomeEvent.ShowError("Connection error")) + } + } + } + } + + fun loadMore() { + val state = _uiState.value + if (state.isLoading || !state.hasMore) return + + viewModelScope.launch { + _uiState.update { it.copy(isLoading = true) } + when (val result = chatRepository.getChatList(offset = state.chats.size)) { + is NetworkResult.Success -> { + _uiState.update { + it.copy( + chats = it.chats + result.data.data.items, + hasMore = result.data.data.hasMore, + isLoading = false + ) + } + } + is NetworkResult.Error -> { + _uiState.update { it.copy(isLoading = false) } + } + is NetworkResult.Exception -> { + _uiState.update { it.copy(isLoading = false) } + } + } + } + } + + fun logout() { + socketManager.disconnect() + authRepository.logout() + } +} diff --git a/app/src/main/java/org/yobble/messenger/presentation/navigation/AppNavGraph.kt b/app/src/main/java/org/yobble/messenger/presentation/navigation/AppNavGraph.kt new file mode 100644 index 0000000..667bbfa --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/presentation/navigation/AppNavGraph.kt @@ -0,0 +1,174 @@ +package org.yobble.messenger.presentation.navigation + +import androidx.compose.runtime.Composable +import androidx.navigation.NavHostController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import org.yobble.messenger.presentation.auth.code.CodeVerificationScreen +import org.yobble.messenger.presentation.auth.login.LoginScreen +import org.yobble.messenger.presentation.auth.register.RegisterScreen +import org.yobble.messenger.presentation.chat.ChatScreen +import org.yobble.messenger.presentation.main.HomeScreen +import org.yobble.messenger.presentation.profile.ProfileScreen +import org.yobble.messenger.presentation.search.SearchScreen +import org.yobble.messenger.presentation.settings.BlacklistScreen +import org.yobble.messenger.presentation.settings.ChangePasswordScreen +import org.yobble.messenger.presentation.settings.PrivacyScreen +import org.yobble.messenger.presentation.settings.SessionsScreen + +object Routes { + const val LOGIN = "login" + const val REGISTER = "register" + const val CODE_VERIFICATION = "code_verification/{login}" + const val HOME = "home" + const val CHAT = "chat/{chatId}" + const val USER_PROFILE = "profile/{userId}" + const val PRIVACY = "settings/privacy" + const val SESSIONS = "settings/sessions" + const val CHANGE_PASSWORD = "settings/change_password" + const val BLACKLIST = "settings/blacklist" + const val SEARCH = "search" + + fun codeVerification(login: String) = "code_verification/$login" + fun chat(chatId: String) = "chat/$chatId" + fun userProfile(userId: String) = "profile/$userId" +} + +@Composable +fun AppNavGraph( + navController: NavHostController, + startDestination: String +) { + NavHost( + navController = navController, + startDestination = startDestination + ) { + composable(Routes.LOGIN) { + LoginScreen( + onNavigateToRegister = { + navController.navigate(Routes.REGISTER) + }, + onNavigateToCodeLogin = { login -> + navController.navigate(Routes.codeVerification(login)) + }, + onLoginSuccess = { + navController.navigate(Routes.HOME) { + popUpTo(Routes.LOGIN) { inclusive = true } + } + } + ) + } + composable(Routes.REGISTER) { + RegisterScreen( + onNavigateBack = { + navController.popBackStack() + }, + onRegisterSuccess = { + navController.popBackStack(Routes.LOGIN, false) + } + ) + } + composable(Routes.CODE_VERIFICATION) { backStackEntry -> + val login = backStackEntry.arguments?.getString("login") ?: "" + CodeVerificationScreen( + login = login, + onNavigateBack = { + navController.popBackStack() + }, + onVerifySuccess = { + navController.navigate(Routes.HOME) { + popUpTo(Routes.LOGIN) { inclusive = true } + } + } + ) + } + composable(Routes.HOME) { + HomeScreen( + onNavigateToChat = { chatId -> + navController.navigate(Routes.chat(chatId)) + }, + onNavigateToPrivacy = { + navController.navigate(Routes.PRIVACY) + }, + onNavigateToSessions = { + navController.navigate(Routes.SESSIONS) + }, + onNavigateToChangePassword = { + navController.navigate(Routes.CHANGE_PASSWORD) + }, + onNavigateToBlacklist = { + navController.navigate(Routes.BLACKLIST) + }, + onNavigateToUserProfile = { userId -> + navController.navigate(Routes.userProfile(userId)) + }, + onNavigateToSearch = { + navController.navigate(Routes.SEARCH) + }, + onLogout = { + navController.navigate(Routes.LOGIN) { + popUpTo(Routes.HOME) { inclusive = true } + } + } + ) + } + composable(Routes.USER_PROFILE) { + ProfileScreen( + onNavigateBack = { + navController.popBackStack() + }, + onNavigateToChat = { chatId -> + navController.navigate(Routes.chat(chatId)) + } + ) + } + composable(Routes.CHAT) { + ChatScreen( + onNavigateBack = { + navController.popBackStack() + }, + onNavigateToProfile = { userId -> + navController.navigate(Routes.userProfile(userId)) + } + ) + } + composable(Routes.PRIVACY) { + PrivacyScreen( + onNavigateBack = { + navController.popBackStack() + } + ) + } + composable(Routes.SESSIONS) { + SessionsScreen( + onNavigateBack = { + navController.popBackStack() + } + ) + } + composable(Routes.CHANGE_PASSWORD) { + ChangePasswordScreen( + onNavigateBack = { + navController.popBackStack() + } + ) + } + composable(Routes.BLACKLIST) { + BlacklistScreen( + onNavigateBack = { + navController.popBackStack() + } + ) + } + composable(Routes.SEARCH) { + SearchScreen( + onNavigateBack = { + navController.popBackStack() + }, + onNavigateToProfile = { userId -> + navController.navigate(Routes.userProfile(userId)) + } + ) + } + } +} diff --git a/app/src/main/java/org/yobble/messenger/presentation/profile/ProfileScreen.kt b/app/src/main/java/org/yobble/messenger/presentation/profile/ProfileScreen.kt new file mode 100644 index 0000000..5990334 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/presentation/profile/ProfileScreen.kt @@ -0,0 +1,449 @@ +package org.yobble.messenger.presentation.profile + +import android.net.Uri +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.automirrored.filled.Chat +import androidx.compose.material.icons.filled.CameraAlt +import androidx.compose.material.icons.filled.Edit +import androidx.compose.material.icons.filled.Star +import androidx.compose.material.icons.filled.Verified +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import kotlinx.coroutines.flow.collectLatest +import org.yobble.messenger.presentation.common.FullScreenImageViewer +import org.yobble.messenger.presentation.common.UserAvatar +import org.yobble.messenger.presentation.common.buildAvatarUrl +import java.io.File + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun ProfileScreen( + onNavigateBack: () -> Unit, + onNavigateToChat: ((chatId: String) -> Unit)? = null, + showTopBar: Boolean = true, + bottomPadding: Dp = 0.dp, + viewModel: ProfileViewModel = hiltViewModel() +) { + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val snackbarHostState = remember { SnackbarHostState() } + + LaunchedEffect(Unit) { + viewModel.events.collectLatest { event -> + when (event) { + is ProfileEvent.ShowError -> snackbarHostState.showSnackbar(event.message) + is ProfileEvent.ShowSuccess -> snackbarHostState.showSnackbar(event.message) + is ProfileEvent.NavigateToChat -> onNavigateToChat?.invoke(event.chatId) + } + } + } + + Scaffold( + snackbarHost = { SnackbarHost(snackbarHostState) }, + topBar = { + if (showTopBar) { + TopAppBar( + title = { Text("Profile", fontWeight = FontWeight.Bold) }, + navigationIcon = { + IconButton(onClick = onNavigateBack) { + Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back") + } + }, + actions = { + if (uiState.isMyProfile && !uiState.isEditing && uiState.profile != null) { + IconButton(onClick = viewModel::startEditing) { + Icon(Icons.Default.Edit, contentDescription = "Edit") + } + } + }, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = MaterialTheme.colorScheme.primary, + titleContentColor = MaterialTheme.colorScheme.onPrimary, + navigationIconContentColor = MaterialTheme.colorScheme.onPrimary, + actionIconContentColor = MaterialTheme.colorScheme.onPrimary + ) + ) + } + } + ) { padding -> + if (uiState.isLoading && uiState.profile == null) { + Box( + modifier = Modifier + .fillMaxSize() + .padding(padding), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator(color = MaterialTheme.colorScheme.primary) + } + } else { + val profile = uiState.profile ?: return@Scaffold + + Column( + modifier = Modifier + .fillMaxSize() + .padding(padding) + .verticalScroll(rememberScrollState()), + horizontalAlignment = Alignment.CenterHorizontally + ) { + val context = LocalContext.current + val allowedMimeTypes = setOf("image/jpeg", "image/png", "image/heic", "image/heif", "image/gif") + val imagePicker = rememberLauncherForActivityResult( + contract = ActivityResultContracts.GetContent() + ) { uri: Uri? -> + uri ?: return@rememberLauncherForActivityResult + val mimeType = context.contentResolver.getType(uri) ?: "image/jpeg" + if (mimeType !in allowedMimeTypes) { + return@rememberLauncherForActivityResult + } + val ext = when (mimeType) { + "image/png" -> "png" + "image/gif" -> "gif" + "image/heic" -> "heic" + "image/heif" -> "heif" + else -> "jpg" + } + val inputStream = context.contentResolver.openInputStream(uri) ?: return@rememberLauncherForActivityResult + val tempFile = File(context.cacheDir, "avatar_upload.$ext") + tempFile.outputStream().use { out -> inputStream.copyTo(out) } + viewModel.uploadAvatar(tempFile, mimeType) + } + + val avatarUrl = buildAvatarUrl(profile.userId, profile.avatarFileId) + var showFullScreenAvatar by remember { mutableStateOf(false) } + + if (showFullScreenAvatar && avatarUrl != null) { + FullScreenImageViewer( + imageUrl = avatarUrl, + onDismiss = { showFullScreenAvatar = false } + ) + } + + Spacer(modifier = Modifier.height(24.dp)) + + // Avatar + Box(contentAlignment = Alignment.BottomEnd) { + Box( + modifier = Modifier.clickable(enabled = avatarUrl != null) { + showFullScreenAvatar = true + } + ) { + UserAvatar( + userId = profile.userId, + fileId = profile.avatarFileId, + displayName = profile.displayName, + size = 100.dp, + fontSize = 40.sp + ) + } + if (uiState.isMyProfile) { + Box( + modifier = Modifier + .size(32.dp) + .clip(CircleShape) + .background(MaterialTheme.colorScheme.primary) + .clickable { imagePicker.launch("image/*") }, + contentAlignment = Alignment.Center + ) { + if (uiState.isUploading) { + CircularProgressIndicator( + modifier = Modifier.size(16.dp), + strokeWidth = 2.dp, + color = MaterialTheme.colorScheme.onPrimary + ) + } else { + Icon( + Icons.Default.CameraAlt, + contentDescription = "Change avatar", + tint = MaterialTheme.colorScheme.onPrimary, + modifier = Modifier.size(16.dp) + ) + } + } + } + } + + Spacer(modifier = Modifier.height(16.dp)) + + // Name + verified + Row(verticalAlignment = Alignment.CenterVertically) { + Text( + text = profile.displayName, + style = MaterialTheme.typography.headlineSmall, + fontWeight = FontWeight.Bold + ) + if (profile.isVerified) { + Spacer(modifier = Modifier.width(6.dp)) + Icon( + Icons.Default.Verified, + contentDescription = "Verified", + tint = MaterialTheme.colorScheme.primary, + modifier = Modifier.size(22.dp) + ) + } + } + + // Login + if (profile.login.isNotBlank()) { + Text( + text = "@${profile.login}", + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + + // Rating + if (profile.rating != null) { + Spacer(modifier = Modifier.height(8.dp)) + Row(verticalAlignment = Alignment.CenterVertically) { + Icon( + Icons.Default.Star, + contentDescription = "Rating", + tint = Color(0xFFFFC107), + modifier = Modifier.size(20.dp) + ) + Spacer(modifier = Modifier.width(4.dp)) + Text( + text = String.format("%.1f", profile.rating), + style = MaterialTheme.typography.bodyLarge, + fontWeight = FontWeight.Medium + ) + } + } + + if (!showTopBar && uiState.isMyProfile && !uiState.isEditing && uiState.profile != null) { + Spacer(modifier = Modifier.height(12.dp)) + OutlinedButton(onClick = viewModel::startEditing) { + Icon(Icons.Default.Edit, contentDescription = null, modifier = Modifier.size(16.dp)) + Spacer(modifier = Modifier.width(6.dp)) + Text("Edit profile") + } + } + + if (!uiState.isMyProfile && profile.canSendMessage && onNavigateToChat != null) { + Spacer(modifier = Modifier.height(12.dp)) + Button( + onClick = viewModel::createChat, + enabled = !uiState.isCreatingChat + ) { + if (uiState.isCreatingChat) { + CircularProgressIndicator( + modifier = Modifier.size(18.dp), + strokeWidth = 2.dp, + color = MaterialTheme.colorScheme.onPrimary + ) + } else { + Icon(Icons.AutoMirrored.Filled.Chat, contentDescription = null, modifier = Modifier.size(18.dp)) + Spacer(modifier = Modifier.width(8.dp)) + Text("Send message") + } + } + } + + Spacer(modifier = Modifier.height(24.dp)) + + if (uiState.isEditing) { + EditProfileSection( + fullName = uiState.editFullName, + bio = uiState.editBio, + onFullNameChange = viewModel::onFullNameChange, + onBioChange = viewModel::onBioChange, + onSave = viewModel::saveProfile, + onCancel = viewModel::cancelEditing, + isSaving = uiState.isSaving, + canSave = uiState.editBio.length <= 1024 + ) + } else { + ProfileInfoSection( + profile = profile, + isMyProfile = uiState.isMyProfile + ) + } + + Spacer(modifier = Modifier.height(24.dp + bottomPadding)) + } + } + } +} + +@Composable +private fun ProfileInfoSection( + profile: ProfileInfo, + isMyProfile: Boolean +) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp) + ) { + if (!profile.bio.isNullOrBlank()) { + ProfileInfoCard(label = "Bio", value = profile.bio) + Spacer(modifier = Modifier.height(12.dp)) + } + + ProfileInfoCard( + label = "Member since", + value = formatUtcToLocalDate(profile.createdAt) + ) + + if (isMyProfile && profile.balances.isNotEmpty()) { + Spacer(modifier = Modifier.height(12.dp)) + ProfileInfoCard( + label = "Balance", + value = profile.balances.joinToString("\n") { + "${it.displayBalance ?: it.balance} ${it.currency.uppercase()}" + } + ) + } + + if (!isMyProfile) { + val rel = profile.relationship + if (rel != null) { + Spacer(modifier = Modifier.height(12.dp)) + if (rel.isTargetInContacts) { + ProfileInfoCard(label = "Contact", value = "In your contacts") + } + if (rel.isTargetBlocked) { + ProfileInfoCard(label = "Blocked", value = "You blocked this user") + } + } + } + } +} + +@Composable +private fun ProfileInfoCard(label: String, value: String) { + Card( + modifier = Modifier.fillMaxWidth(), + colors = CardDefaults.cardColors( + containerColor = MaterialTheme.colorScheme.surfaceVariant + ), + shape = RoundedCornerShape(12.dp) + ) { + Column(modifier = Modifier.padding(16.dp)) { + Text( + text = label, + style = MaterialTheme.typography.labelMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + Spacer(modifier = Modifier.height(4.dp)) + Text( + text = value, + style = MaterialTheme.typography.bodyLarge + ) + } + } +} + +@Composable +private fun EditProfileSection( + fullName: String, + bio: String, + onFullNameChange: (String) -> Unit, + onBioChange: (String) -> Unit, + onSave: () -> Unit, + onCancel: () -> Unit, + isSaving: Boolean, + canSave: Boolean +) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp) + ) { + OutlinedTextField( + value = fullName, + onValueChange = onFullNameChange, + label = { Text("Full name") }, + modifier = Modifier.fillMaxWidth(), + singleLine = true, + shape = RoundedCornerShape(12.dp) + ) + + Spacer(modifier = Modifier.height(12.dp)) + + val bioMaxLength = 1024 + val bioOverLimit = bio.length > bioMaxLength + OutlinedTextField( + value = bio, + onValueChange = onBioChange, + label = { Text("Bio") }, + modifier = Modifier.fillMaxWidth(), + minLines = 3, + maxLines = 5, + isError = bioOverLimit, + shape = RoundedCornerShape(12.dp), + supportingText = { + Text( + text = "${bio.length}/$bioMaxLength", + modifier = Modifier.fillMaxWidth(), + textAlign = TextAlign.End, + color = if (bioOverLimit) + MaterialTheme.colorScheme.error + else + MaterialTheme.colorScheme.onSurfaceVariant + ) + } + ) + + Spacer(modifier = Modifier.height(20.dp)) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(12.dp) + ) { + OutlinedButton( + onClick = onCancel, + modifier = Modifier.weight(1f), + enabled = !isSaving + ) { + Text("Cancel") + } + Button( + onClick = onSave, + modifier = Modifier.weight(1f), + enabled = !isSaving && canSave + ) { + if (isSaving) { + CircularProgressIndicator( + modifier = Modifier.size(20.dp), + strokeWidth = 2.dp, + color = MaterialTheme.colorScheme.onPrimary + ) + } else { + Text("Save") + } + } + } + } +} + +private fun formatUtcToLocalDate(isoString: String): String { + return try { + val zonedUtc = java.time.ZonedDateTime.parse(isoString) + val local = zonedUtc.withZoneSameInstant(java.time.ZoneId.systemDefault()) + local.format(java.time.format.DateTimeFormatter.ofPattern("dd MMM yyyy")) + } catch (_: Exception) { + isoString.substringBefore("T") + } +} diff --git a/app/src/main/java/org/yobble/messenger/presentation/profile/ProfileViewModel.kt b/app/src/main/java/org/yobble/messenger/presentation/profile/ProfileViewModel.kt new file mode 100644 index 0000000..0e49272 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/presentation/profile/ProfileViewModel.kt @@ -0,0 +1,258 @@ +package org.yobble.messenger.presentation.profile + +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import org.yobble.messenger.data.remote.NetworkResult +import org.yobble.messenger.data.remote.dto.ProfileUpdateRequestDto +import org.yobble.messenger.data.remote.dto.RatingDataDto +import org.yobble.messenger.data.remote.dto.RelationshipStatusDto +import org.yobble.messenger.data.remote.dto.WalletBalanceDto +import org.yobble.messenger.domain.repository.ChatRepository +import org.yobble.messenger.domain.repository.ProfileRepository +import javax.inject.Inject + +data class ProfileInfo( + val userId: String = "", + val login: String = "", + val displayName: String = "", + val bio: String? = null, + val isVerified: Boolean = false, + val isSystem: Boolean = false, + val rating: Double? = null, + val createdAt: String = "", + val avatarFileId: String? = null, + val balances: List = emptyList(), + val relationship: RelationshipStatusDto? = null, + val canSendMessage: Boolean = true +) + +data class ProfileUiState( + val profile: ProfileInfo? = null, + val isMyProfile: Boolean = true, + val isLoading: Boolean = false, + val isSaving: Boolean = false, + val isUploading: Boolean = false, + val isCreatingChat: Boolean = false, + val isEditing: Boolean = false, + val editFullName: String = "", + val editBio: String = "" +) + +sealed class ProfileEvent { + data class ShowError(val message: String) : ProfileEvent() + data class ShowSuccess(val message: String) : ProfileEvent() + data class NavigateToChat(val chatId: String) : ProfileEvent() +} + +@HiltViewModel +class ProfileViewModel @Inject constructor( + savedStateHandle: SavedStateHandle, + private val profileRepository: ProfileRepository, + private val chatRepository: ChatRepository +) : ViewModel() { + + private val userId: String? = savedStateHandle.get("userId") + private val isMyProfile = userId == null + + private val _uiState = MutableStateFlow(ProfileUiState(isMyProfile = isMyProfile)) + val uiState: StateFlow = _uiState.asStateFlow() + + private val _events = MutableSharedFlow() + val events: SharedFlow = _events.asSharedFlow() + + init { + loadProfile() + } + + fun loadProfile() { + viewModelScope.launch { + _uiState.update { it.copy(isLoading = true) } + if (isMyProfile) { + loadMyProfile() + } else { + loadUserProfile(userId!!) + } + } + } + + private suspend fun loadMyProfile() { + when (val result = profileRepository.getMyProfile()) { + is NetworkResult.Success -> { + val p = result.data.data + val info = ProfileInfo( + userId = p.userId, + login = p.login, + displayName = p.fullName ?: p.login, + bio = p.bio, + isVerified = p.isVerified == true, + rating = p.rating.rating, + createdAt = p.createdAt, + avatarFileId = p.avatars?.current?.fileId, + balances = p.balances + ) + _uiState.update { + it.copy( + profile = info, + isLoading = false, + editFullName = p.fullName ?: "", + editBio = p.bio ?: "" + ) + } + } + is NetworkResult.Error -> { + _uiState.update { it.copy(isLoading = false) } + _events.emit(ProfileEvent.ShowError( + result.errors.firstOrNull()?.message ?: "Failed to load profile" + )) + } + is NetworkResult.Exception -> { + _uiState.update { it.copy(isLoading = false) } + _events.emit(ProfileEvent.ShowError("Connection error")) + } + } + } + + private suspend fun loadUserProfile(id: String) { + when (val result = profileRepository.getUserProfile(id)) { + is NetworkResult.Success -> { + val p = result.data.data + val info = ProfileInfo( + userId = p.userId, + login = p.login ?: "", + displayName = p.customName ?: p.fullName ?: p.login?.let { "@$it" } ?: "User", + bio = p.bio, + isVerified = p.isVerified == true, + isSystem = p.isSystem == true, + rating = p.rating.rating, + createdAt = p.createdAt, + avatarFileId = p.avatars?.current?.fileId, + relationship = p.relationship, + canSendMessage = p.permissions.youCanSendMessage + ) + _uiState.update { it.copy(profile = info, isLoading = false) } + } + is NetworkResult.Error -> { + _uiState.update { it.copy(isLoading = false) } + _events.emit(ProfileEvent.ShowError( + result.errors.firstOrNull()?.message ?: "Failed to load profile" + )) + } + is NetworkResult.Exception -> { + _uiState.update { it.copy(isLoading = false) } + _events.emit(ProfileEvent.ShowError("Connection error")) + } + } + } + + fun startEditing() { + if (!isMyProfile) return + val profile = _uiState.value.profile ?: return + _uiState.update { + it.copy( + isEditing = true, + editFullName = if (profile.displayName != profile.login) profile.displayName else "", + editBio = profile.bio ?: "" + ) + } + } + + fun cancelEditing() { + _uiState.update { it.copy(isEditing = false) } + } + + fun onFullNameChange(value: String) { + _uiState.update { it.copy(editFullName = value) } + } + + fun onBioChange(value: String) { + _uiState.update { it.copy(editBio = value) } + } + + fun saveProfile() { + val state = _uiState.value + if (state.isSaving || !isMyProfile) return + + viewModelScope.launch { + _uiState.update { it.copy(isSaving = true) } + val request = ProfileUpdateRequestDto( + fullName = state.editFullName.trim().ifBlank { null }, + bio = state.editBio.trim().ifBlank { null } + ) + when (val result = profileRepository.editProfile(request)) { + is NetworkResult.Success -> { + _uiState.update { it.copy(isSaving = false, isEditing = false) } + _events.emit(ProfileEvent.ShowSuccess("Profile updated")) + loadProfile() + } + is NetworkResult.Error -> { + _uiState.update { it.copy(isSaving = false) } + _events.emit(ProfileEvent.ShowError( + result.errors.firstOrNull()?.message ?: "Failed to update profile" + )) + } + is NetworkResult.Exception -> { + _uiState.update { it.copy(isSaving = false) } + _events.emit(ProfileEvent.ShowError("Connection error")) + } + } + } + } + + fun uploadAvatar(file: java.io.File, mimeType: String) { + if (!isMyProfile || _uiState.value.isUploading) return + viewModelScope.launch { + _uiState.update { it.copy(isUploading = true) } + when (val result = profileRepository.uploadAvatar(file, mimeType)) { + is NetworkResult.Success -> { + _uiState.update { it.copy(isUploading = false) } + _events.emit(ProfileEvent.ShowSuccess("Avatar updated")) + loadProfile() + } + is NetworkResult.Error -> { + _uiState.update { it.copy(isUploading = false) } + _events.emit(ProfileEvent.ShowError( + result.errors.firstOrNull()?.message ?: "Failed to upload avatar" + )) + } + is NetworkResult.Exception -> { + _uiState.update { it.copy(isUploading = false) } + _events.emit(ProfileEvent.ShowError("Connection error")) + } + } + } + } + + fun createChat() { + val targetUserId = userId ?: return + if (_uiState.value.isCreatingChat) return + viewModelScope.launch { + _uiState.update { it.copy(isCreatingChat = true) } + when (val result = chatRepository.createChat(targetUserId)) { + is NetworkResult.Success -> { + _uiState.update { it.copy(isCreatingChat = false) } + _events.emit(ProfileEvent.NavigateToChat(result.data.data.chatId)) + } + is NetworkResult.Error -> { + _uiState.update { it.copy(isCreatingChat = false) } + _events.emit(ProfileEvent.ShowError( + result.errors.firstOrNull()?.message ?: "Failed to create chat" + )) + } + is NetworkResult.Exception -> { + _uiState.update { it.copy(isCreatingChat = false) } + _events.emit(ProfileEvent.ShowError("Connection error")) + } + } + } + } +} diff --git a/app/src/main/java/org/yobble/messenger/presentation/search/SearchScreen.kt b/app/src/main/java/org/yobble/messenger/presentation/search/SearchScreen.kt new file mode 100644 index 0000000..23d045c --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/presentation/search/SearchScreen.kt @@ -0,0 +1,222 @@ +package org.yobble.messenger.presentation.search + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.filled.Clear +import androidx.compose.material.icons.filled.Search +import androidx.compose.material.icons.filled.Star +import androidx.compose.material.icons.filled.Verified +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import org.yobble.messenger.data.remote.dto.UserSearchResultDto +import org.yobble.messenger.presentation.common.UserAvatar + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun SearchScreen( + onNavigateBack: () -> Unit, + onNavigateToProfile: (userId: String) -> Unit, + viewModel: SearchViewModel = hiltViewModel() +) { + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val focusRequester = remember { FocusRequester() } + + LaunchedEffect(Unit) { + focusRequester.requestFocus() + } + + Scaffold( + topBar = { + TopAppBar( + title = { + OutlinedTextField( + value = uiState.query, + onValueChange = viewModel::onQueryChange, + placeholder = { Text("Search users...", color = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.6f)) }, + singleLine = true, + modifier = Modifier + .fillMaxWidth() + .focusRequester(focusRequester), + colors = OutlinedTextFieldDefaults.colors( + focusedTextColor = MaterialTheme.colorScheme.onPrimary, + unfocusedTextColor = MaterialTheme.colorScheme.onPrimary, + cursorColor = MaterialTheme.colorScheme.onPrimary, + focusedBorderColor = Color.Transparent, + unfocusedBorderColor = Color.Transparent + ), + trailingIcon = { + if (uiState.query.isNotEmpty()) { + IconButton(onClick = { viewModel.onQueryChange("") }) { + Icon( + Icons.Default.Clear, + contentDescription = "Clear", + tint = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.7f) + ) + } + } + } + ) + }, + navigationIcon = { + IconButton(onClick = onNavigateBack) { + Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back") + } + }, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = MaterialTheme.colorScheme.primary, + navigationIconContentColor = MaterialTheme.colorScheme.onPrimary + ) + ) + } + ) { padding -> + Box( + modifier = Modifier + .fillMaxSize() + .padding(padding) + ) { + when { + uiState.isLoading -> { + CircularProgressIndicator( + modifier = Modifier.align(Alignment.Center), + color = MaterialTheme.colorScheme.primary + ) + } + uiState.query.isBlank() -> { + Column( + modifier = Modifier.align(Alignment.Center), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Icon( + Icons.Default.Search, + contentDescription = null, + modifier = Modifier.size(48.dp), + tint = MaterialTheme.colorScheme.onSurfaceVariant + ) + Spacer(modifier = Modifier.height(8.dp)) + Text( + "Search by login", + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + } + uiState.results.isEmpty() && !uiState.isLoading -> { + Text( + "No users found", + modifier = Modifier.align(Alignment.Center), + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + else -> { + LazyColumn(modifier = Modifier.fillMaxSize()) { + items(uiState.results, key = { it.userId }) { result -> + SearchResultItem( + result = result, + onClick = { onNavigateToProfile(result.userId) } + ) + } + } + } + } + } + } +} + +@Composable +private fun SearchResultItem( + result: UserSearchResultDto, + onClick: () -> Unit +) { + val profile = result.profile + val displayName = profile?.customName + ?: profile?.fullName + ?: profile?.login?.let { "@$it" } + ?: "User" + val isVerified = profile?.isVerified == true + val rating = profile?.rating?.rating + + Row( + modifier = Modifier + .fillMaxWidth() + .clickable(onClick = onClick) + .padding(horizontal = 16.dp, vertical = 10.dp), + verticalAlignment = Alignment.CenterVertically + ) { + UserAvatar( + userId = result.userId, + fileId = profile?.avatars?.current?.fileId, + displayName = displayName, + size = 48.dp, + fontSize = 18.sp + ) + + Spacer(modifier = Modifier.width(12.dp)) + + Column(modifier = Modifier.weight(1f)) { + Row(verticalAlignment = Alignment.CenterVertically) { + Text( + text = displayName, + style = MaterialTheme.typography.bodyLarge, + fontWeight = FontWeight.Medium, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + modifier = Modifier.weight(1f, fill = false) + ) + if (isVerified) { + Spacer(modifier = Modifier.width(4.dp)) + Icon( + Icons.Default.Verified, + contentDescription = "Verified", + tint = MaterialTheme.colorScheme.primary, + modifier = Modifier.size(16.dp) + ) + } + if (rating != null) { + Spacer(modifier = Modifier.width(6.dp)) + Icon( + Icons.Default.Star, + contentDescription = "Rating", + tint = Color(0xFFFFC107), + modifier = Modifier.size(14.dp) + ) + Text( + text = String.format("%.1f", rating), + fontSize = 12.sp, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + } + if (profile?.login != null) { + Text( + text = "@${profile.login}", + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + maxLines = 1 + ) + } + } + } + + HorizontalDivider( + modifier = Modifier.padding(start = 76.dp), + color = MaterialTheme.colorScheme.outlineVariant, + thickness = 0.5.dp + ) +} diff --git a/app/src/main/java/org/yobble/messenger/presentation/search/SearchViewModel.kt b/app/src/main/java/org/yobble/messenger/presentation/search/SearchViewModel.kt new file mode 100644 index 0000000..7c88a9b --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/presentation/search/SearchViewModel.kt @@ -0,0 +1,64 @@ +package org.yobble.messenger.presentation.search + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import org.yobble.messenger.data.remote.NetworkResult +import org.yobble.messenger.data.remote.dto.UserSearchResultDto +import org.yobble.messenger.domain.repository.FeedRepository +import javax.inject.Inject + +data class SearchUiState( + val query: String = "", + val results: List = emptyList(), + val isLoading: Boolean = false +) + +@HiltViewModel +class SearchViewModel @Inject constructor( + private val feedRepository: FeedRepository +) : ViewModel() { + + private val _uiState = MutableStateFlow(SearchUiState()) + val uiState: StateFlow = _uiState.asStateFlow() + + private var searchJob: Job? = null + + fun onQueryChange(query: String) { + _uiState.update { it.copy(query = query) } + searchJob?.cancel() + + if (query.isBlank()) { + _uiState.update { it.copy(results = emptyList(), isLoading = false) } + return + } + + searchJob = viewModelScope.launch { + delay(400) + _uiState.update { it.copy(isLoading = true) } + when (val result = feedRepository.searchUsers(query.trim())) { + is NetworkResult.Success -> { + _uiState.update { + it.copy( + results = result.data.data.users, + isLoading = false + ) + } + } + is NetworkResult.Error -> { + _uiState.update { it.copy(isLoading = false, results = emptyList()) } + } + is NetworkResult.Exception -> { + _uiState.update { it.copy(isLoading = false, results = emptyList()) } + } + } + } + } +} diff --git a/app/src/main/java/org/yobble/messenger/presentation/settings/BlacklistScreen.kt b/app/src/main/java/org/yobble/messenger/presentation/settings/BlacklistScreen.kt new file mode 100644 index 0000000..7c49f9b --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/presentation/settings/BlacklistScreen.kt @@ -0,0 +1,246 @@ +package org.yobble.messenger.presentation.settings + +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.filled.Block +import androidx.compose.material.icons.filled.PersonAdd +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import kotlinx.coroutines.flow.collectLatest +import org.yobble.messenger.data.remote.dto.BlacklistInfoDto +import org.yobble.messenger.presentation.common.UserAvatar + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun BlacklistScreen( + onNavigateBack: () -> Unit, + viewModel: BlacklistViewModel = hiltViewModel() +) { + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val snackbarHostState = remember { SnackbarHostState() } + + LaunchedEffect(Unit) { + viewModel.events.collectLatest { event -> + when (event) { + is BlacklistEvent.ShowError -> snackbarHostState.showSnackbar(event.message) + is BlacklistEvent.ShowSuccess -> snackbarHostState.showSnackbar(event.message) + } + } + } + + if (uiState.showBlockDialog) { + BlockUserDialog( + query = uiState.blockQuery, + onQueryChange = viewModel::onBlockQueryChange, + onBlock = viewModel::blockUser, + onDismiss = viewModel::hideBlockDialog, + isBlocking = uiState.isBlocking + ) + } + + Scaffold( + snackbarHost = { SnackbarHost(snackbarHostState) }, + topBar = { + TopAppBar( + title = { Text("Blacklist", fontWeight = FontWeight.Bold) }, + navigationIcon = { + IconButton(onClick = onNavigateBack) { + Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back") + } + }, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = MaterialTheme.colorScheme.primary, + titleContentColor = MaterialTheme.colorScheme.onPrimary, + navigationIconContentColor = MaterialTheme.colorScheme.onPrimary + ) + ) + }, + floatingActionButton = { + FloatingActionButton( + onClick = viewModel::showBlockDialog, + containerColor = MaterialTheme.colorScheme.primary, + contentColor = MaterialTheme.colorScheme.onPrimary + ) { + Icon(Icons.Default.PersonAdd, contentDescription = "Block user") + } + } + ) { padding -> + if (uiState.isLoading && uiState.blacklist.isEmpty()) { + Box( + modifier = Modifier + .fillMaxSize() + .padding(padding), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator(color = MaterialTheme.colorScheme.primary) + } + } else if (uiState.blacklist.isEmpty() && !uiState.isLoading) { + Box( + modifier = Modifier + .fillMaxSize() + .padding(padding), + contentAlignment = Alignment.Center + ) { + Column(horizontalAlignment = Alignment.CenterHorizontally) { + Icon( + Icons.Default.Block, + contentDescription = null, + modifier = Modifier.size(48.dp), + tint = MaterialTheme.colorScheme.onSurfaceVariant + ) + Spacer(modifier = Modifier.height(8.dp)) + Text( + "Blacklist is empty", + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + } + } else { + LazyColumn( + modifier = Modifier + .fillMaxSize() + .padding(padding) + ) { + items(uiState.blacklist, key = { it.userId }) { blocked -> + BlacklistItem( + item = blocked, + onUnblock = { viewModel.unblockUser(blocked.userId) } + ) + } + + if (uiState.isLoading && uiState.blacklist.isNotEmpty()) { + item { + Box( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator( + modifier = Modifier.size(24.dp), + strokeWidth = 2.dp + ) + } + } + } + } + } + } +} + +@Composable +private fun BlacklistItem( + item: BlacklistInfoDto, + onUnblock: () -> Unit +) { + val displayName = item.fullName + ?: item.login?.let { "@$it" } + ?: "User" + + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp, vertical = 10.dp), + verticalAlignment = Alignment.CenterVertically + ) { + UserAvatar( + userId = item.userId, + fileId = null, + displayName = displayName, + size = 44.dp, + fontSize = 16.sp + ) + + Spacer(modifier = Modifier.width(12.dp)) + + Column(modifier = Modifier.weight(1f)) { + Text( + text = displayName, + style = MaterialTheme.typography.bodyLarge, + fontWeight = FontWeight.Medium, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + if (item.login != null) { + Text( + text = "@${item.login}", + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + maxLines = 1 + ) + } + } + + TextButton(onClick = onUnblock) { + Text("Unblock", color = MaterialTheme.colorScheme.error) + } + } + + HorizontalDivider( + modifier = Modifier.padding(start = 72.dp), + color = MaterialTheme.colorScheme.outlineVariant, + thickness = 0.5.dp + ) +} + +@Composable +private fun BlockUserDialog( + query: String, + onQueryChange: (String) -> Unit, + onBlock: () -> Unit, + onDismiss: () -> Unit, + isBlocking: Boolean +) { + AlertDialog( + onDismissRequest = onDismiss, + title = { Text("Block user") }, + text = { + OutlinedTextField( + value = query, + onValueChange = onQueryChange, + label = { Text("Login") }, + placeholder = { Text("username") }, + singleLine = true, + modifier = Modifier.fillMaxWidth(), + shape = RoundedCornerShape(12.dp) + ) + }, + confirmButton = { + Button( + onClick = onBlock, + enabled = query.isNotBlank() && !isBlocking, + colors = ButtonDefaults.buttonColors( + containerColor = MaterialTheme.colorScheme.error + ) + ) { + if (isBlocking) { + CircularProgressIndicator( + modifier = Modifier.size(18.dp), + strokeWidth = 2.dp, + color = MaterialTheme.colorScheme.onError + ) + } else { + Text("Block") + } + } + }, + dismissButton = { + TextButton(onClick = onDismiss) { + Text("Cancel") + } + } + ) +} diff --git a/app/src/main/java/org/yobble/messenger/presentation/settings/BlacklistViewModel.kt b/app/src/main/java/org/yobble/messenger/presentation/settings/BlacklistViewModel.kt new file mode 100644 index 0000000..3e0ec57 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/presentation/settings/BlacklistViewModel.kt @@ -0,0 +1,134 @@ +package org.yobble.messenger.presentation.settings + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import org.yobble.messenger.data.remote.NetworkResult +import org.yobble.messenger.data.remote.dto.BlacklistCreateRequestDto +import org.yobble.messenger.data.remote.dto.BlacklistInfoDto +import org.yobble.messenger.domain.repository.UserRepository +import javax.inject.Inject + +data class BlacklistUiState( + val blacklist: List = emptyList(), + val isLoading: Boolean = false, + val hasMore: Boolean = false, + val blockQuery: String = "", + val isBlocking: Boolean = false, + val showBlockDialog: Boolean = false +) + +sealed class BlacklistEvent { + data class ShowError(val message: String) : BlacklistEvent() + data class ShowSuccess(val message: String) : BlacklistEvent() +} + +@HiltViewModel +class BlacklistViewModel @Inject constructor( + private val userRepository: UserRepository +) : ViewModel() { + + private val _uiState = MutableStateFlow(BlacklistUiState()) + val uiState: StateFlow = _uiState.asStateFlow() + + private val _events = MutableSharedFlow() + val events: SharedFlow = _events.asSharedFlow() + + init { + loadBlacklist() + } + + fun loadBlacklist() { + viewModelScope.launch { + _uiState.update { it.copy(isLoading = true) } + when (val result = userRepository.getBlacklist()) { + is NetworkResult.Success -> { + _uiState.update { + it.copy( + blacklist = result.data.data.items, + hasMore = result.data.data.hasMore, + isLoading = false + ) + } + } + is NetworkResult.Error -> { + _uiState.update { it.copy(isLoading = false) } + _events.emit(BlacklistEvent.ShowError( + result.errors.firstOrNull()?.message ?: "Failed to load blacklist" + )) + } + is NetworkResult.Exception -> { + _uiState.update { it.copy(isLoading = false) } + _events.emit(BlacklistEvent.ShowError("Connection error")) + } + } + } + } + + fun showBlockDialog() { + _uiState.update { it.copy(showBlockDialog = true, blockQuery = "") } + } + + fun hideBlockDialog() { + _uiState.update { it.copy(showBlockDialog = false) } + } + + fun onBlockQueryChange(value: String) { + _uiState.update { it.copy(blockQuery = value) } + } + + fun blockUser() { + val query = _uiState.value.blockQuery.trim() + if (query.isBlank() || _uiState.value.isBlocking) return + + val login = if (query.startsWith("@")) query.removePrefix("@") else query + + viewModelScope.launch { + _uiState.update { it.copy(isBlocking = true) } + when (val result = userRepository.addToBlacklist(BlacklistCreateRequestDto(login = login))) { + is NetworkResult.Success -> { + _uiState.update { it.copy(isBlocking = false, showBlockDialog = false) } + _events.emit(BlacklistEvent.ShowSuccess("User blocked")) + loadBlacklist() + } + is NetworkResult.Error -> { + _uiState.update { it.copy(isBlocking = false) } + _events.emit(BlacklistEvent.ShowError( + result.errors.firstOrNull()?.message ?: "Failed to block user" + )) + } + is NetworkResult.Exception -> { + _uiState.update { it.copy(isBlocking = false) } + _events.emit(BlacklistEvent.ShowError("Connection error")) + } + } + } + } + + fun unblockUser(userId: String) { + viewModelScope.launch { + when (val result = userRepository.removeFromBlacklist(userId)) { + is NetworkResult.Success -> { + _events.emit(BlacklistEvent.ShowSuccess("User unblocked")) + loadBlacklist() + } + is NetworkResult.Error -> { + _events.emit(BlacklistEvent.ShowError( + result.errors.firstOrNull()?.message ?: "Failed to unblock user" + )) + } + is NetworkResult.Exception -> { + _events.emit(BlacklistEvent.ShowError("Connection error")) + } + } + } + } +} diff --git a/app/src/main/java/org/yobble/messenger/presentation/settings/ChangePasswordScreen.kt b/app/src/main/java/org/yobble/messenger/presentation/settings/ChangePasswordScreen.kt new file mode 100644 index 0000000..8490012 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/presentation/settings/ChangePasswordScreen.kt @@ -0,0 +1,147 @@ +package org.yobble.messenger.presentation.settings + +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.filled.Visibility +import androidx.compose.material.icons.filled.VisibilityOff +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.PasswordVisualTransformation +import androidx.compose.ui.text.input.VisualTransformation +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import kotlinx.coroutines.flow.collectLatest + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun ChangePasswordScreen( + onNavigateBack: () -> Unit, + viewModel: SettingsViewModel = hiltViewModel() +) { + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val snackbarHostState = remember { SnackbarHostState() } + + LaunchedEffect(Unit) { + viewModel.events.collectLatest { event -> + when (event) { + is SettingsEvent.ShowError -> snackbarHostState.showSnackbar(event.message) + is SettingsEvent.ShowSuccess -> { + snackbarHostState.showSnackbar(event.message) + onNavigateBack() + } + } + } + } + + Scaffold( + snackbarHost = { SnackbarHost(snackbarHostState) }, + topBar = { + TopAppBar( + title = { Text("Change password", fontWeight = FontWeight.Bold) }, + navigationIcon = { + IconButton(onClick = onNavigateBack) { + Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back") + } + }, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = MaterialTheme.colorScheme.primary, + titleContentColor = MaterialTheme.colorScheme.onPrimary, + navigationIconContentColor = MaterialTheme.colorScheme.onPrimary + ) + ) + } + ) { padding -> + Column( + modifier = Modifier + .fillMaxSize() + .padding(padding) + .verticalScroll(rememberScrollState()) + .padding(16.dp), + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + PasswordField( + value = uiState.oldPassword, + onValueChange = viewModel::onOldPasswordChange, + label = "Current password" + ) + PasswordField( + value = uiState.newPassword, + onValueChange = viewModel::onNewPasswordChange, + label = "New password", + isError = uiState.newPassword.isNotEmpty() && uiState.newPassword.length < 8, + supportingText = if (uiState.newPassword.isNotEmpty() && uiState.newPassword.length < 8) + "At least 8 characters" else null + ) + PasswordField( + value = uiState.confirmPassword, + onValueChange = viewModel::onConfirmPasswordChange, + label = "Confirm new password", + isError = uiState.confirmPassword.isNotEmpty() && uiState.confirmPassword != uiState.newPassword, + supportingText = if (uiState.confirmPassword.isNotEmpty() && uiState.confirmPassword != uiState.newPassword) + "Passwords don't match" else null + ) + + Spacer(modifier = Modifier.height(8.dp)) + + val canSubmit = uiState.oldPassword.isNotBlank() && + uiState.newPassword.length >= 8 && + uiState.newPassword == uiState.confirmPassword && + !uiState.isChangingPassword + + Button( + onClick = viewModel::changePassword, + modifier = Modifier.fillMaxWidth(), + enabled = canSubmit, + shape = RoundedCornerShape(12.dp) + ) { + if (uiState.isChangingPassword) { + CircularProgressIndicator( + modifier = Modifier.size(20.dp), + strokeWidth = 2.dp, + color = MaterialTheme.colorScheme.onPrimary + ) + } else { + Text("Change password", modifier = Modifier.padding(vertical = 4.dp)) + } + } + } + } +} + +@Composable +private fun PasswordField( + value: String, + onValueChange: (String) -> Unit, + label: String, + isError: Boolean = false, + supportingText: String? = null +) { + var visible by remember { mutableStateOf(false) } + OutlinedTextField( + value = value, + onValueChange = onValueChange, + label = { Text(label) }, + modifier = Modifier.fillMaxWidth(), + singleLine = true, + isError = isError, + supportingText = supportingText?.let { { Text(it) } }, + visualTransformation = if (visible) VisualTransformation.None else PasswordVisualTransformation(), + trailingIcon = { + IconButton(onClick = { visible = !visible }) { + Icon( + if (visible) Icons.Default.VisibilityOff else Icons.Default.Visibility, + contentDescription = if (visible) "Hide" else "Show" + ) + } + }, + shape = RoundedCornerShape(12.dp) + ) +} diff --git a/app/src/main/java/org/yobble/messenger/presentation/settings/PrivacyScreen.kt b/app/src/main/java/org/yobble/messenger/presentation/settings/PrivacyScreen.kt new file mode 100644 index 0000000..1b301ed --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/presentation/settings/PrivacyScreen.kt @@ -0,0 +1,306 @@ +package org.yobble.messenger.presentation.settings + +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import kotlinx.coroutines.flow.collectLatest +import org.yobble.messenger.data.remote.dto.ProfilePermissionsRequestDto + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun PrivacyScreen( + onNavigateBack: () -> Unit, + viewModel: SettingsViewModel = hiltViewModel() +) { + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val snackbarHostState = remember { SnackbarHostState() } + + LaunchedEffect(Unit) { + viewModel.loadPermissions() + viewModel.events.collectLatest { event -> + when (event) { + is SettingsEvent.ShowError -> snackbarHostState.showSnackbar(event.message) + is SettingsEvent.ShowSuccess -> snackbarHostState.showSnackbar(event.message) + } + } + } + + Scaffold( + snackbarHost = { SnackbarHost(snackbarHostState) }, + topBar = { + TopAppBar( + title = { Text("Privacy", fontWeight = FontWeight.Bold) }, + navigationIcon = { + IconButton(onClick = onNavigateBack) { + Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back") + } + }, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = MaterialTheme.colorScheme.primary, + titleContentColor = MaterialTheme.colorScheme.onPrimary, + navigationIconContentColor = MaterialTheme.colorScheme.onPrimary + ) + ) + } + ) { padding -> + val permissions = uiState.permissions + if (uiState.isLoadingPermissions && permissions == null) { + Box( + modifier = Modifier + .fillMaxSize() + .padding(padding), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator(color = MaterialTheme.colorScheme.primary) + } + } else if (permissions != null) { + Column( + modifier = Modifier + .fillMaxSize() + .padding(padding) + .verticalScroll(rememberScrollState()) + ) { + SectionHeader("Visibility") + + ToggleItem( + title = "Searchable", + subtitle = "Others can find you by search", + checked = permissions.isSearchable, + enabled = !uiState.isSavingPermissions, + onToggle = { value -> + viewModel.updatePermission { + ProfilePermissionsRequestDto(isSearchable = value) + } + } + ) + + ToggleItem( + title = "Show bio to non-contacts", + subtitle = "Users not in your contacts can see your bio", + checked = permissions.showBioToNonContacts, + enabled = !uiState.isSavingPermissions, + onToggle = { value -> + viewModel.updatePermission { + ProfilePermissionsRequestDto(showBioToNonContacts = value) + } + } + ) + + ToggleItem( + title = "Show photo to non-contacts", + subtitle = "Users not in your contacts can see your photo", + checked = permissions.showProfilePhotoToNonContacts, + enabled = !uiState.isSavingPermissions, + onToggle = { value -> + viewModel.updatePermission { + ProfilePermissionsRequestDto(showProfilePhotoToNonContacts = value) + } + } + ) + + ToggleItem( + title = "Show stories to non-contacts", + subtitle = "Users not in your contacts can see your stories", + checked = permissions.showStoriesToNonContacts, + enabled = !uiState.isSavingPermissions, + onToggle = { value -> + viewModel.updatePermission { + ProfilePermissionsRequestDto(showStoriesToNonContacts = value) + } + } + ) + + SelectItem( + title = "Last seen visibility", + options = listOf("Nobody" to 0, "Contacts" to 1, "Everyone" to 2), + selected = permissions.lastSeenVisibility, + enabled = !uiState.isSavingPermissions, + onSelect = { value -> + viewModel.updatePermission { + ProfilePermissionsRequestDto(lastSeenVisibility = value) + } + } + ) + + HorizontalDivider(modifier = Modifier.padding(vertical = 8.dp)) + SectionHeader("Messages") + + ToggleItem( + title = "Allow messages from non-contacts", + subtitle = "Receive messages from users not in your contacts", + checked = permissions.allowMessagesFromNonContacts, + enabled = !uiState.isSavingPermissions, + onToggle = { value -> + viewModel.updatePermission { + ProfilePermissionsRequestDto(allowMessagesFromNonContacts = value) + } + } + ) + + ToggleItem( + title = "Allow message forwarding", + subtitle = "Others can forward your messages", + checked = permissions.allowMessageForwarding, + enabled = !uiState.isSavingPermissions, + onToggle = { value -> + viewModel.updatePermission { + ProfilePermissionsRequestDto(allowMessageForwarding = value) + } + } + ) + + ToggleItem( + title = "Force auto-delete in private", + subtitle = "Messages in private chats auto-delete", + checked = permissions.forceAutoDeleteMessagesInPrivate, + enabled = !uiState.isSavingPermissions, + onToggle = { value -> + viewModel.updatePermission { + ProfilePermissionsRequestDto(forceAutoDeleteMessagesInPrivate = value) + } + } + ) + + HorizontalDivider(modifier = Modifier.padding(vertical = 8.dp)) + SectionHeader("Groups & Invites") + + ToggleItem( + title = "Allow server chats", + subtitle = "Participate in server-based chats", + checked = permissions.allowServerChats, + enabled = !uiState.isSavingPermissions, + onToggle = { value -> + viewModel.updatePermission { + ProfilePermissionsRequestDto(allowServerChats = value) + } + } + ) + + SelectItem( + title = "Public invite", + options = listOf("Nobody" to 0, "Contacts" to 1, "Everyone" to 2), + selected = permissions.publicInvitePermission, + enabled = !uiState.isSavingPermissions, + onSelect = { value -> + viewModel.updatePermission { + ProfilePermissionsRequestDto(publicInvitePermission = value) + } + } + ) + + SelectItem( + title = "Group invite", + options = listOf("Nobody" to 0, "Contacts" to 1, "Everyone" to 2), + selected = permissions.groupInvitePermission, + enabled = !uiState.isSavingPermissions, + onSelect = { value -> + viewModel.updatePermission { + ProfilePermissionsRequestDto(groupInvitePermission = value) + } + } + ) + + SelectItem( + title = "Calls", + options = listOf("Nobody" to 0, "Contacts" to 1, "Everyone" to 2), + selected = permissions.callPermission, + enabled = !uiState.isSavingPermissions, + onSelect = { value -> + viewModel.updatePermission { + ProfilePermissionsRequestDto(callPermission = value) + } + } + ) + + Spacer(modifier = Modifier.height(16.dp)) + } + } + } +} + +@Composable +private fun SectionHeader(title: String) { + Text( + text = title, + style = MaterialTheme.typography.titleSmall, + color = MaterialTheme.colorScheme.primary, + fontWeight = FontWeight.Bold, + modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp) + ) +} + +@Composable +private fun ToggleItem( + title: String, + subtitle: String, + checked: Boolean, + enabled: Boolean, + onToggle: (Boolean) -> Unit +) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp, vertical = 8.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Column(modifier = Modifier.weight(1f)) { + Text(text = title, style = MaterialTheme.typography.bodyLarge) + Text( + text = subtitle, + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + Spacer(modifier = Modifier.width(8.dp)) + Switch( + checked = checked, + onCheckedChange = onToggle, + enabled = enabled + ) + } +} + +@Composable +private fun SelectItem( + title: String, + options: List>, + selected: Int, + enabled: Boolean, + onSelect: (Int) -> Unit +) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp, vertical = 8.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = title, + style = MaterialTheme.typography.bodyLarge, + modifier = Modifier.weight(1f) + ) + Spacer(modifier = Modifier.width(8.dp)) + SingleChoiceSegmentedButtonRow { + options.forEachIndexed { index, (label, value) -> + SegmentedButton( + selected = selected == value, + onClick = { onSelect(value) }, + shape = SegmentedButtonDefaults.itemShape(index, options.size), + enabled = enabled + ) { + Text(label, style = MaterialTheme.typography.labelSmall) + } + } + } + } +} diff --git a/app/src/main/java/org/yobble/messenger/presentation/settings/SessionsScreen.kt b/app/src/main/java/org/yobble/messenger/presentation/settings/SessionsScreen.kt new file mode 100644 index 0000000..fb5c9f3 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/presentation/settings/SessionsScreen.kt @@ -0,0 +1,211 @@ +package org.yobble.messenger.presentation.settings + +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.filled.PhoneAndroid +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import kotlinx.coroutines.flow.collectLatest +import org.yobble.messenger.data.remote.dto.UserSessionItemDto +import org.yobble.messenger.util.formatUtcToLocalTime + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun SessionsScreen( + onNavigateBack: () -> Unit, + viewModel: SettingsViewModel = hiltViewModel() +) { + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val snackbarHostState = remember { SnackbarHostState() } + + LaunchedEffect(Unit) { + viewModel.loadSessions() + viewModel.events.collectLatest { event -> + when (event) { + is SettingsEvent.ShowError -> snackbarHostState.showSnackbar(event.message) + is SettingsEvent.ShowSuccess -> snackbarHostState.showSnackbar(event.message) + } + } + } + + Scaffold( + snackbarHost = { SnackbarHost(snackbarHostState) }, + topBar = { + TopAppBar( + title = { Text("Sessions", fontWeight = FontWeight.Bold) }, + navigationIcon = { + IconButton(onClick = onNavigateBack) { + Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back") + } + }, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = MaterialTheme.colorScheme.primary, + titleContentColor = MaterialTheme.colorScheme.onPrimary, + navigationIconContentColor = MaterialTheme.colorScheme.onPrimary + ) + ) + } + ) { padding -> + if (uiState.isLoadingSessions && uiState.sessions.isEmpty()) { + Box( + modifier = Modifier + .fillMaxSize() + .padding(padding), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator(color = MaterialTheme.colorScheme.primary) + } + } else { + LazyColumn( + modifier = Modifier + .fillMaxSize() + .padding(padding), + contentPadding = PaddingValues(16.dp), + verticalArrangement = Arrangement.spacedBy(12.dp) + ) { + val otherSessions = uiState.sessions.filter { !it.isCurrent } + if (otherSessions.size > 1) { + item { + OutlinedButton( + onClick = viewModel::revokeAllExceptCurrent, + modifier = Modifier.fillMaxWidth(), + colors = ButtonDefaults.outlinedButtonColors( + contentColor = MaterialTheme.colorScheme.error + ), + shape = RoundedCornerShape(12.dp) + ) { + Text("Revoke all other sessions") + } + } + } + + val currentSession = uiState.sessions.find { it.isCurrent } + if (currentSession != null) { + item { + Text( + "Current session", + style = MaterialTheme.typography.titleSmall, + color = MaterialTheme.colorScheme.primary, + fontWeight = FontWeight.Bold + ) + } + item { + SessionCard(session = currentSession, onRevoke = null) + } + } + + if (otherSessions.isNotEmpty()) { + item { + Text( + "Other sessions", + style = MaterialTheme.typography.titleSmall, + color = MaterialTheme.colorScheme.primary, + fontWeight = FontWeight.Bold + ) + } + items(otherSessions, key = { it.id }) { session -> + SessionCard( + session = session, + onRevoke = { viewModel.revokeSession(session.id) } + ) + } + } + } + } + } +} + +@Composable +private fun SessionCard( + session: UserSessionItemDto, + onRevoke: (() -> Unit)? +) { + Card( + modifier = Modifier.fillMaxWidth(), + colors = CardDefaults.cardColors( + containerColor = if (session.isCurrent) + MaterialTheme.colorScheme.primaryContainer + else + MaterialTheme.colorScheme.surfaceVariant + ), + shape = RoundedCornerShape(12.dp) + ) { + Column(modifier = Modifier.padding(16.dp)) { + Row(verticalAlignment = Alignment.CenterVertically) { + Icon( + Icons.Default.PhoneAndroid, + contentDescription = null, + modifier = Modifier.size(20.dp), + tint = MaterialTheme.colorScheme.onSurfaceVariant + ) + Spacer(modifier = Modifier.width(8.dp)) + Text( + text = session.clientType.replaceFirstChar { it.uppercase() }, + style = MaterialTheme.typography.bodyLarge, + fontWeight = FontWeight.Medium + ) + if (session.isCurrent) { + Spacer(modifier = Modifier.width(8.dp)) + Text( + text = "Current", + style = MaterialTheme.typography.labelSmall, + color = MaterialTheme.colorScheme.primary + ) + } + } + + if (!session.ipAddress.isNullOrBlank()) { + Spacer(modifier = Modifier.height(4.dp)) + Text( + text = "IP: ${session.ipAddress}", + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + + Spacer(modifier = Modifier.height(4.dp)) + Text( + text = "Last active: ${formatSessionDate(session.lastRefreshAt)}", + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + Text( + text = "Created: ${formatSessionDate(session.createdAt)}", + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + + if (onRevoke != null) { + Spacer(modifier = Modifier.height(8.dp)) + TextButton( + onClick = onRevoke, + colors = ButtonDefaults.textButtonColors( + contentColor = MaterialTheme.colorScheme.error + ) + ) { + Text("Revoke") + } + } + } + } +} + +private fun formatSessionDate(isoString: String): String { + return try { + val zonedUtc = java.time.ZonedDateTime.parse(isoString) + val local = zonedUtc.withZoneSameInstant(java.time.ZoneId.systemDefault()) + local.format(java.time.format.DateTimeFormatter.ofPattern("dd MMM yyyy, HH:mm")) + } catch (_: Exception) { + isoString.substringBefore("T") + } +} diff --git a/app/src/main/java/org/yobble/messenger/presentation/settings/SettingsScreen.kt b/app/src/main/java/org/yobble/messenger/presentation/settings/SettingsScreen.kt new file mode 100644 index 0000000..70d4af4 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/presentation/settings/SettingsScreen.kt @@ -0,0 +1,119 @@ +package org.yobble.messenger.presentation.settings + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight +import androidx.compose.material.icons.filled.Block +import androidx.compose.material.icons.filled.Lock +import androidx.compose.material.icons.filled.PhoneAndroid +import androidx.compose.material.icons.filled.Shield +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp + +@Composable +fun SettingsScreen( + onNavigateToPrivacy: () -> Unit, + onNavigateToSessions: () -> Unit, + onNavigateToChangePassword: () -> Unit, + onNavigateToBlacklist: () -> Unit, + onLogout: () -> Unit, + bottomPadding: Dp = 0.dp +) { + Column( + modifier = Modifier + .fillMaxSize() + .verticalScroll(rememberScrollState()) + .padding(top = 8.dp, bottom = bottomPadding + 8.dp) + ) { + SettingsMenuItem( + icon = Icons.Default.Shield, + title = "Privacy", + subtitle = "Visibility, messages, search", + onClick = onNavigateToPrivacy + ) + SettingsMenuItem( + icon = Icons.Default.PhoneAndroid, + title = "Sessions", + subtitle = "Active sessions and devices", + onClick = onNavigateToSessions + ) + SettingsMenuItem( + icon = Icons.Default.Lock, + title = "Change password", + subtitle = "Update your account password", + onClick = onNavigateToChangePassword + ) + SettingsMenuItem( + icon = Icons.Default.Block, + title = "Blacklist", + subtitle = "Blocked users", + onClick = onNavigateToBlacklist + ) + + Spacer(modifier = Modifier.height(16.dp)) + + Button( + onClick = onLogout, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + colors = ButtonDefaults.buttonColors( + containerColor = MaterialTheme.colorScheme.error + ), + shape = RoundedCornerShape(12.dp) + ) { + Text("Log out", modifier = Modifier.padding(vertical = 4.dp)) + } + } +} + +@Composable +private fun SettingsMenuItem( + icon: ImageVector, + title: String, + subtitle: String, + onClick: () -> Unit +) { + Row( + modifier = Modifier + .fillMaxWidth() + .clickable(onClick = onClick) + .padding(horizontal = 16.dp, vertical = 14.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + icon, + contentDescription = null, + tint = MaterialTheme.colorScheme.primary, + modifier = Modifier.size(24.dp) + ) + Spacer(modifier = Modifier.width(16.dp)) + Column(modifier = Modifier.weight(1f)) { + Text( + text = title, + style = MaterialTheme.typography.bodyLarge, + fontWeight = FontWeight.Medium + ) + Text( + text = subtitle, + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + Icon( + Icons.AutoMirrored.Filled.KeyboardArrowRight, + contentDescription = null, + tint = MaterialTheme.colorScheme.onSurfaceVariant + ) + } +} diff --git a/app/src/main/java/org/yobble/messenger/presentation/settings/SettingsViewModel.kt b/app/src/main/java/org/yobble/messenger/presentation/settings/SettingsViewModel.kt new file mode 100644 index 0000000..ec2b222 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/presentation/settings/SettingsViewModel.kt @@ -0,0 +1,221 @@ +package org.yobble.messenger.presentation.settings + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import org.yobble.messenger.data.remote.NetworkResult +import org.yobble.messenger.data.remote.dto.MyProfilePermissionsDto +import org.yobble.messenger.data.remote.dto.ProfilePermissionsRequestDto +import org.yobble.messenger.data.remote.dto.ProfileUpdateRequestDto +import org.yobble.messenger.data.remote.dto.UserSessionItemDto +import org.yobble.messenger.domain.repository.AuthRepository +import org.yobble.messenger.domain.repository.ProfileRepository +import javax.inject.Inject + +data class SettingsUiState( + val sessions: List = emptyList(), + val isLoadingSessions: Boolean = false, + val permissions: MyProfilePermissionsDto? = null, + val isLoadingPermissions: Boolean = false, + val isSavingPermissions: Boolean = false, + val oldPassword: String = "", + val newPassword: String = "", + val confirmPassword: String = "", + val isChangingPassword: Boolean = false +) + +sealed class SettingsEvent { + data class ShowError(val message: String) : SettingsEvent() + data class ShowSuccess(val message: String) : SettingsEvent() +} + +@HiltViewModel +class SettingsViewModel @Inject constructor( + private val authRepository: AuthRepository, + private val profileRepository: ProfileRepository +) : ViewModel() { + + private val _uiState = MutableStateFlow(SettingsUiState()) + val uiState: StateFlow = _uiState.asStateFlow() + + private val _events = MutableSharedFlow() + val events: SharedFlow = _events.asSharedFlow() + + fun loadSessions() { + viewModelScope.launch { + _uiState.update { it.copy(isLoadingSessions = true) } + when (val result = authRepository.getSessionsList()) { + is NetworkResult.Success -> { + _uiState.update { + it.copy( + sessions = result.data.data.sessions, + isLoadingSessions = false + ) + } + } + is NetworkResult.Error -> { + _uiState.update { it.copy(isLoadingSessions = false) } + _events.emit(SettingsEvent.ShowError( + result.errors.firstOrNull()?.message ?: "Failed to load sessions" + )) + } + is NetworkResult.Exception -> { + _uiState.update { it.copy(isLoadingSessions = false) } + _events.emit(SettingsEvent.ShowError("Connection error")) + } + } + } + } + + fun revokeSession(sessionId: String) { + viewModelScope.launch { + when (val result = authRepository.revokeSession(sessionId)) { + is NetworkResult.Success -> { + _events.emit(SettingsEvent.ShowSuccess("Session revoked")) + loadSessions() + } + is NetworkResult.Error -> { + _events.emit(SettingsEvent.ShowError( + result.errors.firstOrNull()?.message ?: "Failed to revoke session" + )) + } + is NetworkResult.Exception -> { + _events.emit(SettingsEvent.ShowError("Connection error")) + } + } + } + } + + fun revokeAllExceptCurrent() { + viewModelScope.launch { + when (val result = authRepository.revokeAllExceptCurrent()) { + is NetworkResult.Success -> { + _events.emit(SettingsEvent.ShowSuccess("All other sessions revoked")) + loadSessions() + } + is NetworkResult.Error -> { + _events.emit(SettingsEvent.ShowError( + result.errors.firstOrNull()?.message ?: "Failed to revoke sessions" + )) + } + is NetworkResult.Exception -> { + _events.emit(SettingsEvent.ShowError("Connection error")) + } + } + } + } + + fun loadPermissions() { + viewModelScope.launch { + _uiState.update { it.copy(isLoadingPermissions = true) } + when (val result = profileRepository.getMyProfile()) { + is NetworkResult.Success -> { + _uiState.update { + it.copy( + permissions = result.data.data.profilePermissions, + isLoadingPermissions = false + ) + } + } + is NetworkResult.Error -> { + _uiState.update { it.copy(isLoadingPermissions = false) } + _events.emit(SettingsEvent.ShowError( + result.errors.firstOrNull()?.message ?: "Failed to load privacy settings" + )) + } + is NetworkResult.Exception -> { + _uiState.update { it.copy(isLoadingPermissions = false) } + _events.emit(SettingsEvent.ShowError("Connection error")) + } + } + } + } + + fun updatePermission(update: (MyProfilePermissionsDto) -> ProfilePermissionsRequestDto) { + val current = _uiState.value.permissions ?: return + viewModelScope.launch { + _uiState.update { it.copy(isSavingPermissions = true) } + val request = ProfileUpdateRequestDto(profilePermissions = update(current)) + when (val result = profileRepository.editProfile(request)) { + is NetworkResult.Success -> { + _uiState.update { it.copy(isSavingPermissions = false) } + loadPermissions() + } + is NetworkResult.Error -> { + _uiState.update { it.copy(isSavingPermissions = false) } + _events.emit(SettingsEvent.ShowError( + result.errors.firstOrNull()?.message ?: "Failed to update setting" + )) + } + is NetworkResult.Exception -> { + _uiState.update { it.copy(isSavingPermissions = false) } + _events.emit(SettingsEvent.ShowError("Connection error")) + } + } + } + } + + fun onOldPasswordChange(value: String) { + _uiState.update { it.copy(oldPassword = value) } + } + + fun onNewPasswordChange(value: String) { + _uiState.update { it.copy(newPassword = value) } + } + + fun onConfirmPasswordChange(value: String) { + _uiState.update { it.copy(confirmPassword = value) } + } + + fun changePassword() { + val state = _uiState.value + if (state.isChangingPassword) return + if (state.newPassword != state.confirmPassword) { + viewModelScope.launch { + _events.emit(SettingsEvent.ShowError("Passwords don't match")) + } + return + } + if (state.newPassword.length < 8) { + viewModelScope.launch { + _events.emit(SettingsEvent.ShowError("Password must be at least 8 characters")) + } + return + } + + viewModelScope.launch { + _uiState.update { it.copy(isChangingPassword = true) } + when (val result = authRepository.changePassword(state.oldPassword, state.newPassword)) { + is NetworkResult.Success -> { + _uiState.update { + it.copy( + isChangingPassword = false, + oldPassword = "", + newPassword = "", + confirmPassword = "" + ) + } + _events.emit(SettingsEvent.ShowSuccess("Password changed successfully")) + } + is NetworkResult.Error -> { + _uiState.update { it.copy(isChangingPassword = false) } + _events.emit(SettingsEvent.ShowError( + result.errors.firstOrNull()?.message ?: "Failed to change password" + )) + } + is NetworkResult.Exception -> { + _uiState.update { it.copy(isChangingPassword = false) } + _events.emit(SettingsEvent.ShowError("Connection error")) + } + } + } + } +} diff --git a/app/src/main/java/org/yobble/messenger/ui/theme/Color.kt b/app/src/main/java/org/yobble/messenger/ui/theme/Color.kt new file mode 100644 index 0000000..185ccb8 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/ui/theme/Color.kt @@ -0,0 +1,31 @@ +package org.yobble.messenger.ui.theme + +import androidx.compose.ui.graphics.Color + +// Telegram-style primary palette +val TelegramBlue = Color(0xFF2AABEE) +val TelegramBlueDark = Color(0xFF0088CC) +val TelegramBlueLight = Color(0xFF6DD0FF) + +// Light theme colors +val LightBackground = Color(0xFFF7F7F8) +val LightSurface = Color(0xFFFFFFFF) +val LightSurfaceVariant = Color(0xFFEFEFF4) +val LightOnBackground = Color(0xFF1C1C1E) +val LightOnSurface = Color(0xFF1C1C1E) +val LightOnSurfaceVariant = Color(0xFF8E8E93) +val LightOutline = Color(0xFFC7C7CC) + +// Dark theme colors +val DarkBackground = Color(0xFF1C1C1E) +val DarkSurface = Color(0xFF2C2C2E) +val DarkSurfaceVariant = Color(0xFF3A3A3C) +val DarkOnBackground = Color(0xFFF2F2F7) +val DarkOnSurface = Color(0xFFF2F2F7) +val DarkOnSurfaceVariant = Color(0xFF8E8E93) +val DarkOutline = Color(0xFF48484A) + +// Semantic colors +val ErrorRed = Color(0xFFFF3B30) +val SuccessGreen = Color(0xFF34C759) +val OnPrimary = Color(0xFFFFFFFF) \ No newline at end of file diff --git a/app/src/main/java/org/yobble/messenger/ui/theme/Theme.kt b/app/src/main/java/org/yobble/messenger/ui/theme/Theme.kt new file mode 100644 index 0000000..054d16f --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/ui/theme/Theme.kt @@ -0,0 +1,69 @@ +package org.yobble.messenger.ui.theme + +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext + +private val LightColorScheme = lightColorScheme( + primary = TelegramBlue, + onPrimary = OnPrimary, + primaryContainer = TelegramBlueLight, + onPrimaryContainer = TelegramBlueDark, + secondary = TelegramBlueDark, + onSecondary = OnPrimary, + background = LightBackground, + onBackground = LightOnBackground, + surface = LightSurface, + onSurface = LightOnSurface, + surfaceVariant = LightSurfaceVariant, + onSurfaceVariant = LightOnSurfaceVariant, + outline = LightOutline, + error = ErrorRed, + onError = OnPrimary +) + +private val DarkColorScheme = darkColorScheme( + primary = TelegramBlue, + onPrimary = OnPrimary, + primaryContainer = TelegramBlueDark, + onPrimaryContainer = TelegramBlueLight, + secondary = TelegramBlueLight, + onSecondary = DarkOnBackground, + background = DarkBackground, + onBackground = DarkOnBackground, + surface = DarkSurface, + onSurface = DarkOnSurface, + surfaceVariant = DarkSurfaceVariant, + onSurfaceVariant = DarkOnSurfaceVariant, + outline = DarkOutline, + error = ErrorRed, + onError = OnPrimary +) + +@Composable +fun YobbleTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + dynamicColor: Boolean = false, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +} \ No newline at end of file diff --git a/app/src/main/java/org/yobble/messenger/ui/theme/Type.kt b/app/src/main/java/org/yobble/messenger/ui/theme/Type.kt new file mode 100644 index 0000000..cea5436 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/ui/theme/Type.kt @@ -0,0 +1,74 @@ +package org.yobble.messenger.ui.theme + +import androidx.compose.material3.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +val Typography = Typography( + // Screen titles — "Yobble" + headlineLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Bold, + fontSize = 28.sp, + lineHeight = 34.sp, + letterSpacing = 0.sp + ), + // Section headers — "Create your account" + headlineSmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 20.sp, + lineHeight = 26.sp, + letterSpacing = 0.sp + ), + // TopAppBar titles + titleLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + // Button text + labelLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 16.sp, + lineHeight = 20.sp, + letterSpacing = 0.sp + ), + // Secondary text buttons, links + labelMedium = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 14.sp, + lineHeight = 18.sp, + letterSpacing = 0.sp + ), + // Body text + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ), + // Subtitles / descriptions + bodyMedium = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 14.sp, + lineHeight = 20.sp, + letterSpacing = 0.25.sp + ), + // Small captions + bodySmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 12.sp, + lineHeight = 16.sp, + letterSpacing = 0.4.sp + ) +) \ No newline at end of file diff --git a/app/src/main/java/org/yobble/messenger/util/TimeUtils.kt b/app/src/main/java/org/yobble/messenger/util/TimeUtils.kt new file mode 100644 index 0000000..1fb1440 --- /dev/null +++ b/app/src/main/java/org/yobble/messenger/util/TimeUtils.kt @@ -0,0 +1,15 @@ +package org.yobble.messenger.util + +import java.time.ZonedDateTime +import java.time.format.DateTimeFormatter + +fun formatUtcToLocalTime(isoString: String?): String { + if (isoString.isNullOrBlank()) return "" + return try { + val zonedUtc = ZonedDateTime.parse(isoString) + val local = zonedUtc.withZoneSameInstant(java.time.ZoneId.systemDefault()) + local.format(DateTimeFormatter.ofPattern("HH:mm")) + } catch (_: Exception) { + isoString.substringAfter("T").take(5) + } +} diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..ca3826a --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..c4a603d --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..c4a603d --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000000000000000000000000000000000000..ef8ab6ef8411258d8a066a2efa1376fd09635072 GIT binary patch literal 5356 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000000000000000000000000000000000000..db50875a5baf3406c1f22ec6f36bd6418bd31a41 GIT binary patch literal 7088 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 aPqo^+_Jhr4|MB&@%CA3FJF~7(jR64F`dd{1 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000000000000000000000000000000000000..0c020b2ec5703c59c12228fce19fdd5d8d77bfc6 GIT binary patch literal 3196 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 0000000000000000000000000000000000000000..f8b79539d0ade905bc4af35e681a4eed0c07a201 GIT binary patch literal 3946 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 E0FC~g-T(jq literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000000000000000000000000000000000000..8a718182dde50c77ccefd27bfcc29f0588255b25 GIT binary patch literal 8130 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp new file mode 100644 index 0000000000000000000000000000000000000000..e23574df0b0b0f02f5e97d5823aa84774f4a904e GIT binary patch literal 22882 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 MG;VBeZl!y51pS6gv;Y7A literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 0000000000000000000000000000000000000000..6299eea4a554fa7d36786e80a10c0502a5de3b4c GIT binary patch literal 14424 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp new file mode 100644 index 0000000000000000000000000000000000000000..ec01b30466c81a1116a4f083a6e242dca2829272 GIT binary patch literal 35962 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℞#i7a|g+a_VwJM8aYjB0)}A_K$xhq_p=uP&uR~dY{nK! z!hG2&UgkC6!gGvwau5<6*SF+f1)^7LHjxC321Ez}L_&p}uw}|AG;{{Pgp#o)R|CD? znm})w91J8VsljnL8#yJ^$lEsObSIoSmY-}YH>(3+KS;4tCAZl|}>f5-K@DUa+e91q4IGX9q#vjmh(g^CL%|? zj3p8{miY`U`MBo1l243tn{gzW07x1%b2A!GK?W49&W@N7`4$z-JM5O;Q2?h`__cC{#$LCpNW*{vZaaCY6a2=FwKmP`3!td}@?9Of>Z4 z3Zl4#M#zO%yE^LZjDX6SEG!9xis1pylpUfeE#!iAMl?a6O)ARbI4e(CcVbCiLRSYL zF^6=#ohFP1w3*Z9Uc%i^K2{&8Gptwc<$V>I_y_>-IAbnikaU>631B7p{hlj19HM zDU^4D;)D|U`N#VHHRbiZlN70b=#P*9OTzYVVt_6wfB_(2fI@_6$6bmKhf_M~n?W)( zVF1wa1v7}Ez1GZviBKbFBDZyOn4U|ElBXP0qyf~<<+3w55)F_9LgFe80RNsH07U*h z|11C;=Nr*9k#&`}{7U<1x0oABRY2Vb} z*qijiUkSQtX<5?8=mc_}2(YsDH+O&g;2ReEyeQ*KYFmXN{OE2@&)d@ZhdWOLMR-l@ z^%sf;BRPun^`i~!AreNTAx?x*6u9Q{cA+L3B#YswR#tV&i2Cyn{rS`Rf|)g-^x*Qw z6kr`{Z1sSd#0mfy1n@L;VFON>dI3<7g04nEgb`F&C4eD9l(k8BYTSf%Tp;C3no{1- zU+Z4YElF6a#-m!phC+>{qRF&b@gxBJ-TY4GV2r;s-vT(#C$pK`a|i|?t1PmI@f>*C zsncgb{t?a<^D#>Hyrd)pa(GJaaMJAlvngp^oeo*Zkx#*2GyaJGW{#vJQgeeORbK(- zXXnqJMu~!MK{FhGEDIQdFKHn?Z-PqrZyrOLuVb+^MEwK1NQkigpdS#=B96sbMh^fW z5=z6asKE3z#-Ak`3!z5vPE&_ve16cg@qhd0Ma!Jvl(vSO6lnU;s>xx1rGzJu1Ax%d zO@dJ*nzIQw#minNhEO3vgveV941vg<;e$+9ITM5oXmEuI!Q9Gg>JLEmT_~Bt1V$yO zSf*qy0pM%+vX`Im@~_$C@1|tQSMljYn$$!jNJ7$4qGp}>#N=`=y{hEDe|ws=zJYLq=IGoyNLlYBHY<4@1w|J9AG$tM2@81Z?6@lCfewWd|1V$ zUEcAM`1v=0`^Wzo!@Aq5jT>vA`K_HO5)h{jPfJcqM@wK(kZp;hKus#YGDcj13jIKt zNRd=gh!ob--~JjBZ3vJ+ajh`q23;)>$^hyo6OP7{k<`?b_*kw3z|YM0;#)F>8DZ{l zoRl5cnG?*6>|*2?#~%4=^DEFgXRr9QWc5|0DNv zUf@?UbDpuOO*#jiSi0aLz+9|PM$wQ-e- z2MC6VC=m;Z2%1VHLMnMJPoOrYpybRt2@_K|u{ zfQF4kkN;O=%sj&ZB+;@ZUnX-Z|j8<{S(HO5uF#_8M^rXxP z^1iPhlEX`|tX-anF}V;D_-f>7iJ*B4m&oU%jh57?naME}0|1~4<(J9`CZX^|ECEpz z39A-0#1unI)vPADXynRyGZH+M7TuNkLO5IJo6I{kn@uHR8*TiGNCF1YI6+|83ED`= z=AA;2!{j=Q49M4~M8X0W&`QzZAbmb6l@3xSby4WU!6spE?MuI_r-lFs>OxD9sR01v zQEF_O000iS7Y)ySoN*jW#~n^M50mM`7}iOTTD*v&0SzyFQ@a?K?5!IUO0Q%nhT%OauV9P;MtrO@qV;8Zk5C9F)2t-%j9SF%E(=H-iN>E~A7NFCkDShZQ zzq=8y9-Z1c#md%g++AsFf_1ff8E$#k1^s~f>WZ9_ASPfc`#768FqO{*H6@I4!0l=C zWL8Xc+=emw=2q+q1)w2nd-s&_9|v@&Jpm(WU`WCPXEqiVvM34ol0f1~jKMdA6(m^f z!eSRzdz|JPbw(s&aw%L}M~MW4DZ9ndXL@pL?SOPpR;|>}Cvb9VL5ReekRbrF6fKqZ zRJ!3wERtwo7$y~mIshZ(-_G8tT0k)JCH5xExQc;2;y1FM%2dl*t1JPP*IUUJOAvT8 z4gd&|06-~m40J^uTDQ_S7dl|XVz7lUhX4RW^#0$o2r9Guw!Pod*h?Y>Pa$BE%)veM zQT-X@pr$k>Xdn_M5;z{oyPHCDhm6J}d7g_L@J=Kh6=e}xZLh7n2DJROCf(+S9TVde zfD?c@NY0)oJxdBfRzS8vf)w;Jw-XVLVSqZZu}RV7&Hdd`0e}^^hj$;IQzn_6R;^bd ztv4mR)rPFHp^xMOMksNHNb;Uld+jd;BNg3Em=VTe1dPBmyl9Hg%Q;L&=#fae zc_T=RWzU%RmgPqQO}|^}*(De!0~m)9rhqAh#MU_gWUsH8WGX?9Au@_gVJkG@c!zxb za(7zvXh4D(YW3cwTH|QVs7O#tq6p|Qqc>Zlfd*krGNQ^}l&J+-hd3?@0p#KEqJiPm z|{@=t0@bsvwXo7OLK095v8cSbac04NeC z2moN1LzmqpE&**>QjKp1+AzYh%{WC5%EB=FwfpGLG4$|k03h=snLr|ukT%0y!cDjt zy=wVw`%7%cL!i+(F_s`eoH>;U00&tk0c|`%re)1N_R*}svQV!enlxzF4RkdGOcNl{ zXd=vrlfp96lF*XLvt_1FhK6rha1qup2_t|+`O^(`Y2*k*WjPRwo0pz;4=7=swsXo! zE+=%|SdR~AAZExbns}5{CiZG5MiByMrFO~$il(F_U`UV#PeL;fTR|+fSXgM((+x1z zGE0SH`6ubt)*R2vQ*s2~SWlCa9TcV4+DgCXfy^%7_#Ub3y= z_kdI)(A70LrA25Ufd(Le2l`f>-xLtb-&|k3X^aye0dLmZ&Ty31ciW^>x12C3s{pF6 zY9NjigJBQ^!w3?n;MgX1& zzyuM&0E@Z=07cp)j#Wv-a+5qI!p;P8Fb9WBX|XuYJ3PpmnoPr#3$|gLJ{zVO3P=)Z z7^dr})CA>hC!zs@B;_WWKQjM^E9P{7niQX9hOvyf5#H{+@9Nusp^NF5lqScZZ$96g z^9dx5jZssv7?Bi>Ib{Y~?dIR^sEQQfVwOw6tXbwH_5JG48(MP$fj|@|Vph)3;K;4k zM%U%3mj?({YUajPj+O+01|&jIMjd`6ZKi@SJIZpux)fEML<$K21E^5ZWwtG)0M>Pt z>!k+)knriCDdN+ZnOEyqyLzK7!#)~AmLs_p0g^~2VF>`jcoHeeg&qJQ%*A5CC@AyM zyvUp9Lt=RlQAMsvf6p z9%_TbP;oSev=rli`X@=(b|4T@iV+x z8>5hDV5TN!qv8tbhYylT0WHfY3PJ=>d6u2rAc1NB`s_s|R->3CdHE~N(!4lldcfxS z_VMk806_NA-d;{kfN_Kb#sYvOfK2Og2!Oq8H=EcdA!jBrQPNGHH#29?z{s4Il5b8> z6F4QzB5Q7FV9xWBmJ2GHjC6A2MzW%F{()|23FR|!+HMxWSV=h%qX=ukz4-d#_v^xm zmAae+h%LQR4V94=i_b9AD=ssI+Q`}U6W=epK!fv1qPsSc$)`mnR;~2&k1Fj*bnqnf z1T_I5a%Q%(bO2V;vO|saL_oM{))ijOCa1+6(*x2fvw-SQ>f;@iZ32r#;((0Du{bT# ziqjSu05(yKl%!-joQnuKE#=&B$@2ioluA%i0)m2(lX8FttYCVsGXf+jZ4cEtT!Rj9 zeHw@(5d@}knQ@MDdVJb!n8Lis0jpf#v*R#YR9papKz+Z#?iJ@OQ>4i)p6_6VGG;yi z5CkwDoP6gD`ey!tV0!CQE>{(Cb=DJ&{cF`4zWkxl0bdoVtZ%!WFKDaI3CRBAB z2UORX{q(nsnZ5pqOIiAHglIrr1&b7{DpyZrw=P4Fl; z367AH=>wp?-=Y0o*E&2*O?sbZ&p8pIQ6d01U`kENu7wV?O6txj*8x>D=EV-!W@4wO zC09lWGnH}>OOc410540Yn+cancFa_3h9CG|4$wdyenWJj3|Nz};_Ix^bIfX5S`;1z zFceg%VT0}E%F&XOP69L~_1`?@h~fWx{!6q8+C`%QK_$q@sQ^%rW-YtW0{}b-lb&Iw z3<(~)6709dtq&RYV^{Db2XNd``^QV>1zov#CoKOX*-iKm3W zZiUq#qX59v7=Q@^p2j)HI${7M?4UQgi?hYqByo~ehHR7IsgH63XOV_ApP%o+cg`!x zNP=hlx|e?(4bvx5vS-91C=%)PR+j|;2$hsViG(Q;S~OE`2r?yCdBM!f6z+t4CdYg+ zJ1#*$lTC<%#f)yIqiS8XbV>y=W+Ip%9VVD5nU7ierZeMOT0BdKf)$}43K7emQqWc= zvjS@2LezxP3?C;rPvS&z6FSAz@Bs~6l!X~XbEzklIb!4_uW^nrCxy`@B#`ptwp|$d zCbrmh3Y~`6sDbL*ZOapuT*}iB&lhzb06?Hejzw@P5uy=tuMGhL0L)A}HR)J(jDvGH zcTccqI!ZosGDmz4KY*{wX`r!9e#p;08lY&#OlOypL`q6u+nqiN0RhkfB1j|#FhNU7 z4Ki|_PiIFB12UGQkrYx68FGU#U}3e6#XeotQs%BS)a;MuUeG6y%uztZ@sUh%=0Hu$ zLQ4vzwQ)HLsEtNTBsGKil%c6Lx;oiLjIFc|+kT6+R!(bfa<;J2fCjPm`M+nIq{>Eg zDG8RzJW9ze0wwSWC#GFKVPOQ=*RJ<-n1GgugvB?JV;_xWh=Yp8+t@czSxh~Fp#YBs zATmy>Yvtht05}$HaK)RMnKPxPkTcGg@bSFIlp{{b`C<7^X@Dm2>K~a?12jxC1b_fk zlh1tH0szbg6+-|u3_w5!W__lE*=EFOxx|8u@0*V*M_CI(g+KpaD>tvsmBKrP%b z7`SG{NjP(W4TA(mu;R3bCk1F}DYJmwr9<{7j2N3d z#u?B^=A<-PSEHHGRE^!q>eCPo~l!ZcZNqUX&YztI3}#k}(9R?k>< z;daK&=Ay?{AVdRpB3W*NgnKQS8q1W34Ptma9$?K`_2wJ^0BlFOU}A)^fO<;6nm6;4 z52WaGj}cj9q%cgyV%g7}Fln|C01vyEoD4>yX~3i-A&Kw7kLF(92Xp_t1_MCw`LP5w zd-ky~n(YJ(dENP`*}yUerLE=2=LR>`w2{ia4wvPQO zT)sC}@{*K>mc$~GBSF63*Lzevaj@&b$Ad-`ZZSp-5c&{tP>!0bQ&o#bGE!gyB&ZlE zLEhOZFtxyXnuUcX5{rlFrbJ2ycqRWma|S$?N(93bA?RK&W?;P#U}^#e00C(xsQJPJ zO$t)BK_Z@#5~8V*bSx}hSX(h%MUmtrV91;rKoTSX%5idqg)C~R4u=JN{eym=w{Wyj zphngiLtnU}5CKI1eMI)Mb>ag*h4VShnl3=f-1}$-ziKE;Hp=D=s}bHhp@`4gIXyW5 zm`sQu4X8-ijn0@B!?08g1QVl&$>tv2i+c^Q^Qji;=(7kgmU+TlN_hTW27+(d->yP{1z5l z524ccJSnnaLMzp#-*^My0`yoYL&dS=KAD(J6pI5uiQ(}`sxw-%qXwh2*)JNX6oM4X zK+Cq2NWN(5&%|W2EE`XLAShOR*Uv4Kzsv*LFRu0l*o>P64><(}I z1v!Z01W0aa^UJyT6|kGth$0pjR)Xd34e>=D2!Lt4&gYztiVa<>P9gTIqFbJT| zjH%0rkib?bl09Q8HIBs?Ig^&tbU2cdfX4|yz;tQ>9Nc0F0EjRcATYpzR!#X2oaTs> z%s_(??6S9i@&hY@21Odf83-7mO$^Wol7Pt&V3r(F#nD=^r7!F6zrnx00{sWDg6XiG z*BlvZhA@JNNlKa}7_np$i`rgY)jBPxcyO`;$B9EsguJ`blT5Ck>>&}bBQe*~gAF_uW+7?L3902f*U z{yjsE)6t|!0Gf2OExzb;QwN~I{aq7@5+eaXWf!7BD*MDR8)VkG`&5CxQSRPzc%iTJ_mMtS zqzn^@Vei0Nj39O6;wShLFfwN@ShQ$mVFcI%zSn#2a&ZDBK-5-bcQn7HWI!lkGCWfh zCc-ExYrFXikz%ydOhz(5U_72VB~n_pDXBOS!c>eB2@}pkpi*Lh0Dv4r4g)}`HQ+yH zz>t7F4Nl36Tvs1@WJWa*J1Pl^roP92s%jH0*Avpnq0Wkn%E|{g@g4?ra zPDYrMBe|81O}B1s3jlx$+gN4{BPYh0DaSG;s07ndxE0sSTu{YFtNpZOeIH(yC}9K> z=A1Rv8nYM@Mh-dIb$Yter1Pmp13EMA$%a|b!tIMIGamIgF={H;b#5KWV0J%PvPi(R z0W}DQX(DA8ol$_u1)3>&Nf5Dkgv!VPos{hJcPM}W0S;h5VDvI`AT~-y9Hgd3;ut`3 zAO$mBMgqsN1Yls#R&uF~001>Ab_r5I&4e5Wlzg;>79)5Bb)rCoeS@X&pLKzEJq}QOeRMNK;SKR%U^(mc^KXEl3hwb!6+GK94QsY`9}5t;Bh>(ox)D6{c_CK84L7H6bnVnj*-ld;t70TEIoFe#;h2>@VIW|N7MN?~Nr91Q_L zF%l#MPfeANS-J_5Z}jVHs7McuV9#9&=XqDjpbrSSwk0=(1i)Z1-|4ssd)Wb z3Nf*~07DE=Ql+BFGN`sl)?_68Y2h(=f|j&TeX1fPnnXG@PJ_f5Q+b{vj-{dD3-g!~ zAYllD5TH0I(|zn(5weseGmekr5DZVrgyiE(LrzfXh&bH@n{&lP*ak5J;HboqOmPZx zYCt9cH9j?fd98(?ty+Oy=3XG)Ydj43I;VTjfz4bh0N!oDP_lDPWglXt388itRg23izuC{FuoN;P7v zU@%5#5w5{7F$yVZTR6%j0TqH$L?^v)xF}1h)kVV+sHALVIRLbsuwzY}6_rFAjT{|I zkPe;~JiQ_`u?Q`1bmMG^STG6*JX@`qbDs{6g(m=j!C(YUX2{+%*2bI-e*pQv0#jnfeW_LwS|BHn7NNcUdq717r2#(SE2 zD#R62=>iy#JVT+q%mhXX8dXHz^$Z<`jSyipF(aJK63#6F_JH;5U!3zASteyvpa?ZJ zJdYm${=QUQXs08nBtXYN%ba9Z*Ym$!5kTUEGB7#d2@;6VW}jfxk~R-=j|Ggv1QA3c z0ia_O3Xkv2-?1VjP}25q@$mpmh5<-M;%ubgG4JC9g$Sq#0?j>|mNx(Zwaki&69f*@ zBq6axfP(?$II*Wn(vQs2DYjU75=B6SK4nP9)49|zQi#|ixsnqsU>yqN^2a9CF&-6* zSEU@priy=Fd>R%w6;>(~ekO-Y0W{QIz*rI<0aQ@UGbM;YESSJ4+0IDOgy2K|Z?^onbO7-6 z>}Vt0fCPr8W<^_Y?lA%YaF8s*6EL2L(@h%(1Qra!T=qoCC{>`#?(7QW$(DOaX+jzp zxR!NC6$xRa=+ovwa0rvIfC^pQ1;Mc(X*CriGd$gZ8qx2?YhIaCD@#yONj;At00t-h zaW{(`kzhI&0TLy$um~RWaYX=47ST4(jFPh_U;?sWTnkFB*+Lph_KXA)z%U@N@n|QV z^_Krr5n=!{ynG>n@i>7eLY#q_z9#$wepg~Vzkpv70RDS2$^c+M3ju&!mX81cOPLj! z9DxMN0W}r}5TGF^jFF(O6iq5PBIrYb<-~}b*`pszyaF9|{nw)0CbR-?XLl_Y8I5m-g5}9~8 z%((#o0P?xK9uR0G0f+!bzzn7l{BAyApynxmCMD;ofQrRnBoYs(jPs(NuK54}xFgfE zOofqHl#Uk1r^blE(4sfcLfwe`Gz0QM4@=0Qov2cp%BCf)oF^i5e^{NwQz{Y(8{sTh z>GU38C$d#30ZJ{LOfp4)o%?|aEC7Jo^KCgB`b0=WpO&1C1V!sk3+Dm$1vKF}U;r7C zna?s#ry0W4Y?%o_AOwuUD1kE*5Se-)-2QrC=+027;~)TNBnpoNINO9qp65S}$EZBx zuO?W}gQR$Bf&gSdn;grqB~cy#0PWx~jHXbiV__nm6cFJFSP^rz&q{U$tM&vq$l8WxFlQQ5c@#K|R9?4Mz33akdzz+zFP51MY{?mFW6+6$~2id8(PjZVa_|50}_G6@qh@CH&|d_I!_KuT@8Gt6*XGzcv@Z6uPYajzfi1S-2> zM#_LPV`HhOfHe7_>1_Cav;mgN91s`*<9H;FB9gG5z3_?%AmRxQA(%*jArXvI4_GGG z$Ow^Sc)l(BFwX!+#UTL05W$$}_QVbV0356|EJ+X`NoWiW!vIMQ5eB)a!+>hh8P7nZ zA2N>khHxyrp*mMqsTOb`1k@c32a!l>!!J{a)HrNOXqu|Tk_t;ah)y`6%B!f(cnA^R z_yZgSO-;EG0sx0k+i-~u^L`{Ck!F#U410CALDZBW9H|83lt?lw20r8?(>RN#0)j{Y z1SE(s7>}IDl-VvQYq|nN*3l-15d?sMh^JE71{%AKoH>T_5ns%^07*%K0TRzDEj)p= z`0SQOQ!-bKM6Tm7fWh=(1c?9?nvimLsjF3^M7bCd1D{7Ih(j1~*~!gJs6(}isuE|| z8FM(;6h-IaDJ7CQ4(r64WteiSP3Szs8PM4K!-Y9doWN;jp;X4k34iax?>gr!H`g(9z_NnCcH z?lFDJ6Cow&gNg9CiN0(TP(6$ePsa%~97&J@GUukyeBNOq9ggA&m=r_;Fiu1w!e(VT z&}<&EMBxb{ATTV5W#TDQjR4T1d4umDU>w5B1QTBHF{_d(pdgV$1|E*aTTH)R3{qYE)DxUYiWP@us{DD{`6x>izbDMcGIas-dZudO$}m1 zoRo`zKhE<20Gw|ng*Yh;!FU`YAOHjuNbx0q3owU}>DYy6R?&C>s5syz&zcU%`6^1B zf+Il~1Oy;(LgrmPb4OsPKmmA;P=KTa2?Pf;C_x}V-fIo?;1q71({6Gl4O2;p!T?<) zH8V)k&dKuah3EbB|NP6p-waCa`=Y8ks6OQAsM|(0G-r<^={O(-@0BM)nEADPb#4}r z;w@c`^14ubQm38Rv$;3OC(urQvY2_4JvI4KMULoh)(fyXQHPPs=G z5u{KoQI=>Jl2L#rr-6|)W7NV!VJiif+czsMI3Xq1q#RO+qz%(k9YHfbo!cl=I>)D7 zma%1wijp9bz)@eJ?%24eO`pKh;FU~HVOr(ivuh-`@6DmE3<{yfr}*R5-eR}vz`wo_ z5+svJ_DClYkUwbIVF05ev!Dj~tCWD25s9&gMIvd)@Gt=Y0Wf@dA)yD5P0`cC#qpgEmBM?#0Y$CY=C_xZ_5(gv%JHT*VkU}g=;;MU- z11CNJRG3HCB<&A0hDQ5m@l5Kc{_kHuyC$W#9xpxboqoFH6*&6i=+aDOm@OsONa&ti zQH7DMcA-`Z*Zf=`EUGYk#xXxrpJ}%M5G+iJ1d6S58aZl>(!Za900|OIn-_`sQxl~0 zCy_A{4v!?I8%YF20DLdldDrt>%XpS(OJl4h6)Ln6Ra65=r4 zG;1mnSl$xk1PqTQFq}CfC4m4KG&+}pWO{@{u|z2m%~NS0g%*;&b|#3T$ziS4>RHY- z_nvoiw0iG$gZ8Pbcxa4aU<2w?V;3n&Aq|XXYDt7CTtb={*?Pi}kWmySE&BxL>VBd(9%tstG;01ml@do{I6RDmi2$IDuyZO9b+M$RA}|$0B1uRjfk%-8 zc`=?#0W?M|%}9nJhzLXIp$jpTp@+WpmCX@F9VL#kKI`?`0AhjDsQV|V7uj!3c)$*%PUi-jF|N6BOISZQ0?PoYXT**z0z;IZJ_L^kQA{s{u z(&6v$cc8H5@xi5Jd&or&EKo=qr^>P<8Z}$gaFYXnT{q; z@^!otVCixk4Th1!Xe59z%eWb}90DoE6jd0;0X`lN0xU!cjr>#o0NYfIK2F3j91j9& z!g{te0@2&ra_dM05JBeD7@mj&0s)e_dqNr@jspuDdgUokLLVB)p~Atot^3zJ_#LnI zL~H>M@1ojvcYI5auiP%J@A>|=+Y8Sdiro0c&6jGxcvSiIeZqc6w9ho*wG71j> z5`;*O8}8Krq!~jDEPw}ioB-n_Qc9`@-sO++Fx@PosYysuBmy8nOqPaL>oiSV{8BFG zJd%jORAz>ZvxP_`JPl#z%LcSGua)jiV<4DaZDbgU*aPA2CXveBsS3Lf$uad;j z#nOVVvGwA9A3Rde$F4Km&wm=r3%3uR=QB!FI-p^ZCq6Ea_+aqlhSXz|EPa|7w$7X>1kAY_UlX6^&M^-M+Gz>vBrQ(_E-uvpNLja?)L=>Tfcr=Uf9wid#`(2 zdfvZ2ANRfZ&UxM~_+Nj!x_#yAYu^pqwJF!a_W5u5l^g`lpa?2n7oudDL?lzl6cP!; zvUc+lT@yPVVNq`GqV%_TcTjRv_$UhQvFE`Jvbyfup9avB<(V>vyv`yGMv3#BeRee5 z(69&q0!ZjEOZuFbHDiu|#x=P~BLETNI1$DPn4C8OAmw$=69kop62>FRWEc>s%ziZL zZ8Zg!t!QEx4gyLP5RnKNPtEK|Y0a&k^{zBP$#&vS;rn`EwtEs8mBhgqdfdSvvCdFx zRh_oy&aZ!cf34?d=EtAUx?SYTRw!xr==#hTs)yI5-K4Wh5NKfLArU+VGv}}jWY+l! zL+KJx5!SiBF8h6F3sUNPqx@xAWQ4BB_aVVA2pqqcBJSy&HcMp!sl} z9f}YH7Kf1#kO6{(^?%q?xaschSLm>96c#%5DCLbN$%z-h8C7~ z^Z^XQfEq(d5mNLtiIEDuwtMOVq)Jq8rDlJ9{pQ_k)$}rJ(#RsaPNg%$)4R16C}Az{4PltlquIeJ`O^Bxw^h| z_4T)R^-2yqk>b;PzwmvqFx5~r!YOA-Lqi`j$MYn}Sx)#G+VHeAG<2jKl{>NcxHCK8 z-#FM92Z}%dgCPjf2+L?H%j{DEG!{ij<7iSk984hAz=j3T;t5iCasmK?z}QC;SR@2A z!Kydi=2fJ0KrG38HT7ocD-sn>gG6MZ)oI0&gGf~FxF~WyY{G!%*W6N>QG6$@fI^7+aq`bk=|QEF ziuyeH*B|)xhx@$7=NSbw7Wtap`4HaCF%miF^X9yooGbElbCNy|$%16wUB_nufqy4w z3Zvmc0y#*)0G^pe{x`=s7>S0-@yJOraxws1nw}N*a@TY)fdWXz6KVW=mS&Mtr^i6dtXhy%*{a@qmx-G6 zyu;mM^RAWWlQU^W1&Sm+8lZuSwOQpIVSv$#wTV3E4OOTy)hZ!<&1WbXHnMu_=cS8k z#7c@Xzl0{-xSM!uXINTsn$oI$GuO$PaqiI0XY!QhWCl7q!Q!&F-_8DftB-nlstbXC zYZYRRg%L<#VMv5YSpEy|hUqg$(Fi#Sr7|UO0D&7*5o>87JoEEdk3_&QLZ${xnMnke zAW`}QSVqH;LO_I#3`;3(Ge(}hO@;-8lO1&(?r51Mc`?IGqC>4QrkOIMw^D1h+T8p8 zHSQ&zk2H30TVQme$bbf`qb`#rnd4-z`iO=u$wEP)$FrcKtqQrn4 z(9jpGw4W&~Jz}a4CLqUHo-EDt(NWjzOfEUE*JXQpPQSIalTK^?>;IL{Cwre5b4y>d;>xAA;etgnnMKYLMgB=9R7{`0MiyrxW3}Ausfr{NMUm*mf=?xZjW}hID2nJ` zZeAT-t#q;2+ATvhm^iZ^H(o6qt=KN^-}L6BA)$B7-Nr`bgG6Du|wrObQ5Ugn$G|DFYhz%w_Wy$@( zf<@1K;e=XY)(#s0d&6HmEti)VGqYEGdK{Jx$QNKRtur&b<~K#4f$K^ z3Oq4g%c!c4<&H{kv(?50BOvzAiUchg00Kq=$i2LlJA6SZfk2p&7$YX&kqBtag#fgi zQM>6@hn`RqI1wP!ltUJbEJK_O({T5kN%j>>t+y%>)+^Hav z$=f{%Nn)e|1R~kY<61qI>orcCvTJh2OrLX00W^@0a~Ucu1?%)V5-t^pUH%nLWOhmP zU~!YEm049HX^5a_Hz%qh5fk4fDp86+wX+e>F$Pqn5lHz`bYqnir`9>c5X%Hd?4weS zxWnS)2!M&%=5k7c<1=MsOl6{^B*G)4G-=hBji*4$CrmBjB@zY!0%KS#0aN4CFlWg* z->u_^UVmm;E(&X)V=n1*pc8scF`CP=rA}2K5Qqdr0Z~{}7a!1|p6dlR7lR3uV_0iH$6S*r0sv^`MklYByi&n}WfjYEK*u@@x3O)yX6$Bq?yiBY z=2@>FIj1)))5i&vOvF#&ICrzcX(yP2L}Ds}MAFk=S0{&ov;(+!s;?uaMgbtgI5~=B zK5I1lxjF9|-PirL6K?eqb@;N}+RManQw5&;(%0ShnP;}5#lY`IgHi$FL>DWmMFcCT za3HPeXmOh1@~d%`r0=u6L5w`n_B7kkVo1yW%_wqkFhn~i;CM(Z_>kU=?p#`($#ob- zIdVSvf!u3+73%|!rTW0Et(|&G-yDcv)t3R(pdxPXW?WRO+knRL;^_~B*nr= zQgSSnlgoW~@7mb#QMH91{+o96e!5YQL#}3@oSc-*TJS~Mzjr5oNz2%H0{)#R7uHLN zApw{O0WBG2o17GhBiiQ228Zvp@wHpFtapKtcug7{jv|-_S?tnp?QcAF zP$DpI0@>qN%tq2pzfY!&sf{HkB^Z9QZn0Q zGMA*ZwB*crcfOIARiC@(8#?^%c~9Gs6?0-3kv6B6=Y@yCh%Zx#p>J3B)aCzkT7c@> zUx!qcC(7iCQKfQt-EJx2=#G_-6W#>?u|E_*Nevv?KOTGcm(DgLH31;Pw7Vwr)>Uuc z*Vf3hkuqjZ=yt)|%F4L^DV;UO18Q&TyztzCO^l9?5=UZ`1XBVgky4nMQXzA7^ws^e+SF>T`H3$HS-|Kx*$q|#L!?}&u>!+z#C{gOcv0Vb zyvzuo!9BgTkDGlXC325-Z`|fx`M^H1T!!VG_j3+>b?33t8 zg^e~X0Wd=ENn=Zlf%RTLN>tD+Yb7ne}NS`(utoy8+DP~}# zrlB=**6ACqk-R8nicYGzB27R{?_B@#)RYWDC?8moH09m3eaEzV!!@7)h}kjLJ8i-) z(*PXt+t)sK(p8~a0s?2sOiJKUjD5k>%uAQFA_o3{%aSpsVUCd)yjT&?1_XMVdr$WZ z2Z=NglU50g-RHc=1Nwhv!gejYlYQrCyHMg7a~vLnarvXozunR(58(efPeGMHF>;J} zBcrAj2vn~}Rj6_$xbohRK6{Oc6KJ3-IO)Vs8hHpDSpa}KZEgC+vIk%fszF8zVL5u| zTfMd)_)z3-@e7^Q;{V>X>^ zCt<&*zI1cuYXAUl`SQ)R?=y0rNJhfJSk0eIuActJ(=%TK44wRUv*_QL=LIlhU~EQa z11Bt${O<%&#f@p-Vn9bWV=|pkE_)v1foLE&E8GT>FfbNV$Hdx+pL+^m4NnqJl9-5z zBuo{jU!Qa@Cg8ciJITmYk}nEXBwxV|v4M?ujo)LDbdG~Dmk=%r9tBheNB#8Vb9Nv0 zDPt~!1SxqnHX4PS#5BFL@z$yDtY;5nEiOV>cd@k3+B&VN9X%niD&rKT2(ki&u@78d zT7Ra`sQz>WGDv-FMiG;m4J*>qs%9)> z`*e#OBf98t_3+=lDbET}U;N4@ylGiYm@$mzIUv_S62|qmYyR|QKtpb5`v2!(kg*Gn z9Vm;VjM5uhDjH$V4mxj*jWpP$!%@#fUWW+#+US?j4Nm0}lDAuY@cM19ykL5mgiaWm?`yPW;E zA7P?aD!YgOb@0mGdJ3P$X}>$~`1I4~{l?OGQ1+Yn2{RgNe%X&{-p)EXAqEHsoVd3a z4ZbCfbI@Qnhj08?ij55I?zr;k<$I1EXpC`knv)L3X+O0z?M(nO9_7WuXzb7{4uNnG zqG*ALKvHZlFnMZ-hmfZ46XRkbXYM>sH(VMnAat;O& zh-x~-SCrA1lHR-70|20bEl^zO$-1fR-%R|knRHdko2IbF4Jl23eBM~_=iF!Qf4iC< z8jbhX&UR$jWbT-5S({$2#M<`qxX-V?rG0**;<@v#RJaGQT5m(AgRueO1AYMj4}JJC z7a5N`?>FX@=g}=DU{o3dPiyl3P90WEFaht!{rUB`|M};`w>BT2n!LN1eY4`5_!3~| zhLjRzYyeDVJD`QPalo&;=vU_SSvr8qJHKM{DZe?FR~uk!V*902gZp=T`YSfS^f{-^ z{L9Jp0d~H}cY=%&Os9c1UcrU+a6b68o6q>wB~Z<;yWkg=^Iz;&C`>nUBWc%_{Rh4a zs3iksFvu7|838V*9@D;uzwRCr{$m0SNpaHOESu?p$;!3td5?wTj(}=Xkb#Raf-Ev| z0IvLvS@3^=rW5|1VW|Nokj?bg=8s4nDRD)BF#@0?%#24I`=?6)U}~XT$hxTwHo|pm zecut>riv7%LdO_E8(k>)kMZk3-!m-wuJaT_17NzXA2u+N(yexV;7|o1J!1sT=&-Q& zZ94pL;MY%E+4R;0h*YtoKX>{8zKm$fG#@GmH?#SpM`)8O-c%SPXu{8V&-2*#u9v^l z0_=NM{)xIygqdgB@al0uAFS_@cU&~2bf^HOWS^=0{e~KOG(w}1z!*U*`s%{po^$_J z>J7klL%4^25dqA;bnV@D|LI<9ASzAyw)s&*ID^d}ypTuub!@?{9J7qXWPmN~U<+PG zN1}(sVc2$%;^g07f(0*F9{Um#Q<2U;yK`^1$(@Q8+R}TrGT6fC0mq_yimG=Tv;GcS za0Az{5(7J*b1nbkZC>XaRwFVhQb@l&E#ojcKYq#u{`y! z=3s9J0Y*VW06G8w08(%RpkeLXCPbw~5ed(x zTzd7QO?Ta4%RRsKzwcRQzuwZ180oj>*}pTneu}fulO{YD+W%l5eBqe*y6>F#($6_h zAHVOO`~La#&4QU#r!E#8$&6E)l-$~n8gg_2l(pQ)t4I(E_vZAM&D<*{ zzf$2FreP6R*1=1kceb2$UX=2>dHqi>A>-i$LzV3PA3aBiaoL}~4D?>O=`n}DzW2AE zR{Gj+J@%`QXnyjYE1vzp!>3MYr4}P1CX5IalZgqDgM7v}_y9m*N$1pGo#+4Ly5sDO zJH9gK`c|;xZ60fg8_fGV01P~(@{b;mF#0Kmi&`FNNO*$-X;{d$z~-)CUiRVW7mfXR z>QmmaVQWO-SpFGRKF|U(d4>OQ5WcP-`@i#?f12NX-g|^D5OKyUzRJ~Ecs+5-cnCzT zc%QNJ>6`2Cz3;?VeJ%a^#Y;Zpj$By>XZ_Wi7JmFk2eyt9;Sf3HZ) z$og7W|J0oKqG?*SgnzM|Fka**DtPteJ94Y(sUv6al9XFNlG;t{-tGCN|FMj}I)ReC z|D)$Tn=>%#aqvFHFE;h>Cjel@=Pv&EgaU}fqeH=h`8fYHXbSLfaQ z>ahp!1P>hTd3;zrR2G*F<>y7pYVYw!yU!V{>sNN}hsOA~HuHUie|ULHngDp4q_LT& zzGZan{`kG>Yqy!Wzzx0pp{Kq5xZQwJFXdf?x$C}n9RT1yTkYF5cqa1^zNKF?9GCTm z5+9qw3K*(eWg5tAMM6PeOn=1qmkm+@RwdT9tsj{?b^OkZmJ;*U;fsG>-+Q1N0PHQ} zmK#r4acwW3oqYfD-Y400v%hub=}?LpK{uJd$u$B0o&Nc8NWHryMXG@ zjCEcd?UW!P7P;5xR{@n z*K+)1@F;SXu35h5?%}m1i-&=s{;~|L_hz&!`3V3O%~-fI`i`3RzC~;JIZLcc=gT?|90Us&u&dH^f`;(#RDHYd`kp?ItynTu0Ay_ z05F(Zyc`urnKp7w0T39e8dn(SrNj?^JAT{WpD=P?;W_#l1%WoI$a~GyFJkL?MwM?L z$ukZsmy?0J8EsD*K*L3gx3n!zxnOTb1GDy@8X6WAbLWlcth9`)K*V*|#)FHsx8D5j zNFXi`CE@`9fZFl+;W(*A1VHo28XkAj=%f4me!~L|@B?5}Y{!Q|!R;9Qr>c1GQTf~g zsdOe_=28f2-fn~@wCK&Jet7l0r&}_lu1+bL-Dc6w5=57D`OPyE*H6#umyx0mjI*sX zhm7M1Xjl;=d%AV;?yDsB<7RXOL=qXe)TWOp`&F~_|1!>Tz0k%CPdo4qP}J0AV0Y zFKpfPwtaVYvEh0h%bUo!0Hfs+PNMZGoRzJYbjY}>?=;#DIT6U@M6Mzekj@qGTKet_ zsig_{bN#B7Z~D#k%MlGsUOW(KrD7g~tcwrMoPPfBIccE=tUkFIII5(Z58ip+jTg>c zz8trGfkeRQ88;Lk;@C(|*TJV^0suhSfx=()IY8UyRZp+){{Lo4lW6(3Z(2}pvAOPL z0H1o}zU98IjWtzyubP8=@zKLdIxjE>FxOb%u#JF-?bH#!e~Bj@p;3T4%4vf$p{8ii ztfTvEC7c!vt<9;%@mxRKphjsd`GiDlT*-wL08D%};G!458)*H?|8uO_H$(#qt~{{Y zvbkAh0B4{4v+YtM69|a++~|}mRaL3bB*%x zsu~~$FLp+CZdxgR;@@n0Kh;c*vQAvvIl%zt9iFixgz_4L&97!|omW+ZsfLpR$EeN^ zNWZ-mXg?vHUt1#h|$TUZBjLO$?+qX|QAQ z`z(nroi_dY-bjVgd3k{e}8GR7h>z zCvp{8o!XZI9K?qcYZgHC73%HQYPYdfZst?uoH9GNI$6eqHTmF%SY&f(dnow2_rb$qpb z1B+>p-nQrP-Ymv)P3h#{TNAd*w@D&{1V(QGo?k0FFCoyQ}}UAJZ-`{lBjhOjvT3 zgCB1ga1u*V^Pi3pF=Kdh?Rx7#K9d=(SqrwjGXenEn^TWm@efPQ(r3RmO?juW6m1AC zM_U(5dj6S|cMOh1%YH+qj&SaOFzIBU=#v*g`&v82JFN4x%E&)b3TKYRSojYeTwpQS zZgqKoD~jBvTjhm40%m=Xt^5fh4wNH8MhG-$laMbnj_3Z(SQ2ENjNWdAg|B<_H-GNm z6al95^2CG!wv7jk7z8DrWQPUB50?&h zh74S8)4L8OizAVZd;%uj+WmABNDQz7JD%Ct_W-$}LC`_}-Tg;C>q@+13__LPWM2*@ zL*B*J1pvUXN?hfMfB~@!PV|X0xtR+a%o#BMZqgdA{Ac zweYVUp2Yx?Hg)zCv1GPC_`XW1{k& zv3{qZp@x{Joc{;gHeJg*!IC_SHspv!XRl4pO}{=gyU&$J8wKRT0j}Vc%TJoIw6We= zkh+8`*~-~~NsLFpez1G(jrG+#!eRpx>Q_?EireBI50<29-gV)G#W1esbT3@|*Ja(h zj^n8$5deUJrDZQ+6Sn%(`!A6q=CKF>Qu&D8yvUDq5@5!oPXCYP{Fjz@ll3TunX|uk z-`*umH~Pl`;2jm%mik5!QXds)H#$!roAajsixQk3`1|`k^VfHLSjYL3B&>{E_)8YF zzw~&8343k(jBeMVL}iQd001Cd#2385pSU5!VXQ9t?|I2TET{JAYf&sNH?Mwt;1QuC z0CeU4_xu; zQPLXMtgg7@c8Sa-mjM#d@dv5ANESQUy^N@oGj0sxS?6BD@*0J~^Q1cQ97X3lH3 z0brsF!;xM0J<6Y$rBSJa>q)2RC<6chIQrQU z$n>O2fWIwQn7FvbI_o{;m3-!q;$ZkCxGNV8=g;R+wLX%-J!0b2)w_D`gXj zSeoy+t(QcG5FP~Cn3NLw=^?Wx)5y4&PhdWj{|Ep8jg&C3p+BqNFp#%&r~h)NODwZ; zwwGn2rcRB^lIjn+SdTP#>bN+@GXz-Wp)@J5be`FB(MrneCSX?5o}SHbH_iU;;KrXG zj_-t;tN2`U{>jvhuT0!HXX@zejQB2R9{`yHlKib^uM1@^?J;Zs02<3+ zb9wvrKXz|?d$-zG12dM5eHj}+ORifp@|KkLCpCB6#*BhiEG-F4Uo&YtEIU+13^(Yi$Wh)>W7`yr;oosYEkmKnS5R1^*A(gJ*fi^^+`lALyS35x#$~fP}=7o za(W@tL*xCsyYmKFe3f%m?!@#-h5ek^O~VjDUBlbv9rY0y`0Cqc+#OIV`e^ZRoN76= z0_y~aiM#*u)hE8>vu)>Ydg$`4nl9g_W^uo+#Yv=D7)O9 zJUflt^{24py>6EY%v zzXwF676a+V-R0)Hj{acB?isytO1NKfA2Ci>(ziAkd#0oHg4Za1#VmY;<#wdl`4I(2 zodh;=L)ol!&b^ydp!vFLyLa?oR|Cs+*9l4pn%ANYRbtKSh;ZFhzIx#9)dTIv2esAP z_ud*3I#SniU*DX+S#E#tk-&9;Ar`83rw;Ey${XXeKZIk!k*J;fOslu9Iqc8m=2%waQUcU4b-LmKU;Ma0JY?$>_)W;%`s7+_SnHDHZ7L)dmF zD<^}t9=#&hxBhN_?=u;8yTkeAX(qdO&}-cpBC=xnEfz|=lu!ci`Q#Wdn4@hrCc_`x z`fU0p^#}$Gi?m9=x})UE^>J(>z(1ihL}imr1S=B6-AytIZ9ZyS|4>=u8zrRp$2xZm ziDQ{&Gs*t_PcKLX4jH)2odf{z=R=67 z-72ekW(*Hll?umR%z4&vaB6Gs2}N+7l_!Ojs+E#B?ximrzD+9nF1F;oN7vR+BrpLz z;2-c^2zb0;3KK4(oA23M^}yqq7Dmc1+d{_%E}DS=h8!t$ixBt6@6(o~wiB<~2Eu0n zIiJ0QVeN1LyzIbJSpbC>OheEo%S+>>QMCl_X2<>G{_i+*>suF`ibkWxdoB6EQT@z( zk&i^;5CH##cZvYrK5=o(CHn?m_XzcSk6bHcC*s#fQ40b9n8^IHarBb}fN#C+kEImE zubAs&OW%-jM?S^>ilMzgLgE*`#VD{zEfD5?mf>%@kof&~K-dzM_ES2&(hc%Y%@jaZU9aGdtIqGat6@^r~{pG%0&q*0q! z+UvQ@-=O3RB8IxJRRch#o=SFOrv(Ct!^V8hpb!h-pK`qi015zI1qm%PX1D^u;v!K!001ROD+U5&V?hA?69oX;{UyBs literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000000000000000000000000000000000000..bfc3c600c5e808bc6d9e464452b0b00abfa34ff0 GIT binary patch literal 18736 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 f&h-jg{yT14_IZ9T!d%0YB!)tk7+RlR^*X literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000000000000000000000000000000000000..77261971e8c276d9f162cc223209ea8ba9853a39 GIT binary patch literal 17650 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000000000000000000000000000000000000..41927c662c7ae4ee432301b233f62f2ee57188df GIT binary patch literal 23018 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..f8c6127 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..adced57 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + Yobble + \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..00c2614 --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,5 @@ + + + +