├── .gitignore
├── .idea
├── .gitignore
├── compiler.xml
├── gradle.xml
├── jarRepositories.xml
├── misc.xml
└── vcs.xml
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── example
│ │ └── dispatch
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── example
│ │ │ └── dispatch
│ │ │ ├── app
│ │ │ └── App.kt
│ │ │ ├── di
│ │ │ ├── DataModule.kt
│ │ │ └── DomainModule.kt
│ │ │ └── presentation
│ │ │ ├── MainActivity.kt
│ │ │ ├── currentUserProfile
│ │ │ ├── CurrentUserProfileContract.kt
│ │ │ ├── view
│ │ │ │ ├── CurrentUserProfileFragment.kt
│ │ │ │ └── ValidEditTextUserDetails.kt
│ │ │ └── viewmodel
│ │ │ │ └── CurrentUserProfileViewModel.kt
│ │ │ ├── detailsMessages
│ │ │ ├── DetailsMessagesContract.kt
│ │ │ ├── view
│ │ │ │ ├── DeleteMessagesDialog.kt
│ │ │ │ ├── DetailsMessagesFragment.kt
│ │ │ │ ├── MessageFromItem.kt
│ │ │ │ └── MessageToItem.kt
│ │ │ └── viewmodel
│ │ │ │ └── DetailsMessagesViewModel.kt
│ │ │ ├── latestMessages
│ │ │ ├── LatestMessagesContract.kt
│ │ │ ├── view
│ │ │ │ ├── LatestMessageItem.kt
│ │ │ │ └── LatestMessagesFragment.kt
│ │ │ └── viewmodel
│ │ │ │ └── LatestMessagesViewModel.kt
│ │ │ ├── listUsers
│ │ │ ├── ListUsersContract.kt
│ │ │ ├── view
│ │ │ │ ├── ListUsersFragment.kt
│ │ │ │ └── UserItem.kt
│ │ │ └── viewmodel
│ │ │ │ └── ListUsersViewModel.kt
│ │ │ ├── restorePassword
│ │ │ ├── RestorePasswordContract.kt
│ │ │ ├── view
│ │ │ │ └── RestorePasswordFragment.kt
│ │ │ └── viewmodel
│ │ │ │ └── RestorePasswordViewModel.kt
│ │ │ ├── signIn
│ │ │ ├── SignInContract.kt
│ │ │ ├── view
│ │ │ │ └── SignInFragment.kt
│ │ │ └── viewmodel
│ │ │ │ └── SignInViewModel.kt
│ │ │ ├── signUp
│ │ │ ├── SignUpContract.kt
│ │ │ ├── view
│ │ │ │ └── SignUpFragment.kt
│ │ │ └── viewmodel
│ │ │ │ └── SignUpViewModel.kt
│ │ │ └── splash
│ │ │ ├── SplashScreenContract.kt
│ │ │ ├── view
│ │ │ └── SplashScreenFragment.kt
│ │ │ └── viewmodel
│ │ │ └── SplashScreenViewModel.kt
│ └── res
│ │ ├── drawable-v24
│ │ ├── ic_launcher_foreground.xml
│ │ └── splash_screen.png
│ │ ├── drawable
│ │ ├── background_circle.xml
│ │ ├── background_content_bottom.xml
│ │ ├── background_content_top.xml
│ │ ├── background_details_messages_input.xml
│ │ ├── background_edittext.xml
│ │ ├── background_recipient_message.xml
│ │ ├── background_sender_message.xml
│ │ ├── background_shapeableimageview.xml
│ │ ├── background_view_circle.xml
│ │ ├── ic_account_circle.xml
│ │ ├── ic_arrow_back.xml
│ │ ├── ic_calendar_month.xml
│ │ ├── ic_cleaning_services.xml
│ │ ├── ic_delete.xml
│ │ ├── ic_info.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── ic_lock.xml
│ │ ├── ic_logout.xml
│ │ ├── ic_mail.xml
│ │ ├── ic_more_vert.xml
│ │ ├── ic_person.xml
│ │ ├── ic_remove_circle.xml
│ │ ├── ic_send.xml
│ │ ├── ic_translate.xml
│ │ └── ic_two_user_circle.xml
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ ├── fragment_current_user_profile.xml
│ │ ├── fragment_details_messages.xml
│ │ ├── fragment_latest_messages.xml
│ │ ├── fragment_list_users.xml
│ │ ├── fragment_restore_password.xml
│ │ ├── fragment_sign_in.xml
│ │ ├── fragment_sign_up.xml
│ │ ├── fragment_splash_screen.xml
│ │ ├── item_container_latest_message.xml
│ │ ├── item_container_recipient_message.xml
│ │ ├── item_container_sender_message.xml
│ │ └── item_container_user.xml
│ │ ├── menu
│ │ ├── bottom_menu.xml
│ │ └── details_messages_menu.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── navigation
│ │ └── nav_graph.xml
│ │ ├── values-night
│ │ └── themes.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ ├── styles.xml
│ │ └── themes.xml
│ └── test
│ └── java
│ └── com
│ └── example
│ └── dispatch
│ └── ExampleUnitTest.kt
├── build.gradle
├── data
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── example
│ │ └── dispatch
│ │ └── data
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ └── java
│ │ └── com
│ │ └── example
│ │ └── dispatch
│ │ └── data
│ │ ├── repository
│ │ ├── MessageRepositoryImpl.kt
│ │ ├── TranslateRepositoryImpl.kt
│ │ ├── UserAuthRepositoryImpl.kt
│ │ ├── UserDetailsRepositoryImpl.kt
│ │ └── UserImagesRepositoryImpl.kt
│ │ └── storage
│ │ ├── MessageStorage.kt
│ │ ├── TranslateStorage.kt
│ │ ├── UserAuthStorage.kt
│ │ ├── UserDetailsStorage.kt
│ │ ├── UserImagesStorage.kt
│ │ ├── firebase
│ │ ├── FirebaseMessageStorage.kt
│ │ ├── FirebaseUserAuthStorage.kt
│ │ ├── FirebaseUserDetailsStorage.kt
│ │ └── FirebaseUserImagesStorage.kt
│ │ └── mlkit
│ │ └── MlKitTranslateStorage.kt
│ └── test
│ └── java
│ └── com
│ └── example
│ └── dispatch
│ └── data
│ └── ExampleUnitTest.kt
├── domain
├── .gitignore
├── build.gradle
└── src
│ └── main
│ └── java
│ └── com
│ └── example
│ └── dispatch
│ └── domain
│ ├── constants
│ └── LanguageCodeConstants.kt
│ ├── models
│ ├── FromToUser.kt
│ ├── Message.kt
│ ├── Response.kt
│ ├── UserAuth.kt
│ ├── UserDetails.kt
│ └── UserDetailsPublic.kt
│ ├── repository
│ ├── MessageRepository.kt
│ ├── TranslateRepository.kt
│ ├── UserAuthRepository.kt
│ ├── UserDetailsRepository.kt
│ └── UserImagesRepository.kt
│ └── usecase
│ ├── ChangeUserAuthEmailUseCase.kt
│ ├── ChangeUserAuthPasswordUseCase.kt
│ ├── ChangeUserDetailsEmailUseCase.kt
│ ├── ChangeUserDetailsFullnameUseCase.kt
│ ├── ChangeUserDetailsPasswordUseCase.kt
│ ├── ChangeUserDetailsPhotoProfileUrlUseCase.kt
│ ├── CheckUserAuthSignedInUseCase.kt
│ ├── DeleteCurrentUserAuthUseCase.kt
│ ├── DeleteCurrentUserDetailsUseCase.kt
│ ├── DeleteDialogBothUsersUseCase.kt
│ ├── DeleteLatestMessagesBothUsersUseCase.kt
│ ├── DeleteUserImageProfileUseCase.kt
│ ├── DownloadLangRussianEnglishPackUseCase.kt
│ ├── GetCurrentUserDetailsUseCase.kt
│ ├── GetCurrentUserUidUseCase.kt
│ ├── GetLatestMessagesUseCase.kt
│ ├── GetUserDetailsPublicOnUidUseCase.kt
│ ├── GetUsersListUseCase.kt
│ ├── LanguageIdentifierUseCase.kt
│ ├── ListenFromToUserMessagesUseCase.kt
│ ├── RestoreUserByEmailUseCase.kt
│ ├── SaveLatestMessageUseCase.kt
│ ├── SaveMessageUseCase.kt
│ ├── SaveUserDetailsUseCase.kt
│ ├── SaveUserImageProfileUseCase.kt
│ ├── SignInUserAuthUseCase.kt
│ ├── SignOutUserAuthUseCase.kt
│ ├── SignUpUserAuthUseCase.kt
│ ├── TranslateEnglishRussianTextUseCase.kt
│ └── TranslateRussianEnglishTextUseCase.kt
├── github_images
├── example1.png
├── example2.png
├── example3.png
├── example4.png
├── example5.png
├── example6.png
└── example7.png
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 | local.properties
16 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Dispatch
2 |
3 | This project contains a demo messenger for communicating with each other without knowledge of English in English (through a translator), created using Kotlin and Firebase.
4 |
5 | The ideology of the project is to improve the level of English by communicating with each other, sending a message in Russian, it is translated into English and saved in both languages.
6 | It is possible to send a message in English (if you know how to write a sentence in English) - it will be translated into Russian and saved in both languages.
7 | Upon receipt, all messages are displayed in English.
8 |
9 | ## Get started
10 |
11 | To get started you need to first create a Firebase project for your app and add the google-service.json file in your project.
12 | After adding the google-services.json file, you need to create a database in Firebase Authentication, Firebase Database, Firebase Storage.
13 | Firebase Authentication needs to allow user registration by email.
14 |
15 | ## Screenshots
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | ## Demonstration application on youtube video
29 |
30 | You can see the application in action on youtube video hosting at the link: https://youtu.be/KlT0G5GxQU4 .
31 |
32 | ## Used tech
33 |
34 | * [Kotlin](https://kotlinlang.org/)
35 | * [Kotlin flows](https://developer.android.com/kotlin/flow)
36 | * [Clean Architecture](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) - Clean architecture in Android.
37 | * [MVVM](https://developer.android.com/jetpack/docs/guide) - Architectural pattern.
38 | * [Dagger Hilt](https://developer.android.com/training/dependency-injection/hilt-android) - Standard library to incorporate Dagger dependency injection into an Android application.
39 | * [Coroutines](https://kotlinlang.org/docs/reference/coroutines-overview.html) - Asynchronous programming.
40 | * [View Binding](https://developer.android.com/topic/libraries/data-binding/) - Declaratively bind observable data to UI elements.
41 | * [Lifecycles](https://developer.android.com/topic/libraries/architecture/lifecycle) - Create a UI that automatically responds to lifecycle events.
42 | * [LiveData](https://developer.android.com/topic/libraries/architecture/livedata) - Build data objects that notify views when the underlying database changes.
43 | * [Navigation](https://developer.android.com/guide/navigation/) - Handle everything needed for in-app navigation.
44 | * [Firebase](https://firebase.google.com/docs) - Tools to develop high-quality apps.
45 | * [SDP](https://github.com/intuit/sdp) - Scalable size unit.
46 | * [SSP](https://github.com/intuit/sdp) - Scalable size unit for text.
47 | * [Android Image Cropper](https://github.com/ArthurHub/Android-Image-Cropper) - Powerful (Zoom, Rotation, Multi-Source), customizable (Shape, Limits, Style), optimized (Async, Sampling, Matrix) and simple image cropping library for Android.
48 | * [Picasso](https://github.com/square/picasso) - Load and cache images by URL.
49 | * [Groupie](https://github.com/lisawray/groupie) - Groupie is a simple, flexible library for complex RecyclerView layouts.
50 | * [Ml-Kit Translator](https://developers.google.com/ml-kit/language/translation) - Ml-Kit translator API.
51 | * [Ml-kit Language](https://developers.google.com/ml-kit/language/identification/android) - Ml-Kit language id identificator for text.
52 |
53 | ## Find this repository useful? ❤
54 |
55 | Support it by joining stargazers for this repository 🌟
56 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'org.jetbrains.kotlin.android'
4 | id 'com.google.gms.google-services'
5 | id 'kotlin-kapt'
6 | id 'dagger.hilt.android.plugin'
7 | }
8 |
9 | android {
10 | compileSdk 32
11 |
12 | defaultConfig {
13 | applicationId "com.example.dispatch"
14 | minSdk 21
15 | targetSdk 32
16 | versionCode 1
17 | versionName "1.0"
18 |
19 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
20 | }
21 |
22 | buildTypes {
23 | release {
24 | minifyEnabled false
25 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
26 | }
27 | }
28 | buildFeatures {
29 | viewBinding true
30 | }
31 | compileOptions {
32 | sourceCompatibility JavaVersion.VERSION_1_8
33 | targetCompatibility JavaVersion.VERSION_1_8
34 | }
35 | kotlinOptions {
36 | jvmTarget = '1.8'
37 | }
38 | }
39 |
40 | dependencies {
41 |
42 | implementation 'androidx.core:core-ktx:1.7.0'
43 | implementation 'androidx.appcompat:appcompat:1.4.1'
44 | implementation 'com.google.android.material:material:1.5.0'
45 | implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
46 | implementation "androidx.fragment:fragment-ktx:1.4.1"
47 |
48 | // navigation component
49 | implementation "androidx.navigation:navigation-fragment-ktx:2.4.2"
50 | implementation "androidx.navigation:navigation-ui-ktx:2.4.2"
51 | implementation "androidx.navigation:navigation-dynamic-features-fragment:2.4.2"
52 |
53 | // sdp and ssp / scalable size unit
54 | implementation 'com.intuit.sdp:sdp-android:1.0.6'
55 | implementation 'com.intuit.ssp:ssp-android:1.0.6'
56 |
57 | // dagger hilt
58 | implementation 'com.google.dagger:hilt-android:2.41'
59 | implementation 'androidx.legacy:legacy-support-v4:1.0.0'
60 | kapt 'com.google.dagger:hilt-compiler:2.41'
61 |
62 | // coroutines
63 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0'
64 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0'
65 |
66 | // lifecycle
67 | implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1'
68 | implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1'
69 | implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.4.1'
70 |
71 | // crop image view
72 | implementation 'com.theartofdev.edmodo:android-image-cropper:2.8.0'
73 |
74 | // picasso
75 | implementation 'com.squareup.picasso:picasso:2.71828'
76 | implementation 'jp.wasabeef:picasso-transformations:2.4.0'
77 |
78 | // groupie RecyclerView
79 | implementation 'com.github.lisawray.groupie:groupie:2.9.0'
80 | implementation 'com.github.lisawray.groupie:groupie-viewbinding:2.9.0'
81 |
82 | testImplementation 'junit:junit:4.13.2'
83 | androidTestImplementation 'androidx.test.ext:junit:1.1.3'
84 |
85 | implementation project(path: ':domain')
86 | implementation project(path: ':data')
87 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/example/dispatch/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4
4 | import androidx.test.platform.app.InstrumentationRegistry
5 | import org.junit.Assert.assertEquals
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | /**
10 | * Instrumented test, which will execute on an Android device.
11 | *
12 | * See [testing documentation](http://d.android.com/tools/testing).
13 | */
14 | @RunWith(AndroidJUnit4::class)
15 | class ExampleInstrumentedTest {
16 | @Test
17 | fun useAppContext() {
18 | // Context of the app under test.
19 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
20 | assertEquals("com.example.dispatch", appContext.packageName)
21 | }
22 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
13 |
14 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/dispatch/app/App.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.app
2 |
3 | import android.app.Application
4 | import dagger.hilt.android.HiltAndroidApp
5 |
6 | @HiltAndroidApp
7 | class App : Application()
8 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/dispatch/di/DataModule.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.di
2 |
3 | import com.example.dispatch.data.repository.*
4 | import com.example.dispatch.data.storage.*
5 | import com.example.dispatch.data.storage.firebase.FirebaseMessageStorage
6 | import com.example.dispatch.data.storage.firebase.FirebaseUserAuthStorage
7 | import com.example.dispatch.data.storage.firebase.FirebaseUserDetailsStorage
8 | import com.example.dispatch.data.storage.firebase.FirebaseUserImagesStorage
9 | import com.example.dispatch.data.storage.mlkit.MlKitTranslateStorage
10 | import com.example.dispatch.domain.repository.*
11 | import dagger.Module
12 | import dagger.Provides
13 | import dagger.hilt.InstallIn
14 | import dagger.hilt.components.SingletonComponent
15 | import kotlinx.coroutines.ExperimentalCoroutinesApi
16 | import javax.inject.Singleton
17 |
18 | @Module
19 | @ExperimentalCoroutinesApi
20 | @InstallIn(SingletonComponent::class)
21 | class DataModule {
22 | @Provides
23 | @Singleton
24 | fun providesUserAuthStorage(): UserAuthStorage {
25 | return FirebaseUserAuthStorage()
26 | }
27 |
28 | @Provides
29 | @Singleton
30 | fun providesUserAuthRepository(userAuthStorage: UserAuthStorage): UserAuthRepository {
31 | return UserAuthRepositoryImpl(userAuthStorage = userAuthStorage)
32 | }
33 |
34 | @Provides
35 | @Singleton
36 | fun providesUserDetailsStorage(): UserDetailsStorage {
37 | return FirebaseUserDetailsStorage()
38 | }
39 |
40 | @Provides
41 | @Singleton
42 | fun providesUserDetailsRepository(userDetailsStorage: UserDetailsStorage): UserDetailsRepository {
43 | return UserDetailsRepositoryImpl(userDetailsStorage = userDetailsStorage)
44 | }
45 |
46 | @Provides
47 | @Singleton
48 | fun providesUserImagesStorage(): UserImagesStorage {
49 | return FirebaseUserImagesStorage()
50 | }
51 |
52 | @Provides
53 | @Singleton
54 | fun providesUserImagesRepository(userImagesStorage: UserImagesStorage): UserImagesRepository {
55 | return UserImagesRepositoryImpl(userImagesStorage = userImagesStorage)
56 | }
57 |
58 | @Provides
59 | @Singleton
60 | fun providesTranslateStorage(): TranslateStorage {
61 | return MlKitTranslateStorage()
62 | }
63 |
64 | @Provides
65 | @Singleton
66 | fun providesTranslateRepository(translateStorage: TranslateStorage): TranslateRepository {
67 | return TranslateRepositoryImpl(translateStorage = translateStorage)
68 | }
69 |
70 | @Provides
71 | @Singleton
72 | fun providesMessageStorage(): MessageStorage {
73 | return FirebaseMessageStorage()
74 | }
75 |
76 | @Provides
77 | @Singleton
78 | fun providesMessageRepository(messageStorage: MessageStorage): MessageRepository {
79 | return MessageRepositoryImpl(messageStorage = messageStorage)
80 | }
81 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/dispatch/presentation/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.presentation
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import androidx.appcompat.app.AppCompatActivity
6 | import androidx.navigation.NavController
7 | import androidx.navigation.Navigation
8 | import androidx.navigation.ui.NavigationUI
9 | import com.example.dispatch.R
10 | import com.example.dispatch.databinding.ActivityMainBinding
11 | import dagger.hilt.android.AndroidEntryPoint
12 |
13 | @AndroidEntryPoint
14 | class MainActivity : AppCompatActivity() {
15 | private lateinit var binding: ActivityMainBinding
16 | private lateinit var navController: NavController
17 |
18 | override fun onCreate(savedInstanceState: Bundle?) {
19 | super.onCreate(savedInstanceState)
20 | binding = ActivityMainBinding.inflate(layoutInflater)
21 | setContentView(binding.root)
22 |
23 | setupNav()
24 | }
25 |
26 | private fun setupNav() {
27 | navController = Navigation.findNavController(this, R.id.container_fragment)
28 | NavigationUI.setupWithNavController(binding.bottomNavigation, navController)
29 |
30 | navController.addOnDestinationChangedListener { _, destination, _ ->
31 | when (destination.id) {
32 | R.id.currentUserProfileFragment -> showBottomNav()
33 | R.id.latestMessagesFragment -> showBottomNav()
34 | else -> hideBottomNav()
35 | }
36 | }
37 | }
38 |
39 | private fun showBottomNav() {
40 | binding.bottomNavigation.visibility = View.VISIBLE
41 |
42 | }
43 |
44 | private fun hideBottomNav() {
45 | binding.bottomNavigation.visibility = View.GONE
46 | }
47 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/dispatch/presentation/currentUserProfile/view/ValidEditTextUserDetails.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.presentation.currentUserProfile.view
2 |
3 | class ValidEditTextUserDetails(
4 | var fullname: Boolean = false,
5 | var email: Boolean = false
6 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/example/dispatch/presentation/currentUserProfile/viewmodel/CurrentUserProfileViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.presentation.currentUserProfile.viewmodel
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import androidx.lifecycle.ViewModel
6 | import androidx.lifecycle.liveData
7 | import com.example.dispatch.domain.models.Response
8 | import com.example.dispatch.domain.models.UserAuth
9 | import com.example.dispatch.domain.models.UserDetails
10 | import com.example.dispatch.domain.usecase.*
11 | import com.example.dispatch.presentation.currentUserProfile.CurrentUserProfileContract
12 | import dagger.hilt.android.lifecycle.HiltViewModel
13 | import kotlinx.coroutines.Dispatchers
14 | import kotlinx.coroutines.ExperimentalCoroutinesApi
15 | import javax.inject.Inject
16 |
17 | @HiltViewModel
18 | @ExperimentalCoroutinesApi
19 | class CurrentUserProfileViewModel @Inject constructor(
20 | private val signOutUserAuthUseCase: SignOutUserAuthUseCase,
21 | private val getCurrentUserDetailsUseCase: GetCurrentUserDetailsUseCase,
22 | private val saveUserImageProfileUseCase: SaveUserImageProfileUseCase,
23 | private val changeUserDetailsPhotoProfileUrlUseCase: ChangeUserDetailsPhotoProfileUrlUseCase,
24 | private val changeUserAuthEmailUseCase: ChangeUserAuthEmailUseCase,
25 | private val changeUserAuthPasswordUseCase: ChangeUserAuthPasswordUseCase,
26 | private val changeUserDetailsEmailUseCase: ChangeUserDetailsEmailUseCase,
27 | private val changeUserDetailsPasswordUseCase: ChangeUserDetailsPasswordUseCase,
28 | private val changeUserDetailsFullnameUseCase: ChangeUserDetailsFullnameUseCase,
29 | ) : ViewModel(), CurrentUserProfileContract.CurrentUserProfileViewModel {
30 |
31 | private val _cropImageView = MutableLiveData("")
32 | val cropImageView: LiveData = _cropImageView
33 |
34 | val _userDetails = MutableLiveData()
35 | val userDetails: LiveData = _userDetails
36 |
37 | override fun signOutUserAuth(): LiveData> = liveData(Dispatchers.IO) {
38 | try {
39 | signOutUserAuthUseCase.execute().collect { emit(it) }
40 | } catch (e: Exception) {
41 | emit(Response.Fail(e = e))
42 | }
43 | }
44 |
45 | override fun getCurrentUserDetails(): LiveData> =
46 | liveData(Dispatchers.IO) {
47 | try {
48 | getCurrentUserDetailsUseCase.execute().collect { emit(it) }
49 | } catch (e: Exception) {
50 | emit(Response.Fail(e = e))
51 | }
52 | }
53 |
54 | override fun saveUserImageProfile(imageUriCache: String): LiveData> =
55 | liveData(Dispatchers.IO) {
56 | try {
57 | saveUserImageProfileUseCase.execute(newImageUriStr = imageUriCache)
58 | .collect { emit(it) }
59 | } catch (e: Exception) {
60 | emit(Response.Fail(e))
61 | }
62 | }
63 |
64 | override fun changeUserDetailsPhotoProfileUrl(imageUriStr: String): LiveData> =
65 | liveData(Dispatchers.IO) {
66 | try {
67 | changeUserDetailsPhotoProfileUrlUseCase.execute(newImageUriStr = imageUriStr)
68 | .collect { emit(it) }
69 | } catch (e: Exception) {
70 | emit(Response.Fail(e))
71 | }
72 | }
73 |
74 | override fun changeUserAuthEmail(
75 | userAuth: UserAuth,
76 | newEmail: String
77 | ): LiveData> =
78 | liveData(Dispatchers.IO) {
79 | try {
80 | changeUserAuthEmailUseCase.execute(userAuth = userAuth, newEmail = newEmail)
81 | .collect { emit(it) }
82 | } catch (e: Exception) {
83 | emit(Response.Fail(e = e))
84 | }
85 | }
86 |
87 | override fun changeUserDetailsEmail(newEmail: String): LiveData> =
88 | liveData(Dispatchers.IO) {
89 | try {
90 | changeUserDetailsEmailUseCase.execute(newEmail = newEmail).collect { emit(it) }
91 | } catch (e: Exception) {
92 | emit(Response.Fail(e = e))
93 | }
94 | }
95 |
96 | override fun changeUserAuthPassword(
97 | userAuth: UserAuth,
98 | newPassword: String
99 | ): LiveData> =
100 | liveData(Dispatchers.IO) {
101 | try {
102 | changeUserAuthPasswordUseCase.execute(
103 | userAuth = userAuth,
104 | newPassword = newPassword
105 | )
106 | .collect { emit(it) }
107 | } catch (e: Exception) {
108 | emit(Response.Fail(e = e))
109 | }
110 | }
111 |
112 | override fun changeUserDetailsPassword(newPassword: String): LiveData> =
113 | liveData(Dispatchers.IO) {
114 | try {
115 | changeUserDetailsPasswordUseCase.execute(newPassword = newPassword)
116 | .collect { emit(it) }
117 | } catch (e: Exception) {
118 | emit(Response.Fail(e = e))
119 | }
120 | }
121 |
122 | override fun changeUserDetailsFullname(newFullname: String): LiveData> =
123 | liveData(Dispatchers.IO) {
124 | try {
125 | changeUserDetailsFullnameUseCase.execute(newFullname = newFullname)
126 | .collect { emit(it) }
127 | } catch (e: Exception) {
128 | emit(Response.Fail(e = e))
129 | }
130 | }
131 |
132 | override fun saveUserImageLiveData(imageUriStr: String) {
133 | if (imageUriStr.isNotEmpty()) {
134 | _cropImageView.value = imageUriStr
135 | }
136 | }
137 |
138 | override fun deleteUserImageLiveData() {
139 | _cropImageView.value = ""
140 | }
141 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/dispatch/presentation/detailsMessages/view/DeleteMessagesDialog.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.presentation.detailsMessages.view
2 |
3 | import android.app.Dialog
4 | import android.os.Bundle
5 | import androidx.appcompat.app.AlertDialog
6 | import androidx.fragment.app.DialogFragment
7 | import com.example.dispatch.presentation.detailsMessages.DetailsMessagesContract
8 | import kotlinx.coroutines.ExperimentalCoroutinesApi
9 |
10 | @ExperimentalCoroutinesApi
11 | class DeleteMessagesDialog(private val dialogClickListener: DetailsMessagesContract.DeleteMessagesDialogClickListener) :
12 | DialogFragment() {
13 | override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
14 | return activity?.let {
15 | val alertDialog = AlertDialog.Builder(it)
16 | .setTitle("Deleting messages")
17 | .setMessage(
18 | "Are you sure you want to clear your chat history?" +
19 | " Messages will be deleted from both users."
20 | ).setPositiveButton("YES") { _, _ ->
21 | dialogClickListener.onClickPositive()
22 | }.setNegativeButton("CANCEL") { dialog, _ ->
23 | dialog.cancel()
24 | }
25 |
26 | alertDialog.create()
27 | } ?: throw IllegalStateException("Activity is null!")
28 | }
29 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/dispatch/presentation/detailsMessages/view/MessageFromItem.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.presentation.detailsMessages.view
2 |
3 | import android.view.View
4 | import com.example.dispatch.R
5 | import com.example.dispatch.databinding.ItemContainerSenderMessageBinding
6 | import com.example.dispatch.domain.models.Message
7 | import com.xwray.groupie.viewbinding.BindableItem
8 | import java.sql.Date
9 | import java.sql.Timestamp
10 | import java.text.SimpleDateFormat
11 |
12 | class MessageFromItem(private val message: Message) :
13 | BindableItem() {
14 | override fun bind(viewBinding: ItemContainerSenderMessageBinding, position: Int) {
15 | viewBinding.textViewMessage.text = message.englishMessage
16 |
17 | val netDate = Date(Timestamp(message.timestamp).time)
18 | val date = SimpleDateFormat("dd/MM/yy hh:mm a").format(netDate)
19 | viewBinding.textViewDateTime.text = date
20 |
21 | var textEnglish: Boolean = true
22 | viewBinding.imageviewTranslated.setOnClickListener {
23 | if (textEnglish) {
24 | viewBinding.textViewMessage.text = message.russianMessage
25 | textEnglish = false
26 | } else {
27 | viewBinding.textViewMessage.text = message.englishMessage
28 | textEnglish = true
29 | }
30 | }
31 | }
32 |
33 | override fun getLayout(): Int {
34 | return R.layout.item_container_sender_message
35 | }
36 |
37 | override fun initializeViewBinding(view: View): ItemContainerSenderMessageBinding {
38 | return ItemContainerSenderMessageBinding.bind(view)
39 | }
40 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/dispatch/presentation/detailsMessages/view/MessageToItem.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.presentation.detailsMessages.view
2 |
3 | import android.view.View
4 | import com.example.dispatch.R
5 | import com.example.dispatch.databinding.ItemContainerRecipientMessageBinding
6 | import com.example.dispatch.domain.models.Message
7 | import com.xwray.groupie.viewbinding.BindableItem
8 | import java.sql.Date
9 | import java.sql.Timestamp
10 | import java.text.SimpleDateFormat
11 |
12 | class MessageToItem(private val message: Message) :
13 | BindableItem() {
14 | override fun bind(viewBinding: ItemContainerRecipientMessageBinding, position: Int) {
15 | viewBinding.textViewMessage.text = message.englishMessage
16 |
17 | val netDate = Date(Timestamp(message.timestamp).time)
18 | val date = SimpleDateFormat("dd/MM/yy hh:mm a").format(netDate)
19 | viewBinding.textViewDateTime.text = date
20 |
21 | var textEnglish: Boolean = true
22 | viewBinding.imageviewTranslated.setOnClickListener {
23 | if (textEnglish) {
24 | viewBinding.textViewMessage.text = message.russianMessage
25 | textEnglish = false
26 | } else {
27 | viewBinding.textViewMessage.text = message.englishMessage
28 | textEnglish = true
29 | }
30 | }
31 | }
32 |
33 | override fun getLayout(): Int {
34 | return R.layout.item_container_recipient_message
35 | }
36 |
37 | override fun initializeViewBinding(view: View): ItemContainerRecipientMessageBinding {
38 | return ItemContainerRecipientMessageBinding.bind(view)
39 | }
40 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/dispatch/presentation/detailsMessages/viewmodel/DetailsMessagesViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.presentation.detailsMessages.viewmodel
2 |
3 | import androidx.lifecycle.*
4 | import com.example.dispatch.domain.models.FromToUser
5 | import com.example.dispatch.domain.models.Message
6 | import com.example.dispatch.domain.models.Response
7 | import com.example.dispatch.domain.models.UserDetailsPublic
8 | import com.example.dispatch.domain.usecase.*
9 | import com.example.dispatch.presentation.detailsMessages.DetailsMessagesContract
10 | import dagger.hilt.android.lifecycle.HiltViewModel
11 | import kotlinx.coroutines.Dispatchers
12 | import kotlinx.coroutines.ExperimentalCoroutinesApi
13 | import kotlinx.coroutines.launch
14 | import javax.inject.Inject
15 |
16 | @HiltViewModel
17 | @ExperimentalCoroutinesApi
18 | class DetailsMessagesViewModel @Inject constructor(
19 | private val getUserDetailsPublicOnUidUseCase: GetUserDetailsPublicOnUidUseCase,
20 | private val translateRussianEnglishTextUseCase: TranslateRussianEnglishTextUseCase,
21 | private val translateEnglishRussianTextUseCase: TranslateEnglishRussianTextUseCase,
22 | private val languageIdentifierUseCase: LanguageIdentifierUseCase,
23 | private val getCurrentUserUidUseCase: GetCurrentUserUidUseCase,
24 | private val saveMessageUseCase: SaveMessageUseCase,
25 | private val listenFromToUserMessagesUseCase: ListenFromToUserMessagesUseCase,
26 | private val deleteDialogBothUsersUseCase: DeleteDialogBothUsersUseCase,
27 | private val saveLatestMessageUseCase: SaveLatestMessageUseCase,
28 | private val deleteLatestMessagesBothUsersUseCase: DeleteLatestMessagesBothUsersUseCase
29 | ) : ViewModel(), DetailsMessagesContract.DetailsMessagesViewModel {
30 |
31 | val _companionUid = MutableLiveData()
32 | val companionUid: LiveData = _companionUid
33 |
34 | val _companionDetails = MutableLiveData()
35 | val companionDetails: LiveData = _companionDetails
36 |
37 | private val _currUserUid = MutableLiveData()
38 | val currUserUid: LiveData = _currUserUid
39 |
40 | override fun getUserDetailsPublicOnUid(uid: String): LiveData> =
41 | liveData(Dispatchers.IO) {
42 | try {
43 | getUserDetailsPublicOnUidUseCase.execute(uid = uid).collect { emit(it) }
44 | } catch (e: Exception) {
45 | emit(Response.Fail(e = e))
46 | }
47 | }
48 |
49 | override fun translateRussianEnglishText(text: String): LiveData> =
50 | liveData(Dispatchers.IO) {
51 | try {
52 | translateRussianEnglishTextUseCase.execute(text = text).collect { emit(it) }
53 | } catch (e: Exception) {
54 | emit(Response.Fail(e = e))
55 | }
56 | }
57 |
58 | override fun translateEnglishRussianText(text: String): LiveData> =
59 | liveData(Dispatchers.IO) {
60 | try {
61 | translateEnglishRussianTextUseCase.execute(text = text).collect { emit(it) }
62 | } catch (e: Exception) {
63 | emit(Response.Fail(e = e))
64 | }
65 | }
66 |
67 | override fun languageIdentifier(text: String): LiveData> =
68 | liveData(Dispatchers.IO) {
69 | try {
70 | languageIdentifierUseCase.execute(text = text).collect { emit(it) }
71 | } catch (e: Exception) {
72 | emit(Response.Fail(e = e))
73 | }
74 | }
75 |
76 | override fun getCurrentUserUid() {
77 | viewModelScope.launch(Dispatchers.IO) {
78 | getCurrentUserUidUseCase.execute().collect { result ->
79 | when (result) {
80 | is Response.Loading -> {}
81 | is Response.Fail -> {}
82 | is Response.Success -> this@DetailsMessagesViewModel._currUserUid.postValue(
83 | result.data
84 | )
85 | }
86 | }
87 | }
88 | }
89 |
90 | override fun saveMessage(message: Message): LiveData> =
91 | liveData(Dispatchers.IO) {
92 | try {
93 | saveMessageUseCase.execute(message = message).collect { emit(it) }
94 | } catch (e: Exception) {
95 | emit(Response.Fail(e = e))
96 | }
97 | }
98 |
99 | override fun saveLatestMessage(message: Message) {
100 | viewModelScope.launch(Dispatchers.IO) {
101 | saveLatestMessageUseCase.execute(message = message).collect {}
102 | }
103 | }
104 |
105 | override fun listenFromToUserMessages(fromToUser: FromToUser): LiveData> =
106 | liveData(Dispatchers.IO) {
107 | try {
108 | listenFromToUserMessagesUseCase.execute(fromToUser = fromToUser)
109 | .collect { emit(it) }
110 | } catch (e: Exception) {
111 | emit(Response.Fail(e = e))
112 | }
113 | }
114 |
115 | override fun deleteDialogBothUsers(fromToUser: FromToUser) {
116 | viewModelScope.launch(Dispatchers.IO) {
117 | deleteDialogBothUsersUseCase.execute(fromToUser = fromToUser).collect { result ->
118 | when (result) {
119 | is Response.Success -> deleteLatestMessageBothUsers(fromToUser = fromToUser)
120 | else -> {}
121 | }
122 | }
123 | }
124 | }
125 |
126 | override fun deleteLatestMessageBothUsers(fromToUser: FromToUser) {
127 | viewModelScope.launch(Dispatchers.IO) {
128 | deleteLatestMessagesBothUsersUseCase.execute(fromToUser = fromToUser).collect {}
129 | }
130 | }
131 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/dispatch/presentation/latestMessages/LatestMessagesContract.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.presentation.latestMessages
2 |
3 | import com.example.dispatch.domain.models.Message
4 | import com.example.dispatch.domain.models.UserDetailsPublic
5 | import kotlinx.coroutines.flow.Flow
6 |
7 | interface LatestMessagesContract {
8 | interface LatestMessagesFragment {
9 | /**
10 | * Sets the required setOnClickListener on the views fragment
11 | */
12 | fun setOnClickListeners()
13 |
14 | /**
15 | * Observer userDetails LiveData from [LatestMessagesViewModel]
16 | */
17 | fun userDetailsObserver()
18 |
19 | /**
20 | * Observer progressBarLoadUserDetails LiveData from [LatestMessagesViewModel]
21 | */
22 | fun progressBarLoadUserDetailsObserver()
23 |
24 | /**
25 | * Observer loadCurrentUserDetailsSuccess LiveData from [LatestMessagesViewModel]
26 | */
27 | fun loadCurrentUserDetailsSuccessObserver()
28 |
29 | /**
30 | * Observer latestMessagesList LiveData from [LatestMessagesViewModel]
31 | */
32 | fun latestMessagesListObserver()
33 |
34 | /**
35 | * Observer progressBarLoadLatestMessagesList LiveData from [LatestMessagesViewModel]
36 | */
37 | fun progressBarLoadLatestMessagesListObserver()
38 |
39 | /**
40 | * Observer loadLatestMessagesList LiveData from [LatestMessagesViewModel]
41 | */
42 | fun loadLatestMessagesListObserver()
43 |
44 | /**
45 | * Shows progress bar load user details
46 | */
47 | fun showProgressBarLoadUserDetails()
48 |
49 | /**
50 | * Hides progress bar load user details
51 | */
52 | fun hideProgressBarLoadUserDetails()
53 |
54 | /**
55 | * Shows progress bar load latest messages
56 | */
57 | fun showProgressBarLoadLatestMessages()
58 |
59 | /**
60 | * Hides progress bar load latest messages
61 | */
62 | fun hideProgressBarLoadLatestMessages()
63 |
64 | /**
65 | * Show toast Toast.LENGTH_LONG type
66 | * @param text - text, shown in toast
67 | */
68 | fun showToastLengthLong(text: String)
69 |
70 | /**
71 | * Navigate to ListUsersFragment
72 | */
73 | fun navigateToListUsersFragment()
74 |
75 | /**
76 | * Add user item into adapter, update adapter
77 | * @param message - [Message] model
78 | * @param user - [UserDetailsPublic] model
79 | */
80 | fun adapterAddLatestMessage(message: Message, user: UserDetailsPublic)
81 |
82 | /**
83 | * Navigate to DetailsMessagesFragment, passing the uid of the user selected
84 | * in the adapter to the fragment
85 | * @param selectedUserUid - selected user (uid) from adapter
86 | */
87 | fun navigateToDetailsMessagesFragmentTransferSelectedUser(selectedUserUid: String)
88 | }
89 |
90 | interface LatestMessagesViewModel {
91 | /**
92 | * Getting the details of the currently logged in user
93 | */
94 | fun getCurrentUserDetails()
95 |
96 | /**
97 | * Get ArrayList all latest messages current user
98 | * @param currentUserUid - [String] uid current user
99 | */
100 | fun getLatestMessages(currentUserUid: String)
101 |
102 | /**
103 | * Get user details by his uid
104 | * @param uid - [String] uid user
105 | */
106 | fun getUserDetailsPublicOnUid(uid: String): Flow
107 |
108 | /**
109 | * Clear latestMessagesList LiveData from [LatestMessagesViewModel]
110 | */
111 | fun latestMessagesListClear()
112 | }
113 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/dispatch/presentation/latestMessages/view/LatestMessageItem.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.presentation.latestMessages.view
2 |
3 | import android.view.View
4 | import com.example.dispatch.R
5 | import com.example.dispatch.databinding.ItemContainerLatestMessageBinding
6 | import com.example.dispatch.domain.models.Message
7 | import com.example.dispatch.domain.models.UserDetailsPublic
8 | import com.squareup.picasso.Picasso
9 | import com.xwray.groupie.viewbinding.BindableItem
10 | import jp.wasabeef.picasso.transformations.CropCircleTransformation
11 |
12 | class LatestMessageItem(
13 | val message: Message,
14 | val companionUser: UserDetailsPublic
15 | ) : BindableItem() {
16 | override fun bind(viewBinding: ItemContainerLatestMessageBinding, position: Int) {
17 | viewBinding.latestMessage.text = message.englishMessage
18 | viewBinding.textViewUserName.text = companionUser.fullname
19 | if (companionUser.photoProfileUrl.isNotEmpty()) {
20 | Picasso.get().load(companionUser.photoProfileUrl).transform(CropCircleTransformation())
21 | .into(viewBinding.imageViewUserPhoto)
22 | }
23 | }
24 |
25 | override fun getLayout(): Int {
26 | return R.layout.item_container_latest_message
27 | }
28 |
29 | override fun initializeViewBinding(view: View): ItemContainerLatestMessageBinding {
30 | return ItemContainerLatestMessageBinding.bind(view)
31 | }
32 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/dispatch/presentation/latestMessages/viewmodel/LatestMessagesViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.presentation.latestMessages.viewmodel
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import androidx.lifecycle.ViewModel
6 | import androidx.lifecycle.viewModelScope
7 | import com.example.dispatch.domain.models.Message
8 | import com.example.dispatch.domain.models.Response
9 | import com.example.dispatch.domain.models.UserDetails
10 | import com.example.dispatch.domain.models.UserDetailsPublic
11 | import com.example.dispatch.domain.usecase.GetCurrentUserDetailsUseCase
12 | import com.example.dispatch.domain.usecase.GetCurrentUserUidUseCase
13 | import com.example.dispatch.domain.usecase.GetLatestMessagesUseCase
14 | import com.example.dispatch.domain.usecase.GetUserDetailsPublicOnUidUseCase
15 | import com.example.dispatch.presentation.latestMessages.LatestMessagesContract
16 | import dagger.hilt.android.lifecycle.HiltViewModel
17 | import kotlinx.coroutines.Dispatchers
18 | import kotlinx.coroutines.ExperimentalCoroutinesApi
19 | import kotlinx.coroutines.flow.Flow
20 | import kotlinx.coroutines.flow.flow
21 | import kotlinx.coroutines.launch
22 | import javax.inject.Inject
23 |
24 | @HiltViewModel
25 | @ExperimentalCoroutinesApi
26 | class LatestMessagesViewModel @Inject constructor(
27 | private val getCurrentUserDetailsUseCase: GetCurrentUserDetailsUseCase,
28 | private val getLatestMessagesUseCase: GetLatestMessagesUseCase,
29 | private val getUserDetailsPublicOnUidUseCase: GetUserDetailsPublicOnUidUseCase,
30 | private val getCurrentUserUidUseCase: GetCurrentUserUidUseCase
31 | ) : ViewModel(), LatestMessagesContract.LatestMessagesViewModel {
32 |
33 | private val _userDetails = MutableLiveData(UserDetails())
34 | val userDetails: LiveData = _userDetails
35 |
36 | private val _progressBarLoadUserDetails = MutableLiveData()
37 | val progressBarLoadUserDetails: LiveData = _progressBarLoadUserDetails
38 |
39 | private val _loadCurrentUserDetailsSuccess = MutableLiveData>()
40 | val loadCurrentUserDetailsSuccess: LiveData> = _loadCurrentUserDetailsSuccess
41 |
42 | private val _latestMessagesList = MutableLiveData>()
43 | val latestMessagesList: LiveData> = _latestMessagesList
44 |
45 | private val _progressBarLoadLatestMessagesList = MutableLiveData()
46 | val progressBarLoadLatestMessagesList: LiveData = _progressBarLoadLatestMessagesList
47 |
48 | private val _loadLatestMessagesList = MutableLiveData>()
49 | val loadLatestMessagesList: LiveData> = _loadLatestMessagesList
50 |
51 | private val _currentUserUid = MutableLiveData()
52 | val currentUserUid: LiveData = _currentUserUid
53 |
54 | override fun getCurrentUserDetails() {
55 | viewModelScope.launch(Dispatchers.IO) {
56 | getCurrentUserDetailsUseCase.execute().collect { result ->
57 | when (result) {
58 | is Response.Loading -> _progressBarLoadUserDetails.postValue(true)
59 | is Response.Fail -> {
60 | _progressBarLoadUserDetails.postValue(false)
61 | _loadCurrentUserDetailsSuccess.postValue(Response.Fail(e = result.e))
62 | }
63 | is Response.Success -> {
64 | _progressBarLoadUserDetails.postValue(false)
65 | _loadCurrentUserDetailsSuccess.postValue(Response.Success(data = true))
66 | this@LatestMessagesViewModel._userDetails.postValue(result.data)
67 | getLatestMessages(currentUserUid = result.data.uid)
68 | }
69 | }
70 | }
71 | }
72 | }
73 |
74 | override fun getLatestMessages(currentUserUid: String) {
75 | viewModelScope.launch(Dispatchers.IO) {
76 | getLatestMessagesUseCase.execute(fromUserUid = currentUserUid).collect { result ->
77 | when (result) {
78 | is Response.Loading -> _progressBarLoadLatestMessagesList.postValue(true)
79 | is Response.Fail -> {
80 | _progressBarLoadLatestMessagesList.postValue(false)
81 | _loadLatestMessagesList.postValue(Response.Fail(e = result.e))
82 | }
83 | is Response.Success -> {
84 | _progressBarLoadLatestMessagesList.postValue(false)
85 | _loadLatestMessagesList.postValue(Response.Success(data = true))
86 | this@LatestMessagesViewModel._latestMessagesList.postValue(result.data)
87 | }
88 | }
89 | }
90 | }
91 | }
92 |
93 | override fun getUserDetailsPublicOnUid(uid: String): Flow = flow {
94 | getUserDetailsPublicOnUidUseCase.execute(uid = uid).collect { result ->
95 | when (result) {
96 | is Response.Success -> emit(result.data)
97 | else -> {}
98 | }
99 | }
100 | }
101 |
102 | override fun latestMessagesListClear() {
103 | _latestMessagesList.value?.clear()
104 | }
105 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/dispatch/presentation/listUsers/ListUsersContract.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.presentation.listUsers
2 |
3 | import com.example.dispatch.domain.models.UserDetailsPublic
4 |
5 | interface ListUsersContract {
6 | interface ListUsersFragment {
7 | /**
8 | * Sets the required setOnClickListener on the views fragment
9 | */
10 | fun setOnClickListeners()
11 |
12 | /**
13 | * Observer usersList LiveData from [ListUsersViewModel]
14 | */
15 | fun usersListObserver()
16 |
17 | /**
18 | * Observer progressBarListUsers LiveData from [ListUsersViewModel]
19 | */
20 | fun progressBarListUsersObserver()
21 |
22 | /**
23 | * Shows progress bar list users
24 | */
25 | fun showProgressBarListUsers()
26 |
27 | /**
28 | * Hides progress bar list users
29 | */
30 | fun hideProgressBarListUsers()
31 |
32 | /**
33 | * Add user item into adapter, update adapter
34 | * @param userDetailsPublic - [UserDetailsPublic] model user
35 | */
36 | fun adapterAddItemUser(userDetailsPublic: UserDetailsPublic)
37 |
38 | /**
39 | * Navigate to pop back stack
40 | */
41 | fun navigateToPopBackStack()
42 |
43 | /**
44 | * Navigate to DetailsMessagesFragment, passing the uid of the user selected
45 | * in the adapter to the fragment
46 | * @param selectedUserUid - selected user (uid) from adapter
47 | */
48 | fun navigateToDetailsMessagesFragmentTransferSelectedUser(selectedUserUid: String)
49 | }
50 |
51 | interface ListUsersViewModel {
52 | /**
53 | * Get list users
54 | */
55 | fun getUsersList()
56 |
57 | /**
58 | * Get current user uid
59 | */
60 | fun getCurrentUserUid()
61 |
62 | /**
63 | * Clear usersList LiveData
64 | */
65 | fun usersListClear()
66 | }
67 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/dispatch/presentation/listUsers/view/ListUsersFragment.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.presentation.listUsers.view
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import androidx.fragment.app.Fragment
8 | import androidx.fragment.app.viewModels
9 | import androidx.navigation.fragment.findNavController
10 | import com.example.dispatch.R
11 | import com.example.dispatch.databinding.FragmentListUsersBinding
12 | import com.example.dispatch.databinding.ItemContainerUserBinding
13 | import com.example.dispatch.domain.models.UserDetailsPublic
14 | import com.example.dispatch.presentation.detailsMessages.view.DetailsMessagesFragment
15 | import com.example.dispatch.presentation.listUsers.ListUsersContract
16 | import com.example.dispatch.presentation.listUsers.viewmodel.ListUsersViewModel
17 | import com.xwray.groupie.GroupAdapter
18 | import com.xwray.groupie.viewbinding.GroupieViewHolder
19 | import dagger.hilt.android.AndroidEntryPoint
20 | import kotlinx.coroutines.ExperimentalCoroutinesApi
21 |
22 |
23 | @AndroidEntryPoint
24 | @ExperimentalCoroutinesApi
25 | class ListUsersFragment : Fragment(), ListUsersContract.ListUsersFragment {
26 |
27 | private lateinit var binding: FragmentListUsersBinding
28 | private val viewModel: ListUsersViewModel by viewModels()
29 | private val adapter = GroupAdapter>()
30 |
31 | override fun onCreateView(
32 | inflater: LayoutInflater, container: ViewGroup?,
33 | savedInstanceState: Bundle?
34 | ): View {
35 | binding = FragmentListUsersBinding.inflate(inflater, container, false)
36 | return binding.root
37 | }
38 |
39 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
40 | super.onViewCreated(view, savedInstanceState)
41 |
42 | setOnClickListeners()
43 | progressBarListUsersObserver()
44 | usersListObserver()
45 | }
46 |
47 | override fun onStart() {
48 | super.onStart()
49 | viewModel.usersListClear()
50 | adapter.clear()
51 | viewModel.getCurrentUserUid()
52 | viewModel.getUsersList()
53 | }
54 |
55 | override fun setOnClickListeners() {
56 | binding.imageViewBack.setOnClickListener {
57 | navigateToPopBackStack()
58 | }
59 |
60 | adapter.setOnItemClickListener { item, _ ->
61 | val userItem = item as UserItem
62 | val selectedUserUid = userItem.user.uid
63 |
64 | navigateToDetailsMessagesFragmentTransferSelectedUser(selectedUserUid = selectedUserUid)
65 | }
66 | }
67 |
68 | override fun usersListObserver() {
69 | viewModel.usersList.observe(viewLifecycleOwner) { usersList ->
70 | usersList.forEach { userDetailsPublic ->
71 | if (userDetailsPublic.uid != viewModel.currentUserUid.value) {
72 | adapterAddItemUser(userDetailsPublic = userDetailsPublic)
73 | }
74 | }
75 | }
76 | }
77 |
78 | override fun progressBarListUsersObserver() {
79 | viewModel.progressBarListUsers.observe(viewLifecycleOwner) { result ->
80 | if (result) showProgressBarListUsers()
81 | else hideProgressBarListUsers()
82 | }
83 | }
84 |
85 | override fun showProgressBarListUsers() {
86 | binding.progressBarListUsers.visibility = View.VISIBLE
87 | }
88 |
89 | override fun hideProgressBarListUsers() {
90 | binding.progressBarListUsers.visibility = View.INVISIBLE
91 | }
92 |
93 | override fun adapterAddItemUser(userDetailsPublic: UserDetailsPublic) {
94 | adapter.add(UserItem(user = userDetailsPublic))
95 | binding.recyclerViewListUsers.adapter = adapter
96 | }
97 |
98 | override fun navigateToPopBackStack() {
99 | findNavController().popBackStack()
100 | }
101 |
102 | override fun navigateToDetailsMessagesFragmentTransferSelectedUser(selectedUserUid: String) {
103 | findNavController().navigate(
104 | R.id.action_listUsersFragment_to_detailsMessagesFragment,
105 | Bundle().apply {
106 | putString(DetailsMessagesFragment.SELECTED_USER_UID, selectedUserUid)
107 | })
108 | }
109 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/dispatch/presentation/listUsers/view/UserItem.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.presentation.listUsers.view
2 |
3 | import android.view.View
4 | import com.example.dispatch.R
5 | import com.example.dispatch.databinding.ItemContainerUserBinding
6 | import com.example.dispatch.domain.models.UserDetailsPublic
7 | import com.squareup.picasso.Picasso
8 | import com.xwray.groupie.viewbinding.BindableItem
9 | import jp.wasabeef.picasso.transformations.CropCircleTransformation
10 |
11 | class UserItem(val user: UserDetailsPublic) : BindableItem() {
12 | override fun initializeViewBinding(view: View): ItemContainerUserBinding {
13 | return ItemContainerUserBinding.bind(view)
14 | }
15 |
16 | override fun bind(viewBinding: ItemContainerUserBinding, position: Int) {
17 | viewBinding.textViewFullname.text = user.fullname
18 | viewBinding.textViewEmail.text = user.email
19 |
20 | if (user.photoProfileUrl.isNotEmpty()) {
21 | Picasso.get().load(user.photoProfileUrl).transform(CropCircleTransformation())
22 | .into(viewBinding.shapeableImageViewProfileImage)
23 | }
24 | }
25 |
26 | override fun getLayout(): Int {
27 | return R.layout.item_container_user
28 | }
29 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/dispatch/presentation/listUsers/viewmodel/ListUsersViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.presentation.listUsers.viewmodel
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import androidx.lifecycle.ViewModel
6 | import androidx.lifecycle.viewModelScope
7 | import com.example.dispatch.domain.models.Response
8 | import com.example.dispatch.domain.models.UserDetailsPublic
9 | import com.example.dispatch.domain.usecase.GetCurrentUserUidUseCase
10 | import com.example.dispatch.domain.usecase.GetUsersListUseCase
11 | import com.example.dispatch.presentation.listUsers.ListUsersContract
12 | import dagger.hilt.android.lifecycle.HiltViewModel
13 | import kotlinx.coroutines.Dispatchers
14 | import kotlinx.coroutines.ExperimentalCoroutinesApi
15 | import kotlinx.coroutines.launch
16 | import javax.inject.Inject
17 |
18 | @HiltViewModel
19 | @ExperimentalCoroutinesApi
20 | class ListUsersViewModel @Inject constructor(
21 | private val getUsersListUseCase: GetUsersListUseCase,
22 | private val getCurrentUserUidUseCase: GetCurrentUserUidUseCase
23 | ) : ViewModel(), ListUsersContract.ListUsersViewModel {
24 |
25 | private val _usersList = MutableLiveData>()
26 | val usersList: LiveData> = _usersList
27 |
28 | private val _currentUserUid = MutableLiveData()
29 | val currentUserUid: LiveData = _currentUserUid
30 |
31 | private val _progressBarListUsers = MutableLiveData()
32 | val progressBarListUsers: LiveData = _progressBarListUsers
33 |
34 | override fun getUsersList() {
35 | viewModelScope.launch(Dispatchers.IO) {
36 | getUsersListUseCase.execute().collect { result ->
37 | when (result) {
38 | is Response.Loading -> _progressBarListUsers.postValue(true)
39 | is Response.Fail -> _progressBarListUsers.postValue(false)
40 | is Response.Success -> {
41 | _progressBarListUsers.postValue(false)
42 | this@ListUsersViewModel._usersList.postValue(result.data)
43 | }
44 | }
45 | }
46 | }
47 | }
48 |
49 | override fun getCurrentUserUid() {
50 | viewModelScope.launch(Dispatchers.IO) {
51 | getCurrentUserUidUseCase.execute().collect { result ->
52 | when (result) {
53 | is Response.Success -> this@ListUsersViewModel._currentUserUid.postValue(result.data)
54 | else -> {}
55 | }
56 | }
57 | }
58 | }
59 |
60 | override fun usersListClear() {
61 | _usersList.value?.clear()
62 | }
63 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/dispatch/presentation/restorePassword/RestorePasswordContract.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.presentation.restorePassword
2 |
3 | interface RestorePasswordContract {
4 | interface RestorePasswordFragment {
5 | /**
6 | * Sets the required setOnClickListener on the views fragment
7 | */
8 | fun setOnClickListeners()
9 |
10 | /**
11 | * Observer progressBarRestore LiveData from [RestorePasswordViewModel]
12 | */
13 | fun progressBarRestoreObserver()
14 |
15 | /**
16 | * Observer restoreSuccess LiveData from [RestorePasswordViewModel]
17 | */
18 | fun restoreSuccessObserver()
19 |
20 | /**
21 | * Initializes the email value with a string from the edittext
22 | * @return - initializes [String] email
23 | */
24 | fun editTextEmailInit(): String
25 |
26 | /**
27 | * Checks the edittext for valid data
28 | * @return - corresponding boolean value (correct / incorrect)
29 | */
30 | fun validEditTextShowError(): Boolean
31 |
32 | /**
33 | * Show toast Toast.LENGTH_LONG type
34 | * @param text - text, shown in toast
35 | */
36 | fun showToastLengthLong(text: String)
37 |
38 | /**
39 | * Shows progress bar restore
40 | */
41 | fun showProgressBarRestore()
42 |
43 | /**
44 | * Hides progress bar restore
45 | */
46 | fun hideProgressBarRestore()
47 |
48 | /**
49 | * Navigate to pop back stack
50 | */
51 | fun navigateToPopBackStack()
52 | }
53 |
54 | interface RestorePasswordViewModel {
55 | /**
56 | * Sends an email with instructions for account recovery
57 | * @param email - email associated with the account
58 | */
59 | fun restoreUserByEmail(email: String)
60 | }
61 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/dispatch/presentation/restorePassword/view/RestorePasswordFragment.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.presentation.restorePassword.view
2 |
3 | import android.os.Bundle
4 | import android.util.Patterns
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import android.widget.Toast
9 | import androidx.fragment.app.Fragment
10 | import androidx.fragment.app.viewModels
11 | import androidx.navigation.fragment.findNavController
12 | import com.example.dispatch.databinding.FragmentRestorePasswordBinding
13 | import com.example.dispatch.domain.models.Response
14 | import com.example.dispatch.presentation.restorePassword.RestorePasswordContract
15 | import com.example.dispatch.presentation.restorePassword.viewmodel.RestorePasswordViewModel
16 | import dagger.hilt.android.AndroidEntryPoint
17 | import kotlinx.coroutines.ExperimentalCoroutinesApi
18 |
19 | @AndroidEntryPoint
20 | @ExperimentalCoroutinesApi
21 | class RestorePasswordFragment : Fragment(), RestorePasswordContract.RestorePasswordFragment {
22 | private lateinit var binding: FragmentRestorePasswordBinding
23 | private val viewModel: RestorePasswordViewModel by viewModels()
24 |
25 | override fun onCreateView(
26 | inflater: LayoutInflater, container: ViewGroup?,
27 | savedInstanceState: Bundle?
28 | ): View {
29 | binding = FragmentRestorePasswordBinding.inflate(inflater, container, false)
30 | return binding.root
31 | }
32 |
33 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
34 | super.onViewCreated(view, savedInstanceState)
35 |
36 | setOnClickListeners()
37 | progressBarRestoreObserver()
38 | restoreSuccessObserver()
39 | }
40 |
41 | override fun setOnClickListeners() {
42 | binding.buttonBack.setOnClickListener {
43 | navigateToPopBackStack()
44 | }
45 |
46 | binding.buttonRestore.setOnClickListener {
47 | if (validEditTextShowError()) {
48 | val email = editTextEmailInit()
49 | viewModel.restoreUserByEmail(email = email)
50 | }
51 | }
52 | }
53 |
54 | override fun progressBarRestoreObserver() {
55 | viewModel.progressBarRestore.observe(viewLifecycleOwner) { result ->
56 | if (result) showProgressBarRestore()
57 | else hideProgressBarRestore()
58 | }
59 | }
60 |
61 | override fun restoreSuccessObserver() {
62 | viewModel.restoreSuccess.observe(viewLifecycleOwner) { result ->
63 | when (result) {
64 | is Response.Loading -> {}
65 | is Response.Fail -> showToastLengthLong(text = "Restore password failed: ${result.e}")
66 | is Response.Success -> {
67 | showToastLengthLong(text = "Check your email! ;)")
68 | navigateToPopBackStack()
69 | }
70 | }
71 | }
72 | }
73 |
74 | override fun editTextEmailInit(): String {
75 | return binding.edittextEmail.text.toString()
76 | }
77 |
78 | override fun validEditTextShowError(): Boolean {
79 | val email = binding.edittextEmail.text.toString()
80 |
81 | var valid = false
82 |
83 | when {
84 | email.isEmpty() -> {
85 | binding.edittextEmail.setError("Enter email address.", null)
86 | binding.edittextEmail.requestFocus()
87 | }
88 | !Patterns.EMAIL_ADDRESS.matcher(email).matches() -> {
89 | binding.edittextEmail.setError("Enter valid email address.", null)
90 | binding.edittextEmail.requestFocus()
91 | }
92 | else -> valid = true
93 | }
94 |
95 | return valid
96 | }
97 |
98 | override fun showToastLengthLong(text: String) {
99 | Toast.makeText(activity, text, Toast.LENGTH_LONG)
100 | .show()
101 | }
102 |
103 | override fun showProgressBarRestore() {
104 | binding.progressbarRestore.visibility = View.VISIBLE
105 | binding.buttonRestore.visibility = View.INVISIBLE
106 | }
107 |
108 | override fun hideProgressBarRestore() {
109 | binding.progressbarRestore.visibility = View.INVISIBLE
110 | binding.buttonRestore.visibility = View.VISIBLE
111 | }
112 |
113 | override fun navigateToPopBackStack() {
114 | findNavController().popBackStack()
115 | }
116 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/dispatch/presentation/restorePassword/viewmodel/RestorePasswordViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.presentation.restorePassword.viewmodel
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import androidx.lifecycle.ViewModel
6 | import androidx.lifecycle.viewModelScope
7 | import com.example.dispatch.domain.models.Response
8 | import com.example.dispatch.domain.usecase.RestoreUserByEmailUseCase
9 | import com.example.dispatch.presentation.restorePassword.RestorePasswordContract
10 | import dagger.hilt.android.lifecycle.HiltViewModel
11 | import kotlinx.coroutines.Dispatchers
12 | import kotlinx.coroutines.ExperimentalCoroutinesApi
13 | import kotlinx.coroutines.launch
14 | import javax.inject.Inject
15 |
16 | @HiltViewModel
17 | @ExperimentalCoroutinesApi
18 | class RestorePasswordViewModel @Inject constructor(
19 | private val restoreUserByEmailUseCase: RestoreUserByEmailUseCase
20 | ) : ViewModel(), RestorePasswordContract.RestorePasswordViewModel {
21 |
22 | private val _progressBarRestore = MutableLiveData()
23 | val progressBarRestore: LiveData = _progressBarRestore
24 |
25 | private val _restoreSuccess = MutableLiveData>()
26 | val restoreSuccess: LiveData> = _restoreSuccess
27 |
28 | override fun restoreUserByEmail(email: String) {
29 | viewModelScope.launch(Dispatchers.IO) {
30 | restoreUserByEmailUseCase.execute(email = email).collect { result ->
31 | when (result) {
32 | is Response.Loading -> _progressBarRestore.postValue(true)
33 | is Response.Fail -> {
34 | _progressBarRestore.postValue(false)
35 | _restoreSuccess.postValue(Response.Fail(e = result.e))
36 | }
37 | is Response.Success -> {
38 | _progressBarRestore.postValue(false)
39 | _restoreSuccess.postValue(Response.Success(data = true))
40 | }
41 | }
42 | }
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/dispatch/presentation/signIn/SignInContract.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.presentation.signIn
2 |
3 | import com.example.dispatch.domain.models.UserAuth
4 | import com.example.dispatch.presentation.latestMessages.LatestMessagesContract.LatestMessagesViewModel
5 |
6 | interface SignInContract {
7 | interface SignInFragment {
8 | /**
9 | * Sets the required setOnClickListener on the views fragment
10 | */
11 | fun setOnClickListeners()
12 |
13 | /**
14 | * Initialize the UserAuth variable with values from the corresponding edittext
15 | * @return - initialized [UserAuth]
16 | */
17 | fun editTextUserAuthInit(): UserAuth
18 |
19 | /**
20 | * Checks the edittext for valid data
21 | * @return - corresponding boolean value (correct / incorrect)
22 | */
23 | fun validEditTextShowError(): Boolean
24 |
25 | /**
26 | * Observer progressBarSignIn LiveData from [SignInViewModel]
27 | */
28 | fun progressBarSignInObserver()
29 |
30 | /**
31 | * Observer signInSuccess LiveData from [SignInViewModel]
32 | */
33 | fun signInSuccessObserver()
34 |
35 | /**
36 | * Observer loadRussianEnglishPack LiveData from [LatestMessagesViewModel]
37 | */
38 | fun loadRussianEnglishPackObserver()
39 |
40 | /**
41 | * Show toast Toast.LENGTH_LONG type
42 | * @param text - text, shown in toast
43 | */
44 | fun showToastLengthLong(text: String)
45 |
46 | /**
47 | * Shows progress bar sign in
48 | */
49 | fun showProgressBarSignIn()
50 |
51 | /**
52 | * Hides progress bar sign in
53 | */
54 | fun hideProgressBarSignIn()
55 |
56 | /**
57 | * Navigate to SignUpFragment
58 | */
59 | fun navigateToSignUpFragment()
60 |
61 | /**
62 | * Navigate to RestorePasswordFragment
63 | */
64 | fun navigateToRestorePasswordFragment()
65 |
66 | /**
67 | * Navigate to LatestMessagesFragment
68 | */
69 | fun navigateToLatestMessagesFragment()
70 | }
71 |
72 | interface SignInViewModel {
73 | /**
74 | * User authorization in the system
75 | * @param userAuth - authorization data
76 | */
77 | fun signInUserAuth(userAuth: UserAuth)
78 |
79 | /**
80 | * Download language ru-en pack (ml kit translate)
81 | */
82 | fun downloadLangRussianEnglishPack()
83 | }
84 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/dispatch/presentation/signIn/view/SignInFragment.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.presentation.signIn.view
2 |
3 | import android.os.Bundle
4 | import android.util.Patterns
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import android.widget.Toast
9 | import androidx.fragment.app.Fragment
10 | import androidx.fragment.app.viewModels
11 | import androidx.navigation.fragment.findNavController
12 | import com.example.dispatch.R
13 | import com.example.dispatch.databinding.FragmentSignInBinding
14 | import com.example.dispatch.domain.models.Response
15 | import com.example.dispatch.domain.models.UserAuth
16 | import com.example.dispatch.presentation.signIn.SignInContract
17 | import com.example.dispatch.presentation.signIn.viewmodel.SignInViewModel
18 | import dagger.hilt.android.AndroidEntryPoint
19 | import kotlinx.coroutines.ExperimentalCoroutinesApi
20 |
21 | @AndroidEntryPoint
22 | @ExperimentalCoroutinesApi
23 | class SignInFragment : Fragment(), SignInContract.SignInFragment {
24 | private lateinit var binding: FragmentSignInBinding
25 | private val viewModel: SignInViewModel by viewModels()
26 |
27 | override fun onCreateView(
28 | inflater: LayoutInflater, container: ViewGroup?,
29 | savedInstanceState: Bundle?
30 | ): View {
31 | binding = FragmentSignInBinding.inflate(inflater, container, false)
32 | return binding.root
33 | }
34 |
35 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
36 | super.onViewCreated(view, savedInstanceState)
37 |
38 | viewModel.downloadLangRussianEnglishPack()
39 |
40 | setOnClickListeners()
41 | progressBarSignInObserver()
42 | signInSuccessObserver()
43 | loadRussianEnglishPackObserver()
44 | }
45 |
46 | override fun setOnClickListeners() {
47 | binding.buttonSignUp.setOnClickListener {
48 | navigateToSignUpFragment()
49 | }
50 |
51 | binding.buttonSignIn.setOnClickListener {
52 | if (validEditTextShowError()) {
53 | val userAuth: UserAuth = editTextUserAuthInit()
54 | viewModel.signInUserAuth(userAuth = userAuth)
55 | }
56 | }
57 |
58 | binding.textviewRestorePassword.setOnClickListener {
59 | navigateToRestorePasswordFragment()
60 | }
61 | }
62 |
63 | override fun editTextUserAuthInit(): UserAuth {
64 | val userAuth = UserAuth()
65 | userAuth.email = binding.edittextEmail.text.toString()
66 | userAuth.password = binding.edittextPassword.text.toString()
67 |
68 | return userAuth
69 | }
70 |
71 | override fun progressBarSignInObserver() {
72 | viewModel.progressBarSignIn.observe(viewLifecycleOwner) { result ->
73 | if (result) showProgressBarSignIn()
74 | else hideProgressBarSignIn()
75 | }
76 | }
77 |
78 | override fun signInSuccessObserver() {
79 | viewModel.signInSuccess.observe(viewLifecycleOwner) { result ->
80 | when (result) {
81 | is Response.Loading -> {}
82 | is Response.Fail -> showToastLengthLong("Sign in fail: ${result.e}")
83 | is Response.Success -> navigateToLatestMessagesFragment()
84 | }
85 | }
86 | }
87 |
88 | override fun loadRussianEnglishPackObserver() {
89 | viewModel.loadRussianEnglishPack.observe(viewLifecycleOwner) { result ->
90 | when (result) {
91 | is Response.Loading -> {}
92 | is Response.Fail -> showToastLengthLong(text = "Load RU-EN pack false: ${result.e}")
93 | is Response.Success -> {}
94 | }
95 | }
96 | }
97 |
98 | override fun validEditTextShowError(): Boolean {
99 | val email = binding.edittextEmail.text.toString()
100 | val password = binding.edittextPassword.text.toString()
101 |
102 | var valid = false
103 |
104 | when {
105 | email.isEmpty() -> {
106 | binding.edittextEmail.setError("Enter email address.", null)
107 | binding.edittextEmail.requestFocus()
108 | }
109 | !Patterns.EMAIL_ADDRESS.matcher(email).matches() -> {
110 | binding.edittextEmail.setError("Enter valid email address.", null)
111 | binding.edittextEmail.requestFocus()
112 | }
113 | password.isEmpty() -> {
114 | binding.edittextPassword.setError("Enter password.", null)
115 | binding.edittextPassword.requestFocus()
116 | }
117 | else -> {
118 | valid = true
119 | }
120 | }
121 |
122 | return valid
123 | }
124 |
125 | override fun showToastLengthLong(text: String) {
126 | Toast.makeText(activity, text, Toast.LENGTH_LONG)
127 | .show()
128 | }
129 |
130 | override fun showProgressBarSignIn() {
131 | binding.progressbarSignIn.visibility = View.VISIBLE
132 | binding.buttonSignIn.visibility = View.INVISIBLE
133 | }
134 |
135 | override fun hideProgressBarSignIn() {
136 | binding.progressbarSignIn.visibility = View.INVISIBLE
137 | binding.buttonSignIn.visibility = View.VISIBLE
138 | }
139 |
140 | override fun navigateToSignUpFragment() {
141 | findNavController().navigate(R.id.action_signInFragment_to_signUpFragment)
142 | }
143 |
144 | override fun navigateToRestorePasswordFragment() {
145 | findNavController().navigate(R.id.action_signInFragment_to_restorePasswordFragment)
146 | }
147 |
148 | override fun navigateToLatestMessagesFragment() {
149 | findNavController().navigate(R.id.action_signInFragment_to_latestMessagesFragment)
150 | }
151 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/dispatch/presentation/signIn/viewmodel/SignInViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.presentation.signIn.viewmodel
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import androidx.lifecycle.ViewModel
6 | import androidx.lifecycle.viewModelScope
7 | import com.example.dispatch.domain.models.Response
8 | import com.example.dispatch.domain.models.UserAuth
9 | import com.example.dispatch.domain.usecase.DownloadLangRussianEnglishPackUseCase
10 | import com.example.dispatch.domain.usecase.SignInUserAuthUseCase
11 | import com.example.dispatch.presentation.signIn.SignInContract
12 | import dagger.hilt.android.lifecycle.HiltViewModel
13 | import kotlinx.coroutines.Dispatchers
14 | import kotlinx.coroutines.ExperimentalCoroutinesApi
15 | import kotlinx.coroutines.launch
16 | import javax.inject.Inject
17 |
18 | @HiltViewModel
19 | @ExperimentalCoroutinesApi
20 | class SignInViewModel @Inject constructor(
21 | private val signInUserAuthUseCase: SignInUserAuthUseCase,
22 | private val downloadLangRussianEnglishPackUseCase: DownloadLangRussianEnglishPackUseCase
23 | ) : ViewModel(), SignInContract.SignInViewModel {
24 |
25 | private val _progressBarSignIn = MutableLiveData()
26 | val progressBarSignIn: LiveData = _progressBarSignIn
27 |
28 | private val _signInSuccess = MutableLiveData>()
29 | val signInSuccess: LiveData> = _signInSuccess
30 |
31 | private val _loadRussianEnglishPack = MutableLiveData>()
32 | val loadRussianEnglishPack: LiveData> = _loadRussianEnglishPack
33 |
34 | override fun signInUserAuth(userAuth: UserAuth) {
35 | viewModelScope.launch(Dispatchers.IO) {
36 | signInUserAuthUseCase.execute(userAuth = userAuth).collect { result ->
37 | when (result) {
38 | is Response.Loading -> _progressBarSignIn.postValue(true)
39 | is Response.Fail -> {
40 | _progressBarSignIn.postValue(false)
41 | _signInSuccess.postValue(Response.Fail(e = result.e))
42 | }
43 | is Response.Success -> {
44 | _progressBarSignIn.postValue(false)
45 | _signInSuccess.postValue(Response.Success(data = true))
46 | }
47 | }
48 | }
49 | }
50 | }
51 |
52 | override fun downloadLangRussianEnglishPack() {
53 | viewModelScope.launch(Dispatchers.IO) {
54 | downloadLangRussianEnglishPackUseCase.execute().collect { result ->
55 | when (result) {
56 | is Response.Loading -> {}
57 | is Response.Fail -> _loadRussianEnglishPack.postValue(Response.Fail(e = result.e))
58 | is Response.Success -> {}
59 | }
60 | }
61 | }
62 | }
63 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/dispatch/presentation/signUp/SignUpContract.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.presentation.signUp
2 |
3 | import android.net.Uri
4 | import com.example.dispatch.domain.models.UserAuth
5 | import com.example.dispatch.domain.models.UserDetails
6 |
7 | interface SignUpContract {
8 | interface SignUpFragment {
9 | /**
10 | * Sets the required setOnClickListener on the views fragment
11 | */
12 | fun setOnClickListeners()
13 |
14 | /**
15 | * Observer cropImageView LiveData from [SignUpViewModel]
16 | */
17 | fun cropImageViewObserver()
18 |
19 | /**
20 | * Observer progressBarSignUp LiveData from [SignUpViewModel]
21 | */
22 | fun progressBarSignUpObserver()
23 |
24 | /**
25 | * Observer signUpSuccess LiveData from [SignUpViewModel]
26 | */
27 | fun signUpSuccessObserver()
28 |
29 | /**
30 | * Start CropImage Activity
31 | */
32 | fun cropImageActivityStart()
33 |
34 | /**
35 | * Init userDetails variable from [SignUpViewModel] via edittext
36 | */
37 | fun userDetailsEditTextInit()
38 |
39 | /**
40 | * Checking edittext fields for correctness
41 | * @return - corresponding [Boolean] result
42 | */
43 | fun validEditTextShowError(): Boolean
44 |
45 | /**
46 | * Takes an imageUri and sets it to the desired view
47 | * @param imageUri - [Uri]
48 | */
49 | fun setUserImage(imageUri: Uri)
50 |
51 | /**
52 | * Clears cropImageView LiveData from [SignUpViewModel] and manages views
53 | */
54 | fun deleteUserImageView()
55 |
56 | /**
57 | * Shows progress bar sign up
58 | */
59 | fun showProgressBarSignUp()
60 |
61 | /**
62 | * Hides progress bar sign up
63 | */
64 | fun hideProgressBarSignUp()
65 |
66 | /**
67 | * Show toast Toast.LENGTH_LONG type
68 | * @param text - text, shown in toast
69 | */
70 | fun showToastLengthLong(text: String)
71 |
72 | /**
73 | * Navigate to pop back stack
74 | */
75 | fun navigateToPopBackStack()
76 | }
77 |
78 | interface SignUpViewModel {
79 | /**
80 | * Sign up a new user in the system
81 | * @param userAuth - [UserAuth] model for sign up
82 | */
83 | fun signUpUserAuth(userAuth: UserAuth)
84 |
85 | /**
86 | * Get the uid of the current user
87 | */
88 | fun getCurrentUserUid()
89 |
90 | /**
91 | * Stores the user profile photo in the database
92 | * @param imageUriStr - image uri (string type from cache)
93 | */
94 | fun saveUserProfileImage(imageUriStr: String)
95 |
96 | /**
97 | * Deletes the user profile photo from the database
98 | */
99 | fun deleteUserImageProfile()
100 |
101 | /**
102 | * Deletes current user from the system
103 | */
104 | fun deleteCurrentUserAuth()
105 |
106 | /**
107 | * Saves the userDetails data to the database
108 | * @param userDetails - user data [UserDetails] model
109 | */
110 | fun saveUserDetails(userDetails: UserDetails)
111 |
112 | /**
113 | * Save user image in LiveData from [SignUpViewModel]
114 | * @param imageUriStr - image uri [String] model from cache
115 | */
116 | fun saveUserImageLiveData(imageUriStr: String)
117 |
118 | /**
119 | * Clears user image from LiveData from [SignUpViewModel]
120 | */
121 | fun deleteUserImageLiveData()
122 | }
123 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/dispatch/presentation/splash/SplashScreenContract.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.presentation.splash
2 |
3 | interface SplashScreenContract {
4 | interface SplashScreenFragment {
5 | /**
6 | * Observer signInSuccess LiveData from [SplashScreenViewModel]
7 | */
8 | fun signInSuccessObserver()
9 |
10 | /**
11 | * Navigate to LatestMessagesFragment
12 | */
13 | fun navigateToLatestMessagesFragment()
14 |
15 | /**
16 | * Navigate to SignInFragment
17 | */
18 | fun navigateToSignInFragment()
19 | }
20 |
21 | interface SplashScreenViewModel {
22 | /**
23 | * Checking if the user is already logged in
24 | */
25 | fun checkUserAuthSignedIn()
26 | }
27 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/dispatch/presentation/splash/view/SplashScreenFragment.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.presentation.splash.view
2 |
3 | import android.annotation.SuppressLint
4 | import android.os.Bundle
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import androidx.fragment.app.Fragment
9 | import androidx.fragment.app.viewModels
10 | import androidx.navigation.fragment.findNavController
11 | import com.example.dispatch.R
12 | import com.example.dispatch.domain.models.Response
13 | import com.example.dispatch.presentation.splash.SplashScreenContract
14 | import com.example.dispatch.presentation.splash.viewmodel.SplashScreenViewModel
15 | import dagger.hilt.android.AndroidEntryPoint
16 | import kotlinx.coroutines.*
17 |
18 | @AndroidEntryPoint
19 | @ExperimentalCoroutinesApi
20 | @SuppressLint("CustomSplashScreen")
21 | class SplashScreenFragment : Fragment(), SplashScreenContract.SplashScreenFragment {
22 |
23 | private val viewModel: SplashScreenViewModel by viewModels()
24 |
25 | override fun onCreateView(
26 | inflater: LayoutInflater, container: ViewGroup?,
27 | savedInstanceState: Bundle?
28 | ): View? {
29 | return inflater.inflate(R.layout.fragment_splash_screen, container, false)
30 | }
31 |
32 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
33 | CoroutineScope(Dispatchers.Main).launch {
34 | viewModel.checkUserAuthSignedIn()
35 | delay(800)
36 | signInSuccessObserver()
37 | }
38 | }
39 |
40 | override fun signInSuccessObserver() {
41 | viewModel.signInSuccess.observe(viewLifecycleOwner) { result ->
42 | when (result) {
43 | is Response.Loading -> navigateToSignInFragment()
44 | is Response.Fail -> navigateToSignInFragment()
45 | is Response.Success -> navigateToLatestMessagesFragment()
46 | }
47 | }
48 | }
49 |
50 | override fun navigateToLatestMessagesFragment() {
51 | findNavController().navigate(R.id.action_splashScreenFragment_to_latestMessagesFragment)
52 | }
53 |
54 | override fun navigateToSignInFragment() {
55 | findNavController().navigate(R.id.action_splashScreenFragment_to_signInFragment)
56 | }
57 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/dispatch/presentation/splash/viewmodel/SplashScreenViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.presentation.splash.viewmodel
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import androidx.lifecycle.ViewModel
6 | import androidx.lifecycle.viewModelScope
7 | import com.example.dispatch.domain.models.Response
8 | import com.example.dispatch.domain.usecase.CheckUserAuthSignedInUseCase
9 | import com.example.dispatch.presentation.splash.SplashScreenContract
10 | import dagger.hilt.android.lifecycle.HiltViewModel
11 | import kotlinx.coroutines.Dispatchers
12 | import kotlinx.coroutines.ExperimentalCoroutinesApi
13 | import kotlinx.coroutines.launch
14 | import javax.inject.Inject
15 |
16 | @HiltViewModel
17 | @ExperimentalCoroutinesApi
18 | class SplashScreenViewModel @Inject constructor(
19 | private val checkUserAuthSignedInUseCase: CheckUserAuthSignedInUseCase
20 | ) : ViewModel(), SplashScreenContract.SplashScreenViewModel {
21 |
22 | private val _signInSuccess = MutableLiveData>()
23 | val signInSuccess: LiveData> = _signInSuccess
24 |
25 | override fun checkUserAuthSignedIn() {
26 | viewModelScope.launch(Dispatchers.Main) {
27 | checkUserAuthSignedInUseCase.execute().collect { _signInSuccess.postValue(it) }
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/splash_screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alphanication/Dispatch/62c10da5f7c74ace4bc2e7de927c312a6611596b/app/src/main/res/drawable-v24/splash_screen.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/background_circle.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/background_content_bottom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/background_content_top.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/background_details_messages_input.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/background_edittext.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/background_recipient_message.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/background_sender_message.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/background_shapeableimageview.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/background_view_circle.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_account_circle.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_arrow_back.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_calendar_month.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_cleaning_services.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_delete.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_info.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_lock.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_logout.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_mail.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_more_vert.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_person.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_remove_circle.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_send.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_translate.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_two_user_circle.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
20 |
21 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_latest_messages.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
25 |
26 |
37 |
38 |
48 |
49 |
60 |
61 |
67 |
68 |
69 |
70 |
77 |
78 |
87 |
88 |
94 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_list_users.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
22 |
23 |
34 |
35 |
42 |
43 |
52 |
53 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_restore_password.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
18 |
19 |
27 |
28 |
41 |
42 |
51 |
52 |
53 |
54 |
58 |
59 |
69 |
70 |
76 |
77 |
87 |
88 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_splash_screen.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_container_latest_message.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
18 |
19 |
30 |
31 |
40 |
41 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_container_recipient_message.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
19 |
20 |
29 |
30 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_container_sender_message.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
20 |
21 |
29 |
30 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_container_user.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
16 |
17 |
24 |
25 |
26 |
39 |
40 |
53 |
54 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/bottom_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/details_messages_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alphanication/Dispatch/62c10da5f7c74ace4bc2e7de927c312a6611596b/app/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alphanication/Dispatch/62c10da5f7c74ace4bc2e7de927c312a6611596b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alphanication/Dispatch/62c10da5f7c74ace4bc2e7de927c312a6611596b/app/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alphanication/Dispatch/62c10da5f7c74ace4bc2e7de927c312a6611596b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alphanication/Dispatch/62c10da5f7c74ace4bc2e7de927c312a6611596b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alphanication/Dispatch/62c10da5f7c74ace4bc2e7de927c312a6611596b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alphanication/Dispatch/62c10da5f7c74ace4bc2e7de927c312a6611596b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alphanication/Dispatch/62c10da5f7c74ace4bc2e7de927c312a6611596b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alphanication/Dispatch/62c10da5f7c74ace4bc2e7de927c312a6611596b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alphanication/Dispatch/62c10da5f7c74ace4bc2e7de927c312a6611596b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/navigation/nav_graph.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
16 |
19 |
22 |
23 |
28 |
33 |
38 |
43 |
44 |
49 |
52 |
55 |
56 |
61 |
66 |
67 |
72 |
77 |
80 |
81 |
86 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FF000000
4 | #FFFFFFFF
5 | #E14412
6 |
7 | #098E3A
8 | #044008
9 | #212121
10 | #757575
11 |
12 | #ECECEC
13 | #ECECEC
14 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Dispatch
3 | Hello blank fragment
4 |
5 | Messages
6 | Profile
7 |
8 | - learn English in practice!
9 | Enter email address
10 | Enter password
11 | SIGN UP
12 | SIGN IN
13 | Forgot your account password? Restore!
14 |
15 | CREATE NEW ACCOUNT
16 | ADD IMAGE
17 | Enter fullname
18 | Enter date birth
19 | Enter email
20 | Enter password
21 | Confirm password
22 | BACK
23 | SIGN UP
24 |
25 | RESTORE PASSWORD
26 | Enter email address
27 | BACK
28 | RESTORE
29 |
30 | Change fullname
31 | Change date birth
32 | Change email
33 | Change password
34 | UPDATE PROFILE
35 | CHANGE PASSWORD
36 | SELECT USER
37 | Type a message
38 | Delete messages
39 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/app/src/test/java/com/example/dispatch/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch
2 |
3 | import org.junit.Assert.assertEquals
4 | import org.junit.Test
5 |
6 | /**
7 | * Example local unit test, which will execute on the development machine (host).
8 | *
9 | * See [testing documentation](http://d.android.com/tools/testing).
10 | */
11 | class ExampleUnitTest {
12 | @Test
13 | fun addition_isCorrect() {
14 | assertEquals(4, 2 + 2)
15 | }
16 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | maven { url "https://maven.google.com" }
4 | google()
5 | maven { url "https://jitpack.io"}
6 | jcenter()
7 | }
8 | dependencies {
9 | classpath 'com.google.gms:google-services:4.3.10'
10 | classpath 'com.google.dagger:hilt-android-gradle-plugin:2.41'
11 | }
12 | }
13 |
14 | plugins {
15 | id 'com.android.application' version '7.1.2' apply false
16 | id 'com.android.library' version '7.1.2' apply false
17 | id 'org.jetbrains.kotlin.android' version '1.6.20' apply false
18 | id 'org.jetbrains.kotlin.jvm' version '1.6.20' apply false
19 | id 'com.google.gms.google-services' version '4.3.10' apply false
20 | }
21 |
22 | allprojects {
23 | repositories {
24 | maven { url "https://maven.google.com" }
25 | google()
26 | maven { url "https://jitpack.io"}
27 | jcenter()
28 | }
29 | }
30 |
31 | task clean(type: Delete) {
32 | delete rootProject.buildDir
33 | }
--------------------------------------------------------------------------------
/data/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/data/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'org.jetbrains.kotlin.android'
4 | }
5 |
6 | android {
7 | compileSdk 32
8 |
9 | defaultConfig {
10 | minSdk 21
11 | targetSdk 32
12 |
13 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
14 | consumerProguardFiles "consumer-rules.pro"
15 | }
16 |
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 | compileOptions {
24 | sourceCompatibility JavaVersion.VERSION_1_8
25 | targetCompatibility JavaVersion.VERSION_1_8
26 | }
27 | kotlinOptions {
28 | jvmTarget = '1.8'
29 | }
30 | }
31 |
32 | dependencies {
33 |
34 | implementation 'androidx.core:core-ktx:1.7.0'
35 | implementation 'androidx.appcompat:appcompat:1.4.1'
36 |
37 | testImplementation 'junit:junit:4.13.2'
38 | androidTestImplementation 'androidx.test.ext:junit:1.1.3'
39 |
40 | // firebase
41 | implementation 'com.google.firebase:firebase-auth-ktx:21.0.1'
42 | implementation 'com.google.firebase:firebase-database-ktx:20.0.4'
43 | implementation 'com.google.firebase:firebase-storage-ktx:20.0.1'
44 |
45 | // coroutines
46 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0'
47 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0"
48 |
49 | // mlkit translate
50 | implementation 'com.google.mlkit:translate:17.0.0'
51 | implementation 'com.google.mlkit:language-id:17.0.3'
52 |
53 | implementation project(path: ':domain')
54 | }
--------------------------------------------------------------------------------
/data/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alphanication/Dispatch/62c10da5f7c74ace4bc2e7de927c312a6611596b/data/consumer-rules.pro
--------------------------------------------------------------------------------
/data/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/data/src/androidTest/java/com/example/dispatch/data/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.data
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4
4 | import androidx.test.platform.app.InstrumentationRegistry
5 | import org.junit.Assert.assertEquals
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | /**
10 | * Instrumented test, which will execute on an Android device.
11 | *
12 | * See [testing documentation](http://d.android.com/tools/testing).
13 | */
14 | @RunWith(AndroidJUnit4::class)
15 | class ExampleInstrumentedTest {
16 | @Test
17 | fun useAppContext() {
18 | // Context of the app under test.
19 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
20 | assertEquals("com.example.dispatch.data.test", appContext.packageName)
21 | }
22 | }
--------------------------------------------------------------------------------
/data/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/src/main/java/com/example/dispatch/data/repository/MessageRepositoryImpl.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.data.repository
2 |
3 | import com.example.dispatch.data.storage.MessageStorage
4 | import com.example.dispatch.domain.models.FromToUser
5 | import com.example.dispatch.domain.models.Message
6 | import com.example.dispatch.domain.models.Response
7 | import com.example.dispatch.domain.repository.MessageRepository
8 | import kotlinx.coroutines.ExperimentalCoroutinesApi
9 | import kotlinx.coroutines.flow.Flow
10 |
11 | @ExperimentalCoroutinesApi
12 | class MessageRepositoryImpl(private val messageStorage: MessageStorage) : MessageRepository {
13 | override suspend fun save(message: Message): Flow> {
14 | return messageStorage.save(message = message)
15 | }
16 |
17 | override suspend fun saveLatestMessage(message: Message): Flow> {
18 | return messageStorage.saveLatestMessage(message = message)
19 | }
20 |
21 | override suspend fun listenFromToUserMessages(fromToUser: FromToUser): Flow> {
22 | return messageStorage.listenFromToUserMessages(fromToUser = fromToUser)
23 | }
24 |
25 | override suspend fun deleteDialogBothUsers(fromToUser: FromToUser): Flow> {
26 | return messageStorage.deleteDialogBothUsers(fromToUser = fromToUser)
27 | }
28 |
29 | override suspend fun deleteLatestMessageBothUsers(fromToUser: FromToUser): Flow> {
30 | return messageStorage.deleteLatestMessageBothUsers(fromToUser = fromToUser)
31 | }
32 |
33 | override suspend fun getLatestMessages(fromUserUid: String): Flow>> {
34 | return messageStorage.getLatestMessages(fromUserUid = fromUserUid)
35 | }
36 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/example/dispatch/data/repository/TranslateRepositoryImpl.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.data.repository
2 |
3 | import com.example.dispatch.data.storage.TranslateStorage
4 | import com.example.dispatch.domain.models.Response
5 | import com.example.dispatch.domain.repository.TranslateRepository
6 | import kotlinx.coroutines.ExperimentalCoroutinesApi
7 | import kotlinx.coroutines.flow.Flow
8 |
9 | @ExperimentalCoroutinesApi
10 | class TranslateRepositoryImpl(private val translateStorage: TranslateStorage) :
11 | TranslateRepository {
12 | override suspend fun downloadLangRussianEnglishPack(): Flow> {
13 | return translateStorage.downloadLangRussianEnglishPack()
14 | }
15 |
16 | override suspend fun translateRussianEnglishText(text: String): Flow> {
17 | return translateStorage.translateRussianEnglishText(text = text)
18 | }
19 |
20 | override suspend fun translateEnglishRussianText(text: String): Flow> {
21 | return translateStorage.translateEnglishRussianText(text = text)
22 | }
23 |
24 | override suspend fun languageIdentifier(text: String): Flow> {
25 | return translateStorage.languageIndentifier(text = text)
26 | }
27 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/example/dispatch/data/repository/UserAuthRepositoryImpl.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.data.repository
2 |
3 | import com.example.dispatch.data.storage.UserAuthStorage
4 | import com.example.dispatch.domain.models.Response
5 | import com.example.dispatch.domain.models.UserAuth
6 | import com.example.dispatch.domain.repository.UserAuthRepository
7 | import kotlinx.coroutines.ExperimentalCoroutinesApi
8 | import kotlinx.coroutines.flow.Flow
9 |
10 | @ExperimentalCoroutinesApi
11 | class UserAuthRepositoryImpl(private val userAuthStorage: UserAuthStorage) : UserAuthRepository {
12 | override suspend fun login(userAuth: UserAuth): Flow> {
13 | return userAuthStorage.login(userAuth = userAuth)
14 | }
15 |
16 | override suspend fun register(userAuth: UserAuth): Flow> {
17 | return userAuthStorage.register(userAuth = userAuth)
18 | }
19 |
20 | override suspend fun checkSignedIn(): Flow> {
21 | return userAuthStorage.checkSignedIn()
22 | }
23 |
24 | override suspend fun getCurrentUserUid(): Flow> {
25 | return userAuthStorage.getCurrentUserUid()
26 | }
27 |
28 | override suspend fun deleteCurrentUser(): Flow> {
29 | return userAuthStorage.deleteCurrentUser()
30 | }
31 |
32 | override suspend fun restorePasswordByEmail(email: String): Flow> {
33 | return userAuthStorage.restorePasswordByEmail(email = email)
34 | }
35 |
36 | override suspend fun changeEmail(
37 | userAuth: UserAuth,
38 | newEmail: String
39 | ): Flow> {
40 | return userAuthStorage.changeEmail(userAuth = userAuth, newEmail = newEmail)
41 | }
42 |
43 | override suspend fun changePassword(
44 | userAuth: UserAuth,
45 | newPassword: String
46 | ): Flow> {
47 | return userAuthStorage.changePassword(userAuth = userAuth, newPassword = newPassword)
48 | }
49 |
50 | override suspend fun signOut(): Flow> {
51 | return userAuthStorage.signOut()
52 | }
53 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/example/dispatch/data/repository/UserDetailsRepositoryImpl.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.data.repository
2 |
3 | import com.example.dispatch.data.storage.UserDetailsStorage
4 | import com.example.dispatch.domain.models.Response
5 | import com.example.dispatch.domain.models.UserDetails
6 | import com.example.dispatch.domain.models.UserDetailsPublic
7 | import com.example.dispatch.domain.repository.UserDetailsRepository
8 | import kotlinx.coroutines.ExperimentalCoroutinesApi
9 | import kotlinx.coroutines.flow.Flow
10 |
11 | @ExperimentalCoroutinesApi
12 | class UserDetailsRepositoryImpl(private val userDetailsStorage: UserDetailsStorage) :
13 | UserDetailsRepository {
14 | override suspend fun save(userDetails: UserDetails): Flow> {
15 | return userDetailsStorage.save(userDetails = userDetails)
16 | }
17 |
18 | override suspend fun getCurrentUser(): Flow> {
19 | return userDetailsStorage.getCurrentUser()
20 | }
21 |
22 | override suspend fun deleteCurrentUser(): Flow> {
23 | return userDetailsStorage.deleteCurrentUser()
24 | }
25 |
26 | override suspend fun changeFullname(newFullname: String): Flow> {
27 | return userDetailsStorage.changeFullname(newFullname = newFullname)
28 | }
29 |
30 | override suspend fun changeImageProfileUri(newImageUriStr: String): Flow> {
31 | return userDetailsStorage.changeImageProfileUri(newImageUriStr = newImageUriStr)
32 | }
33 |
34 | override suspend fun changeEmailAddress(newEmail: String): Flow> {
35 | return userDetailsStorage.changeEmailAddress(newEmail = newEmail)
36 | }
37 |
38 | override suspend fun changePassword(newPassword: String): Flow> {
39 | return userDetailsStorage.changePassword(newPassword = newPassword)
40 | }
41 |
42 | override suspend fun getUsersList(): Flow>> {
43 | return userDetailsStorage.getUsersList()
44 | }
45 |
46 | override suspend fun getUserDetailsPublicOnUid(uid: String): Flow> {
47 | return userDetailsStorage.getUserDetailsPublicOnUid(uid = uid)
48 | }
49 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/example/dispatch/data/repository/UserImagesRepositoryImpl.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.data.repository
2 |
3 | import com.example.dispatch.data.storage.UserImagesStorage
4 | import com.example.dispatch.domain.models.Response
5 | import com.example.dispatch.domain.repository.UserImagesRepository
6 | import kotlinx.coroutines.ExperimentalCoroutinesApi
7 | import kotlinx.coroutines.flow.Flow
8 |
9 | @ExperimentalCoroutinesApi
10 | class UserImagesRepositoryImpl(private val userImagesStorage: UserImagesStorage) :
11 | UserImagesRepository {
12 | override suspend fun saveImageProfile(newImageUriStr: String): Flow> {
13 | return userImagesStorage.saveImageProfile(newImageUriStr = newImageUriStr)
14 | }
15 |
16 | override suspend fun deleteImageProfile(): Flow> {
17 | return userImagesStorage.deleteImageProfile()
18 | }
19 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/example/dispatch/data/storage/MessageStorage.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.data.storage
2 |
3 | import com.example.dispatch.domain.models.FromToUser
4 | import com.example.dispatch.domain.models.Message
5 | import com.example.dispatch.domain.models.Response
6 | import kotlinx.coroutines.flow.Flow
7 |
8 | interface MessageStorage {
9 | suspend fun save(message: Message): Flow>
10 |
11 | suspend fun saveLatestMessage(message: Message): Flow>
12 |
13 | suspend fun listenFromToUserMessages(fromToUser: FromToUser): Flow>
14 |
15 | suspend fun deleteDialogBothUsers(fromToUser: FromToUser): Flow>
16 |
17 | suspend fun deleteLatestMessageBothUsers(fromToUser: FromToUser): Flow>
18 |
19 | suspend fun getLatestMessages(fromUserUid: String): Flow>>
20 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/example/dispatch/data/storage/TranslateStorage.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.data.storage
2 |
3 | import com.example.dispatch.domain.models.Response
4 | import kotlinx.coroutines.ExperimentalCoroutinesApi
5 | import kotlinx.coroutines.flow.Flow
6 |
7 | @ExperimentalCoroutinesApi
8 | interface TranslateStorage {
9 | suspend fun downloadLangRussianEnglishPack(): Flow>
10 |
11 | suspend fun translateRussianEnglishText(text: String): Flow>
12 |
13 | suspend fun translateEnglishRussianText(text: String): Flow>
14 |
15 | suspend fun languageIndentifier(text: String): Flow>
16 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/example/dispatch/data/storage/UserAuthStorage.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.data.storage
2 |
3 | import com.example.dispatch.domain.models.Response
4 | import com.example.dispatch.domain.models.UserAuth
5 | import kotlinx.coroutines.ExperimentalCoroutinesApi
6 | import kotlinx.coroutines.flow.Flow
7 |
8 | @ExperimentalCoroutinesApi
9 | interface UserAuthStorage {
10 | suspend fun login(userAuth: UserAuth): Flow>
11 |
12 | suspend fun register(userAuth: UserAuth): Flow>
13 |
14 | suspend fun checkSignedIn(): Flow>
15 |
16 | suspend fun getCurrentUserUid(): Flow>
17 |
18 | suspend fun deleteCurrentUser(): Flow>
19 |
20 | suspend fun restorePasswordByEmail(email: String): Flow>
21 |
22 | suspend fun changeEmail(userAuth: UserAuth, newEmail: String): Flow>
23 |
24 | suspend fun changePassword(userAuth: UserAuth, newPassword: String): Flow>
25 |
26 | suspend fun signOut(): Flow>
27 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/example/dispatch/data/storage/UserDetailsStorage.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.data.storage
2 |
3 | import com.example.dispatch.domain.models.Response
4 | import com.example.dispatch.domain.models.UserDetails
5 | import com.example.dispatch.domain.models.UserDetailsPublic
6 | import kotlinx.coroutines.ExperimentalCoroutinesApi
7 | import kotlinx.coroutines.flow.Flow
8 |
9 | @ExperimentalCoroutinesApi
10 | interface UserDetailsStorage {
11 | suspend fun save(userDetails: UserDetails): Flow>
12 |
13 | suspend fun getCurrentUser(): Flow>
14 |
15 | suspend fun deleteCurrentUser(): Flow>
16 |
17 | suspend fun changeImageProfileUri(newImageUriStr: String): Flow>
18 |
19 | suspend fun changeFullname(newFullname: String): Flow>
20 |
21 | suspend fun changeEmailAddress(newEmail: String): Flow>
22 |
23 | suspend fun changePassword(newPassword: String): Flow>
24 |
25 | suspend fun getUsersList(): Flow>>
26 |
27 | suspend fun getUserDetailsPublicOnUid(uid: String): Flow>
28 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/example/dispatch/data/storage/UserImagesStorage.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.data.storage
2 |
3 | import com.example.dispatch.domain.models.Response
4 | import kotlinx.coroutines.ExperimentalCoroutinesApi
5 | import kotlinx.coroutines.flow.Flow
6 |
7 | @ExperimentalCoroutinesApi
8 | interface UserImagesStorage {
9 | suspend fun saveImageProfile(newImageUriStr: String): Flow>
10 |
11 | suspend fun deleteImageProfile(): Flow>
12 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/example/dispatch/data/storage/firebase/FirebaseUserAuthStorage.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.data.storage.firebase
2 |
3 | import com.example.dispatch.data.storage.UserAuthStorage
4 | import com.example.dispatch.domain.models.Response
5 | import com.example.dispatch.domain.models.UserAuth
6 | import com.google.firebase.auth.FirebaseAuth
7 | import kotlinx.coroutines.ExperimentalCoroutinesApi
8 | import kotlinx.coroutines.cancel
9 | import kotlinx.coroutines.channels.awaitClose
10 | import kotlinx.coroutines.flow.Flow
11 | import kotlinx.coroutines.flow.callbackFlow
12 |
13 | @ExperimentalCoroutinesApi
14 | class FirebaseUserAuthStorage : UserAuthStorage {
15 | companion object {
16 | private val fAuth = FirebaseAuth.getInstance()
17 | }
18 |
19 | override suspend fun login(userAuth: UserAuth): Flow> = callbackFlow {
20 | trySend(Response.Loading())
21 |
22 | fAuth.signInWithEmailAndPassword(userAuth.email, userAuth.password)
23 | .addOnSuccessListener {
24 | trySend(Response.Success(data = true))
25 | }.addOnFailureListener { e ->
26 | trySend(Response.Fail(e = e))
27 | }
28 |
29 | awaitClose { this.cancel() }
30 | }
31 |
32 | override suspend fun register(userAuth: UserAuth): Flow> = callbackFlow {
33 | trySend(Response.Loading())
34 |
35 | fAuth.createUserWithEmailAndPassword(userAuth.email, userAuth.password)
36 | .addOnSuccessListener {
37 | trySend(Response.Success(data = true))
38 | }.addOnFailureListener { e ->
39 | trySend(Response.Fail(e = e))
40 | }
41 |
42 | awaitClose { this.cancel() }
43 | }
44 |
45 | override suspend fun checkSignedIn(): Flow> = callbackFlow {
46 | trySend(Response.Loading())
47 |
48 | val currentUser = fAuth.currentUser
49 |
50 | if (currentUser != null) {
51 | trySend(Response.Success(data = true))
52 | } else {
53 | trySend(Response.Fail(Exception("current user = null")))
54 | }
55 |
56 | awaitClose { this.cancel() }
57 | }
58 |
59 | override suspend fun getCurrentUserUid(): Flow> = callbackFlow {
60 | trySend(Response.Loading())
61 |
62 | try {
63 | val uidCurrentUser = fAuth.currentUser?.uid.toString()
64 | trySend(Response.Success(data = uidCurrentUser))
65 | } catch (e: Exception) {
66 | trySend(Response.Fail(e = e))
67 | }
68 |
69 | awaitClose { this.cancel() }
70 | }
71 |
72 | override suspend fun deleteCurrentUser(): Flow> = callbackFlow {
73 | trySend(Response.Loading())
74 |
75 | fAuth.currentUser?.delete()
76 | ?.addOnSuccessListener {
77 | trySend(Response.Success(data = true))
78 | }?.addOnFailureListener { e ->
79 | trySend(Response.Fail(e = e))
80 | }
81 |
82 | awaitClose { this.cancel() }
83 | }
84 |
85 | override suspend fun restorePasswordByEmail(email: String): Flow> =
86 | callbackFlow {
87 | trySend(Response.Loading())
88 |
89 | fAuth.sendPasswordResetEmail(email)
90 | .addOnSuccessListener {
91 | trySend(Response.Success(data = true))
92 | }.addOnFailureListener { e ->
93 | trySend(Response.Fail(e = e))
94 | }
95 |
96 | awaitClose { this.cancel() }
97 | }
98 |
99 | override suspend fun changeEmail(
100 | userAuth: UserAuth,
101 | newEmail: String
102 | ): Flow> = callbackFlow {
103 | trySend(Response.Loading())
104 |
105 | fAuth.signInWithEmailAndPassword(userAuth.email, userAuth.password)
106 | fAuth.currentUser?.updateEmail(newEmail)
107 | ?.addOnSuccessListener {
108 | trySend(Response.Success(data = true))
109 | }?.addOnFailureListener { e ->
110 | trySend(Response.Fail(e = e))
111 | }
112 |
113 | awaitClose { this.cancel() }
114 | }
115 |
116 | override suspend fun changePassword(
117 | userAuth: UserAuth,
118 | newPassword: String
119 | ): Flow> = callbackFlow {
120 | trySend(Response.Loading())
121 |
122 | fAuth.signInWithEmailAndPassword(userAuth.email, userAuth.password)
123 | fAuth.currentUser?.updatePassword(newPassword)
124 | ?.addOnSuccessListener {
125 | trySend(Response.Success(data = true))
126 | }?.addOnFailureListener { e ->
127 | trySend(Response.Fail(e = e))
128 | }
129 |
130 | awaitClose { this.cancel() }
131 | }
132 |
133 | override suspend fun signOut(): Flow> = callbackFlow {
134 | trySend(Response.Loading())
135 |
136 | fAuth.signOut()
137 | trySend(Response.Success(data = true))
138 |
139 | awaitClose { this.cancel() }
140 | }
141 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/example/dispatch/data/storage/firebase/FirebaseUserImagesStorage.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.data.storage.firebase
2 |
3 | import android.net.Uri
4 | import com.example.dispatch.data.storage.UserImagesStorage
5 | import com.example.dispatch.domain.models.Response
6 | import com.google.firebase.auth.FirebaseAuth
7 | import com.google.firebase.storage.FirebaseStorage
8 | import kotlinx.coroutines.ExperimentalCoroutinesApi
9 | import kotlinx.coroutines.cancel
10 | import kotlinx.coroutines.channels.awaitClose
11 | import kotlinx.coroutines.flow.Flow
12 | import kotlinx.coroutines.flow.callbackFlow
13 |
14 | @ExperimentalCoroutinesApi
15 | class FirebaseUserImagesStorage : UserImagesStorage {
16 | companion object {
17 | private val fAuth = FirebaseAuth.getInstance()
18 | private val fStorage = FirebaseStorage.getInstance()
19 | }
20 |
21 | override suspend fun saveImageProfile(newImageUriStr: String): Flow> =
22 | callbackFlow {
23 | trySend(Response.Loading())
24 |
25 | val uidCurrentUser = fAuth.currentUser?.uid.toString()
26 | val refImage = fStorage.getReference("/$uidCurrentUser/profile.jpg")
27 | val imageProfileUri: Uri = Uri.parse(newImageUriStr)
28 |
29 | refImage.putFile(imageProfileUri).addOnCompleteListener {
30 | refImage.downloadUrl.addOnSuccessListener { uri ->
31 | val uriStr = uri.toString()
32 | trySend(Response.Success(data = uriStr))
33 | }.addOnFailureListener { e ->
34 | trySend(Response.Fail(e = e))
35 | }
36 | }.addOnFailureListener { e ->
37 | trySend(Response.Fail(e = e))
38 | }
39 |
40 | awaitClose { this.cancel() }
41 | }
42 |
43 | override suspend fun deleteImageProfile(): Flow> = callbackFlow {
44 | trySend(Response.Loading())
45 |
46 | val uidCurrentUser = fAuth.currentUser?.uid.toString()
47 | val refImage = fStorage.getReference("/$uidCurrentUser/profile.jpg")
48 |
49 | refImage.delete()
50 | .addOnSuccessListener {
51 | trySend(Response.Success(data = true))
52 | }.addOnFailureListener { e ->
53 | trySend(Response.Fail(e = e))
54 | }
55 |
56 | awaitClose { this.cancel() }
57 | }
58 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/example/dispatch/data/storage/mlkit/MlKitTranslateStorage.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.data.storage.mlkit
2 |
3 | import com.example.dispatch.data.storage.TranslateStorage
4 | import com.example.dispatch.domain.constants.LanguageCodeConstants
5 | import com.example.dispatch.domain.models.Response
6 | import com.google.mlkit.nl.languageid.LanguageIdentification
7 | import com.google.mlkit.nl.translate.TranslateLanguage
8 | import com.google.mlkit.nl.translate.Translation
9 | import com.google.mlkit.nl.translate.TranslatorOptions
10 | import kotlinx.coroutines.ExperimentalCoroutinesApi
11 | import kotlinx.coroutines.cancel
12 | import kotlinx.coroutines.channels.awaitClose
13 | import kotlinx.coroutines.flow.Flow
14 | import kotlinx.coroutines.flow.callbackFlow
15 |
16 | @ExperimentalCoroutinesApi
17 | class MlKitTranslateStorage : TranslateStorage {
18 | override suspend fun downloadLangRussianEnglishPack(): Flow> = callbackFlow {
19 | trySend(Response.Loading())
20 |
21 | val options = TranslatorOptions.Builder()
22 | .setSourceLanguage(TranslateLanguage.RUSSIAN)
23 | .setTargetLanguage(TranslateLanguage.ENGLISH)
24 | .build()
25 | val russianEnglishTranslator = Translation.getClient(options)
26 |
27 | russianEnglishTranslator.downloadModelIfNeeded()
28 | .addOnSuccessListener {
29 | trySend(Response.Success(data = true))
30 | }.addOnFailureListener { e ->
31 | trySend(Response.Fail(e = e))
32 | }
33 |
34 | awaitClose { this.cancel() }
35 | }
36 |
37 | override suspend fun translateRussianEnglishText(text: String): Flow> =
38 | callbackFlow {
39 | trySend(Response.Loading())
40 |
41 | val options = TranslatorOptions.Builder()
42 | .setSourceLanguage(TranslateLanguage.RUSSIAN)
43 | .setTargetLanguage(TranslateLanguage.ENGLISH)
44 | .build()
45 | val russianEnglishTranslator = Translation.getClient(options)
46 |
47 | russianEnglishTranslator.downloadModelIfNeeded()
48 | .addOnSuccessListener {
49 | russianEnglishTranslator.translate(text)
50 | .addOnSuccessListener { textTranslated ->
51 | trySend(Response.Success(data = textTranslated))
52 | }.addOnFailureListener { e ->
53 | trySend(Response.Fail(e = e))
54 | }
55 | }.addOnFailureListener { e ->
56 | trySend(Response.Fail(e = e))
57 | }
58 |
59 | awaitClose { this.cancel() }
60 | }
61 |
62 | override suspend fun translateEnglishRussianText(text: String): Flow> =
63 | callbackFlow {
64 | trySend(Response.Loading())
65 |
66 | val options = TranslatorOptions.Builder()
67 | .setSourceLanguage(TranslateLanguage.ENGLISH)
68 | .setTargetLanguage(TranslateLanguage.RUSSIAN)
69 | .build()
70 | val englishRussianTranslator = Translation.getClient(options)
71 |
72 | englishRussianTranslator.downloadModelIfNeeded()
73 | .addOnSuccessListener {
74 | englishRussianTranslator.translate(text)
75 | .addOnSuccessListener { textTranslated ->
76 | trySend(Response.Success(data = textTranslated))
77 | }.addOnFailureListener { e ->
78 | trySend(Response.Fail(e = e))
79 | }
80 | }.addOnFailureListener { e ->
81 | trySend(Response.Fail(e = e))
82 | }
83 |
84 | awaitClose { this.cancel() }
85 | }
86 |
87 | override suspend fun languageIndentifier(text: String): Flow> = callbackFlow {
88 | trySend(Response.Loading())
89 |
90 | val languageIdentifier = LanguageIdentification.getClient()
91 |
92 | languageIdentifier.identifyLanguage(text)
93 | .addOnSuccessListener { languageCode ->
94 | when (languageCode) {
95 | LanguageCodeConstants.EN -> trySend(Response.Success(data = LanguageCodeConstants.EN))
96 | LanguageCodeConstants.RU -> trySend(Response.Success(data = LanguageCodeConstants.RU))
97 | else -> trySend(Response.Success(data = languageCode))
98 | }
99 | }
100 | .addOnFailureListener { e ->
101 | trySend(Response.Fail(e = e))
102 | }
103 |
104 | awaitClose { this.cancel() }
105 | }
106 | }
--------------------------------------------------------------------------------
/data/src/test/java/com/example/dispatch/data/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.data
2 |
3 | import org.junit.Assert.assertEquals
4 | import org.junit.Test
5 |
6 | /**
7 | * Example local unit test, which will execute on the development machine (host).
8 | *
9 | * See [testing documentation](http://d.android.com/tools/testing).
10 | */
11 | class ExampleUnitTest {
12 | @Test
13 | fun addition_isCorrect() {
14 | assertEquals(4, 2 + 2)
15 | }
16 | }
--------------------------------------------------------------------------------
/domain/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/domain/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java-library'
3 | id 'org.jetbrains.kotlin.jvm'
4 | }
5 |
6 | java {
7 | sourceCompatibility = JavaVersion.VERSION_1_7
8 | targetCompatibility = JavaVersion.VERSION_1_7
9 | }
10 |
11 | dependencies {
12 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0"
13 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/constants/LanguageCodeConstants.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.constants
2 |
3 | sealed class LanguageCodeConstants {
4 | companion object {
5 | const val EN = "en"
6 | const val RU = "ru"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/models/FromToUser.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.models
2 |
3 | data class FromToUser(
4 | val fromUserUid: String = "",
5 | val toUserUid: String = ""
6 | )
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/models/Message.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.models
2 |
3 | data class Message(
4 | val russianMessage: String = "",
5 | val englishMessage: String = "",
6 | val timestamp: Long = 0,
7 | val fromUserUid: String = "",
8 | val toUserUid: String = ""
9 | )
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/models/Response.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.models
2 |
3 | sealed class Response {
4 | class Loading : Response()
5 | data class Success(val data: T) : Response()
6 | data class Fail(val e: Exception) : Response()
7 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/models/UserAuth.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.models
2 |
3 | data class UserAuth(
4 | var email: String = "",
5 | var password: String = ""
6 | )
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/models/UserDetails.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.models
2 |
3 | data class UserDetails(
4 | var uid: String = "",
5 | var fullname: String = "",
6 | var email: String = "",
7 | var password: String = "",
8 | var photoProfileUrl: String = ""
9 | )
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/models/UserDetailsPublic.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.models
2 |
3 | data class UserDetailsPublic(
4 | var uid: String = "",
5 | var fullname: String = "",
6 | var email: String = "",
7 | var photoProfileUrl: String = ""
8 | )
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/repository/MessageRepository.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.repository
2 |
3 | import com.example.dispatch.domain.models.FromToUser
4 | import com.example.dispatch.domain.models.Message
5 | import com.example.dispatch.domain.models.Response
6 | import kotlinx.coroutines.ExperimentalCoroutinesApi
7 | import kotlinx.coroutines.flow.Flow
8 |
9 | @ExperimentalCoroutinesApi
10 | interface MessageRepository {
11 | /**
12 | * Save message in the database
13 | * @param message - [Message]
14 | * @return [Boolean] value result operation
15 | */
16 | suspend fun save(message: Message): Flow>
17 |
18 | /**
19 | * Save latest message in the database
20 | * @param message - [Message]
21 | * @return [Boolean] value result operation
22 | */
23 | suspend fun saveLatestMessage(message: Message): Flow>
24 |
25 | /**
26 | * Gets messages between users (if any)
27 | * @param - [FromToUser]
28 | * @return [Message]
29 | */
30 | suspend fun listenFromToUserMessages(fromToUser: FromToUser): Flow>
31 |
32 | /**
33 | * Delete all messages between two users
34 | * @param fromToUser - [FromToUser]
35 | * @return [Boolean] value result operation
36 | */
37 | suspend fun deleteDialogBothUsers(fromToUser: FromToUser): Flow>
38 |
39 | /**
40 | * Removes data from recent messages
41 | * @param fromToUser - [FromToUser]
42 | * @return [Boolean] value result operation
43 | */
44 | suspend fun deleteLatestMessageBothUsers(fromToUser: FromToUser): Flow>
45 |
46 | /**
47 | * Gets latest messages between users
48 | * @param fromUserUid - [String] user uid
49 | * @return [ArrayList]-[Message] all the latest messages of the user
50 | */
51 | suspend fun getLatestMessages(fromUserUid: String): Flow>>
52 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/repository/TranslateRepository.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.repository
2 |
3 | import com.example.dispatch.domain.models.Response
4 | import kotlinx.coroutines.ExperimentalCoroutinesApi
5 | import kotlinx.coroutines.flow.Flow
6 |
7 | @ExperimentalCoroutinesApi
8 | interface TranslateRepository {
9 | /**
10 | * Downloads en-ru language pack
11 | * @return [Boolean] value success operation
12 | */
13 | suspend fun downloadLangRussianEnglishPack(): Flow>
14 |
15 | /**
16 | * Translates text from Russian into English
17 | * @param text - [String] russian text
18 | * @return [String] english text
19 | */
20 | suspend fun translateRussianEnglishText(text: String): Flow>
21 |
22 | /**
23 | * Translates text from English into Russian
24 | * @param text - [String] english text
25 | * @return [String] russian text
26 | */
27 | suspend fun translateEnglishRussianText(text: String): Flow>
28 |
29 | /**
30 | * Specifies the source language of the text
31 | * @param text - [String]
32 | * @return [String], language code according to BCP-47 language code
33 | */
34 | suspend fun languageIdentifier(text: String): Flow>
35 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/repository/UserAuthRepository.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.repository
2 |
3 | import com.example.dispatch.domain.models.Response
4 | import com.example.dispatch.domain.models.UserAuth
5 | import kotlinx.coroutines.ExperimentalCoroutinesApi
6 | import kotlinx.coroutines.flow.Flow
7 |
8 | /**
9 | * The repository provides work with the user of the [UserAuth] class
10 | */
11 | @ExperimentalCoroutinesApi
12 | interface UserAuthRepository {
13 | /**
14 | * The function returns a [Boolean] value of the user's authorization attempt
15 | * @param userAuth - accepts email and password as by [UserAuth] class for authorization
16 | */
17 | suspend fun login(userAuth: UserAuth): Flow>
18 |
19 | /**
20 | * Function returns [Boolean] value of new user registration attempt
21 | * @param userAuth - accepts login and password by [UserAuth] class for registration
22 | */
23 | suspend fun register(userAuth: UserAuth): Flow>
24 |
25 | /**
26 | * The function returns a [Boolean] value whether the user is logged in
27 | */
28 | suspend fun checkSignedIn(): Flow>
29 |
30 | /**
31 | * The function returns the [String] uid of the current user
32 | */
33 | suspend fun getCurrentUserUid(): Flow>
34 |
35 | /**
36 | * The function returns the [Boolean] value of deleting the current user
37 | */
38 | suspend fun deleteCurrentUser(): Flow>
39 |
40 | /**
41 | * The function returns the [Boolean] value of an attempt to recover the password from the email address
42 | * note: the user's email will receive instructions for resetting the password
43 | * @param email - user's email as a [String]
44 | */
45 | suspend fun restorePasswordByEmail(email: String): Flow>
46 |
47 | /**
48 | * The function returns a [Boolean] value of an attempt to change the user's email
49 | * To change your email address, you need to authenticate the user
50 | * @param userAuth - login / password user value as [UserAuth]
51 | * @param newEmail - new email address
52 | */
53 | suspend fun changeEmail(userAuth: UserAuth, newEmail: String): Flow>
54 |
55 | /**
56 | * The function returns a [Boolean] value of an attempt to change the user's password
57 | * To change your password, you need to authenticate the user
58 | * @param userAuth - login / password user value as [UserAuth]
59 | * @param newPassword - new password
60 | */
61 | suspend fun changePassword(userAuth: UserAuth, newPassword: String): Flow>
62 |
63 | /**
64 | * The function returns a [Boolean] value of the user's logout attempt
65 | */
66 | suspend fun signOut(): Flow>
67 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/repository/UserDetailsRepository.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.repository
2 |
3 | import com.example.dispatch.domain.models.Response
4 | import com.example.dispatch.domain.models.UserDetails
5 | import com.example.dispatch.domain.models.UserDetailsPublic
6 | import kotlinx.coroutines.ExperimentalCoroutinesApi
7 | import kotlinx.coroutines.flow.Flow
8 |
9 | /**
10 | * The repository provides work with the [UserDetails] class
11 | */
12 | @ExperimentalCoroutinesApi
13 | interface UserDetailsRepository {
14 | /**
15 | * The function returns a [Boolean] value of attempt to save user data
16 | * @param userDetails - user's personal data to be saved as [UserDetails] class
17 | */
18 | suspend fun save(userDetails: UserDetails): Flow>
19 |
20 | /**
21 | * The function returns the data of the current authorized user in the form of the [UserDetails] class
22 | */
23 | suspend fun getCurrentUser(): Flow>
24 |
25 | /**
26 | * The function returns a [Boolean] value of an attempt to delete the user's personal data
27 | */
28 | suspend fun deleteCurrentUser(): Flow>
29 |
30 | /**
31 | * Function returns [Boolean] value of attempt to change photoProfileUrl in saved [UserDetails]
32 | * @param newImageUriStr - link to new user photo
33 | */
34 | suspend fun changeImageProfileUri(newImageUriStr: String): Flow>
35 |
36 | /**
37 | * Function returns [Boolean] value of attempt to change fullname in saved [UserDetails]
38 | * @param newFullname - new user fullname
39 | */
40 | suspend fun changeFullname(newFullname: String): Flow>
41 |
42 | /**
43 | * Function returns [Boolean] value of attempt to change email address in saved [UserDetails]
44 | * @param newEmail - new user email
45 | */
46 | suspend fun changeEmailAddress(newEmail: String): Flow>
47 |
48 | /**
49 | * Function returns [Boolean] value of attempt to change password in saved [UserDetails]
50 | * @param newPassword - new user password
51 | */
52 | suspend fun changePassword(newPassword: String): Flow>
53 |
54 | /**
55 | * Get all users list
56 | * @return [ArrayList]-[UserDetailsPublic]
57 | */
58 | suspend fun getUsersList(): Flow>>
59 |
60 | /**
61 | * Getting details of a specific user by uid
62 | * @return [UserDetailsPublic] model
63 | */
64 | suspend fun getUserDetailsPublicOnUid(uid: String): Flow>
65 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/repository/UserImagesRepository.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.repository
2 |
3 | import com.example.dispatch.domain.models.Response
4 | import kotlinx.coroutines.ExperimentalCoroutinesApi
5 | import kotlinx.coroutines.flow.Flow
6 |
7 | /**
8 | * The repository provides work with user images
9 | */
10 | @ExperimentalCoroutinesApi
11 | interface UserImagesRepository {
12 | /**
13 | * The function returns a link to the user's saved main image as a [String]
14 | * @param newImageUriStr - cached image link (uri to string)
15 | */
16 | suspend fun saveImageProfile(newImageUriStr: String): Flow>
17 |
18 | /**
19 | * The function returns a [Boolean] value of an attempt to delete the profile photo of the user
20 | */
21 | suspend fun deleteImageProfile(): Flow>
22 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/usecase/ChangeUserAuthEmailUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.usecase
2 |
3 | import com.example.dispatch.domain.models.Response
4 | import com.example.dispatch.domain.models.UserAuth
5 | import com.example.dispatch.domain.repository.UserAuthRepository
6 | import kotlinx.coroutines.ExperimentalCoroutinesApi
7 | import kotlinx.coroutines.flow.Flow
8 |
9 | @ExperimentalCoroutinesApi
10 | class ChangeUserAuthEmailUseCase(private val userAuthRepository: UserAuthRepository) {
11 | suspend fun execute(userAuth: UserAuth, newEmail: String): Flow> {
12 | return userAuthRepository.changeEmail(userAuth = userAuth, newEmail = newEmail)
13 | }
14 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/usecase/ChangeUserAuthPasswordUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.usecase
2 |
3 | import com.example.dispatch.domain.models.Response
4 | import com.example.dispatch.domain.models.UserAuth
5 | import com.example.dispatch.domain.repository.UserAuthRepository
6 | import kotlinx.coroutines.ExperimentalCoroutinesApi
7 | import kotlinx.coroutines.flow.Flow
8 |
9 | @ExperimentalCoroutinesApi
10 | class ChangeUserAuthPasswordUseCase(private val userAuthRepository: UserAuthRepository) {
11 | suspend fun execute(userAuth: UserAuth, newPassword: String): Flow> {
12 | return userAuthRepository.changePassword(userAuth = userAuth, newPassword = newPassword)
13 | }
14 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/usecase/ChangeUserDetailsEmailUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.usecase
2 |
3 | import com.example.dispatch.domain.models.Response
4 | import com.example.dispatch.domain.repository.UserDetailsRepository
5 | import kotlinx.coroutines.ExperimentalCoroutinesApi
6 | import kotlinx.coroutines.flow.Flow
7 |
8 | @ExperimentalCoroutinesApi
9 | class ChangeUserDetailsEmailUseCase(private val userDetailsRepository: UserDetailsRepository) {
10 | suspend fun execute(newEmail: String): Flow> {
11 | return userDetailsRepository.changeEmailAddress(newEmail = newEmail)
12 | }
13 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/usecase/ChangeUserDetailsFullnameUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.usecase
2 |
3 | import com.example.dispatch.domain.models.Response
4 | import com.example.dispatch.domain.repository.UserDetailsRepository
5 | import kotlinx.coroutines.ExperimentalCoroutinesApi
6 | import kotlinx.coroutines.flow.Flow
7 |
8 | @ExperimentalCoroutinesApi
9 | class ChangeUserDetailsFullnameUseCase(private val userDetailsRepository: UserDetailsRepository) {
10 | suspend fun execute(newFullname: String): Flow> {
11 | return userDetailsRepository.changeFullname(newFullname = newFullname)
12 | }
13 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/usecase/ChangeUserDetailsPasswordUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.usecase
2 |
3 | import com.example.dispatch.domain.models.Response
4 | import com.example.dispatch.domain.repository.UserDetailsRepository
5 | import kotlinx.coroutines.ExperimentalCoroutinesApi
6 | import kotlinx.coroutines.flow.Flow
7 |
8 | @ExperimentalCoroutinesApi
9 | class ChangeUserDetailsPasswordUseCase(private val userDetailsRepository: UserDetailsRepository) {
10 | suspend fun execute(newPassword: String): Flow> {
11 | return userDetailsRepository.changePassword(newPassword = newPassword)
12 | }
13 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/usecase/ChangeUserDetailsPhotoProfileUrlUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.usecase
2 |
3 | import com.example.dispatch.domain.models.Response
4 | import com.example.dispatch.domain.repository.UserDetailsRepository
5 | import kotlinx.coroutines.ExperimentalCoroutinesApi
6 | import kotlinx.coroutines.flow.Flow
7 |
8 | @ExperimentalCoroutinesApi
9 | class ChangeUserDetailsPhotoProfileUrlUseCase(private val userDetailsRepository: UserDetailsRepository) {
10 | suspend fun execute(newImageUriStr: String): Flow> {
11 | return userDetailsRepository.changeImageProfileUri(newImageUriStr = newImageUriStr)
12 | }
13 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/usecase/CheckUserAuthSignedInUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.usecase
2 |
3 | import com.example.dispatch.domain.models.Response
4 | import com.example.dispatch.domain.repository.UserAuthRepository
5 | import kotlinx.coroutines.ExperimentalCoroutinesApi
6 | import kotlinx.coroutines.flow.Flow
7 |
8 | @ExperimentalCoroutinesApi
9 | class CheckUserAuthSignedInUseCase(private val userAuthRepository: UserAuthRepository) {
10 | suspend fun execute(): Flow> {
11 | return userAuthRepository.checkSignedIn()
12 | }
13 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/usecase/DeleteCurrentUserAuthUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.usecase
2 |
3 | import com.example.dispatch.domain.models.Response
4 | import com.example.dispatch.domain.repository.UserAuthRepository
5 | import kotlinx.coroutines.ExperimentalCoroutinesApi
6 | import kotlinx.coroutines.flow.Flow
7 |
8 | @ExperimentalCoroutinesApi
9 | class DeleteCurrentUserAuthUseCase(private val userAuthRepository: UserAuthRepository) {
10 | suspend fun execute(): Flow> {
11 | return userAuthRepository.deleteCurrentUser()
12 | }
13 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/usecase/DeleteCurrentUserDetailsUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.usecase
2 |
3 | import com.example.dispatch.domain.models.Response
4 | import com.example.dispatch.domain.repository.UserDetailsRepository
5 | import kotlinx.coroutines.ExperimentalCoroutinesApi
6 | import kotlinx.coroutines.flow.Flow
7 |
8 | @ExperimentalCoroutinesApi
9 | class DeleteCurrentUserDetailsUseCase(private val userDetailsRepository: UserDetailsRepository) {
10 | suspend fun execute(): Flow> {
11 | return userDetailsRepository.deleteCurrentUser()
12 | }
13 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/usecase/DeleteDialogBothUsersUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.usecase
2 |
3 | import com.example.dispatch.domain.models.FromToUser
4 | import com.example.dispatch.domain.models.Response
5 | import com.example.dispatch.domain.repository.MessageRepository
6 | import kotlinx.coroutines.ExperimentalCoroutinesApi
7 | import kotlinx.coroutines.flow.Flow
8 |
9 | @ExperimentalCoroutinesApi
10 | class DeleteDialogBothUsersUseCase(private val messageRepository: MessageRepository) {
11 | suspend fun execute(fromToUser: FromToUser): Flow> {
12 | return messageRepository.deleteDialogBothUsers(fromToUser = fromToUser)
13 | }
14 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/usecase/DeleteLatestMessagesBothUsersUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.usecase
2 |
3 | import com.example.dispatch.domain.models.FromToUser
4 | import com.example.dispatch.domain.models.Response
5 | import com.example.dispatch.domain.repository.MessageRepository
6 | import kotlinx.coroutines.ExperimentalCoroutinesApi
7 | import kotlinx.coroutines.flow.Flow
8 |
9 | @ExperimentalCoroutinesApi
10 | class DeleteLatestMessagesBothUsersUseCase(private val messageRepository: MessageRepository) {
11 | suspend fun execute(fromToUser: FromToUser): Flow> {
12 | return messageRepository.deleteLatestMessageBothUsers(fromToUser = fromToUser)
13 | }
14 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/usecase/DeleteUserImageProfileUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.usecase
2 |
3 | import com.example.dispatch.domain.models.Response
4 | import com.example.dispatch.domain.repository.UserImagesRepository
5 | import kotlinx.coroutines.ExperimentalCoroutinesApi
6 | import kotlinx.coroutines.flow.Flow
7 |
8 | @ExperimentalCoroutinesApi
9 | class DeleteUserImageProfileUseCase(private val userImagesRepository: UserImagesRepository) {
10 | suspend fun execute(): Flow> {
11 | return userImagesRepository.deleteImageProfile()
12 | }
13 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/usecase/DownloadLangRussianEnglishPackUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.usecase
2 |
3 | import com.example.dispatch.domain.models.Response
4 | import com.example.dispatch.domain.repository.TranslateRepository
5 | import kotlinx.coroutines.ExperimentalCoroutinesApi
6 | import kotlinx.coroutines.flow.Flow
7 |
8 | @ExperimentalCoroutinesApi
9 | class DownloadLangRussianEnglishPackUseCase(private val translateRepository: TranslateRepository) {
10 | suspend fun execute(): Flow> {
11 | return translateRepository.downloadLangRussianEnglishPack()
12 | }
13 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/usecase/GetCurrentUserDetailsUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.usecase
2 |
3 | import com.example.dispatch.domain.models.Response
4 | import com.example.dispatch.domain.models.UserDetails
5 | import com.example.dispatch.domain.repository.UserDetailsRepository
6 | import kotlinx.coroutines.ExperimentalCoroutinesApi
7 | import kotlinx.coroutines.flow.Flow
8 |
9 | @ExperimentalCoroutinesApi
10 | class GetCurrentUserDetailsUseCase(private val userDetailsRepository: UserDetailsRepository) {
11 | suspend fun execute(): Flow> {
12 | return userDetailsRepository.getCurrentUser()
13 | }
14 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/usecase/GetCurrentUserUidUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.usecase
2 |
3 | import com.example.dispatch.domain.models.Response
4 | import com.example.dispatch.domain.repository.UserAuthRepository
5 | import kotlinx.coroutines.ExperimentalCoroutinesApi
6 | import kotlinx.coroutines.flow.Flow
7 |
8 | @ExperimentalCoroutinesApi
9 | class GetCurrentUserUidUseCase(private val userAuthRepository: UserAuthRepository) {
10 | suspend fun execute(): Flow> {
11 | return userAuthRepository.getCurrentUserUid()
12 | }
13 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/usecase/GetLatestMessagesUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.usecase
2 |
3 | import com.example.dispatch.domain.models.Message
4 | import com.example.dispatch.domain.models.Response
5 | import com.example.dispatch.domain.repository.MessageRepository
6 | import kotlinx.coroutines.ExperimentalCoroutinesApi
7 | import kotlinx.coroutines.flow.Flow
8 |
9 | @ExperimentalCoroutinesApi
10 | class GetLatestMessagesUseCase(private val messageRepository: MessageRepository) {
11 | suspend fun execute(fromUserUid: String): Flow>> {
12 | return messageRepository.getLatestMessages(fromUserUid = fromUserUid)
13 | }
14 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/usecase/GetUserDetailsPublicOnUidUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.usecase
2 |
3 | import com.example.dispatch.domain.models.Response
4 | import com.example.dispatch.domain.models.UserDetailsPublic
5 | import com.example.dispatch.domain.repository.UserDetailsRepository
6 | import kotlinx.coroutines.ExperimentalCoroutinesApi
7 | import kotlinx.coroutines.flow.Flow
8 |
9 | @ExperimentalCoroutinesApi
10 | class GetUserDetailsPublicOnUidUseCase(private val userDetailsRepository: UserDetailsRepository) {
11 | suspend fun execute(uid: String): Flow> {
12 | return userDetailsRepository.getUserDetailsPublicOnUid(uid = uid)
13 | }
14 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/usecase/GetUsersListUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.usecase
2 |
3 | import com.example.dispatch.domain.models.Response
4 | import com.example.dispatch.domain.models.UserDetailsPublic
5 | import com.example.dispatch.domain.repository.UserDetailsRepository
6 | import kotlinx.coroutines.ExperimentalCoroutinesApi
7 | import kotlinx.coroutines.flow.Flow
8 |
9 | @ExperimentalCoroutinesApi
10 | class GetUsersListUseCase(private val userDetailsRepository: UserDetailsRepository) {
11 | suspend fun execute(): Flow>> {
12 | return userDetailsRepository.getUsersList()
13 | }
14 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/usecase/LanguageIdentifierUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.usecase
2 |
3 | import com.example.dispatch.domain.models.Response
4 | import com.example.dispatch.domain.repository.TranslateRepository
5 | import kotlinx.coroutines.ExperimentalCoroutinesApi
6 | import kotlinx.coroutines.flow.Flow
7 |
8 | @ExperimentalCoroutinesApi
9 | class LanguageIdentifierUseCase(private val translateRepository: TranslateRepository) {
10 | suspend fun execute(text: String): Flow> {
11 | return translateRepository.languageIdentifier(text = text)
12 | }
13 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/usecase/ListenFromToUserMessagesUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.usecase
2 |
3 | import com.example.dispatch.domain.models.FromToUser
4 | import com.example.dispatch.domain.models.Message
5 | import com.example.dispatch.domain.models.Response
6 | import com.example.dispatch.domain.repository.MessageRepository
7 | import kotlinx.coroutines.ExperimentalCoroutinesApi
8 | import kotlinx.coroutines.flow.Flow
9 |
10 | @ExperimentalCoroutinesApi
11 | class ListenFromToUserMessagesUseCase(private val messageRepository: MessageRepository) {
12 | suspend fun execute(fromToUser: FromToUser): Flow> {
13 | return messageRepository.listenFromToUserMessages(fromToUser = fromToUser)
14 | }
15 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/usecase/RestoreUserByEmailUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.usecase
2 |
3 | import com.example.dispatch.domain.models.Response
4 | import com.example.dispatch.domain.repository.UserAuthRepository
5 | import kotlinx.coroutines.ExperimentalCoroutinesApi
6 | import kotlinx.coroutines.flow.Flow
7 |
8 | @ExperimentalCoroutinesApi
9 | class RestoreUserByEmailUseCase(private val userAuthRepository: UserAuthRepository) {
10 | suspend fun execute(email: String): Flow> {
11 | return userAuthRepository.restorePasswordByEmail(email = email)
12 | }
13 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/usecase/SaveLatestMessageUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.usecase
2 |
3 | import com.example.dispatch.domain.models.Message
4 | import com.example.dispatch.domain.models.Response
5 | import com.example.dispatch.domain.repository.MessageRepository
6 | import kotlinx.coroutines.ExperimentalCoroutinesApi
7 | import kotlinx.coroutines.flow.Flow
8 |
9 | @ExperimentalCoroutinesApi
10 | class SaveLatestMessageUseCase(private val messageRepository: MessageRepository) {
11 | suspend fun execute(message: Message): Flow> {
12 | return messageRepository.saveLatestMessage(message = message)
13 | }
14 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/usecase/SaveMessageUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.usecase
2 |
3 | import com.example.dispatch.domain.models.Message
4 | import com.example.dispatch.domain.models.Response
5 | import com.example.dispatch.domain.repository.MessageRepository
6 | import kotlinx.coroutines.ExperimentalCoroutinesApi
7 | import kotlinx.coroutines.flow.Flow
8 |
9 | @ExperimentalCoroutinesApi
10 | class SaveMessageUseCase(private val messageRepository: MessageRepository) {
11 | suspend fun execute(message: Message): Flow> {
12 | return messageRepository.save(message = message)
13 | }
14 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/usecase/SaveUserDetailsUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.usecase
2 |
3 | import com.example.dispatch.domain.models.Response
4 | import com.example.dispatch.domain.models.UserDetails
5 | import com.example.dispatch.domain.repository.UserDetailsRepository
6 | import kotlinx.coroutines.ExperimentalCoroutinesApi
7 | import kotlinx.coroutines.flow.Flow
8 |
9 | @ExperimentalCoroutinesApi
10 | class SaveUserDetailsUseCase(private val userDetailsRepository: UserDetailsRepository) {
11 | suspend fun execute(userDetails: UserDetails): Flow> {
12 | return userDetailsRepository.save(userDetails = userDetails)
13 | }
14 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/usecase/SaveUserImageProfileUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.usecase
2 |
3 | import com.example.dispatch.domain.models.Response
4 | import com.example.dispatch.domain.repository.UserImagesRepository
5 | import kotlinx.coroutines.ExperimentalCoroutinesApi
6 | import kotlinx.coroutines.flow.Flow
7 |
8 | @ExperimentalCoroutinesApi
9 | class SaveUserImageProfileUseCase(private val userImagesRepository: UserImagesRepository) {
10 | suspend fun execute(newImageUriStr: String): Flow> {
11 | return userImagesRepository.saveImageProfile(newImageUriStr = newImageUriStr)
12 | }
13 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/usecase/SignInUserAuthUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.usecase
2 |
3 | import com.example.dispatch.domain.models.Response
4 | import com.example.dispatch.domain.models.UserAuth
5 | import com.example.dispatch.domain.repository.UserAuthRepository
6 | import kotlinx.coroutines.ExperimentalCoroutinesApi
7 | import kotlinx.coroutines.flow.Flow
8 |
9 | @ExperimentalCoroutinesApi
10 | class SignInUserAuthUseCase(private val userAuthRepository: UserAuthRepository) {
11 | suspend fun execute(userAuth: UserAuth): Flow> {
12 | return userAuthRepository.login(userAuth = userAuth)
13 | }
14 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/usecase/SignOutUserAuthUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.usecase
2 |
3 | import com.example.dispatch.domain.models.Response
4 | import com.example.dispatch.domain.repository.UserAuthRepository
5 | import kotlinx.coroutines.ExperimentalCoroutinesApi
6 | import kotlinx.coroutines.flow.Flow
7 |
8 | @ExperimentalCoroutinesApi
9 | class SignOutUserAuthUseCase(private val userAuthRepository: UserAuthRepository) {
10 | suspend fun execute(): Flow> {
11 | return userAuthRepository.signOut()
12 | }
13 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/usecase/SignUpUserAuthUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.usecase
2 |
3 | import com.example.dispatch.domain.models.Response
4 | import com.example.dispatch.domain.models.UserAuth
5 | import com.example.dispatch.domain.repository.UserAuthRepository
6 | import kotlinx.coroutines.ExperimentalCoroutinesApi
7 | import kotlinx.coroutines.flow.Flow
8 |
9 | @ExperimentalCoroutinesApi
10 | class SignUpUserAuthUseCase(private val userAuthRepository: UserAuthRepository) {
11 | suspend fun execute(userAuth: UserAuth): Flow> {
12 | return userAuthRepository.register(userAuth = userAuth)
13 | }
14 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/usecase/TranslateEnglishRussianTextUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.usecase
2 |
3 | import com.example.dispatch.domain.models.Response
4 | import com.example.dispatch.domain.repository.TranslateRepository
5 | import kotlinx.coroutines.ExperimentalCoroutinesApi
6 | import kotlinx.coroutines.flow.Flow
7 |
8 | @ExperimentalCoroutinesApi
9 | class TranslateEnglishRussianTextUseCase(private val translateRepository: TranslateRepository) {
10 | suspend fun execute(text: String): Flow> {
11 | return translateRepository.translateEnglishRussianText(text = text)
12 | }
13 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/example/dispatch/domain/usecase/TranslateRussianEnglishTextUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.dispatch.domain.usecase
2 |
3 | import com.example.dispatch.domain.models.Response
4 | import com.example.dispatch.domain.repository.TranslateRepository
5 | import kotlinx.coroutines.ExperimentalCoroutinesApi
6 | import kotlinx.coroutines.flow.Flow
7 |
8 | @ExperimentalCoroutinesApi
9 | class TranslateRussianEnglishTextUseCase(private val translateRepository: TranslateRepository) {
10 | suspend fun execute(text: String): Flow> {
11 | return translateRepository.translateRussianEnglishText(text = text)
12 | }
13 | }
--------------------------------------------------------------------------------
/github_images/example1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alphanication/Dispatch/62c10da5f7c74ace4bc2e7de927c312a6611596b/github_images/example1.png
--------------------------------------------------------------------------------
/github_images/example2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alphanication/Dispatch/62c10da5f7c74ace4bc2e7de927c312a6611596b/github_images/example2.png
--------------------------------------------------------------------------------
/github_images/example3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alphanication/Dispatch/62c10da5f7c74ace4bc2e7de927c312a6611596b/github_images/example3.png
--------------------------------------------------------------------------------
/github_images/example4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alphanication/Dispatch/62c10da5f7c74ace4bc2e7de927c312a6611596b/github_images/example4.png
--------------------------------------------------------------------------------
/github_images/example5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alphanication/Dispatch/62c10da5f7c74ace4bc2e7de927c312a6611596b/github_images/example5.png
--------------------------------------------------------------------------------
/github_images/example6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alphanication/Dispatch/62c10da5f7c74ace4bc2e7de927c312a6611596b/github_images/example6.png
--------------------------------------------------------------------------------
/github_images/example7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alphanication/Dispatch/62c10da5f7c74ace4bc2e7de927c312a6611596b/github_images/example7.png
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Kotlin code style for this project: "official" or "obsolete":
19 | kotlin.code.style=official
20 | # Enables namespacing of each library's R class so that its R class includes only the
21 | # resources declared in the library itself and none from the library's dependencies,
22 | # thereby reducing the size of the R class for that library
23 | android.nonTransitiveRClass=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alphanication/Dispatch/62c10da5f7c74ace4bc2e7de927c312a6611596b/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Apr 14 14:26:07 MSK 2022
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | gradlePluginPortal()
4 | maven { url "https://maven.google.com" }
5 | google()
6 | mavenCentral()
7 | maven { url "https://jitpack.io"}
8 | jcenter()
9 | }
10 | }
11 | dependencyResolutionManagement {
12 | repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
13 | repositories {
14 | maven { url "https://maven.google.com" }
15 | google()
16 | mavenCentral()
17 | maven { url "https://jitpack.io"}
18 | jcenter()
19 | }
20 | }
21 | rootProject.name = "Dispatch"
22 | include ':app'
23 | include ':domain'
24 | include ':data'
25 |
--------------------------------------------------------------------------------