├── .gitignore
├── .idea
├── .gitignore
├── .name
├── compiler.xml
├── gradle.xml
├── jarRepositories.xml
├── misc.xml
└── vcs.xml
├── Config
├── README.md
├── app
├── .gitignore
├── build.gradle
├── google-services.json
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── devm7mdibrahim
│ │ └── base_android
│ │ ├── BaseApp.kt
│ │ └── fcm
│ │ ├── FirebaseMessagingReceiver.kt
│ │ ├── NotificationItem.kt
│ │ └── NotificationKey.kt
│ └── res
│ ├── drawable-v24
│ └── ic_launcher_foreground.xml
│ ├── drawable
│ └── ic_launcher_background.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
├── build.gradle
├── buildSrc
├── build.gradle.kts
├── build
│ ├── classes
│ │ └── kotlin
│ │ │ └── main
│ │ │ ├── AndroidTestDependencies.class
│ │ │ ├── ApplicationId.class
│ │ │ ├── Build.class
│ │ │ ├── Compilers.class
│ │ │ ├── Dependencies.class
│ │ │ ├── META-INF
│ │ │ └── buildSrc.kotlin_module
│ │ │ ├── SupportDependencies.class
│ │ │ ├── TestDependencies.class
│ │ │ └── Versions.class
│ ├── kotlin
│ │ ├── buildSrcjar-classes.txt
│ │ └── compileKotlin
│ │ │ ├── build-history.bin
│ │ │ ├── caches-jvm
│ │ │ ├── inputs
│ │ │ │ ├── source-to-output.tab
│ │ │ │ ├── source-to-output.tab.keystream
│ │ │ │ ├── source-to-output.tab.keystream.len
│ │ │ │ ├── source-to-output.tab.len
│ │ │ │ ├── source-to-output.tab.values.at
│ │ │ │ ├── source-to-output.tab_i
│ │ │ │ └── source-to-output.tab_i.len
│ │ │ ├── jvm
│ │ │ │ └── kotlin
│ │ │ │ │ ├── class-attributes.tab
│ │ │ │ │ ├── class-attributes.tab.keystream
│ │ │ │ │ ├── class-attributes.tab.keystream.len
│ │ │ │ │ ├── class-attributes.tab.len
│ │ │ │ │ ├── class-attributes.tab.values.at
│ │ │ │ │ ├── class-attributes.tab_i
│ │ │ │ │ ├── class-attributes.tab_i.len
│ │ │ │ │ ├── class-fq-name-to-source.tab
│ │ │ │ │ ├── class-fq-name-to-source.tab.keystream
│ │ │ │ │ ├── class-fq-name-to-source.tab.keystream.len
│ │ │ │ │ ├── class-fq-name-to-source.tab.len
│ │ │ │ │ ├── class-fq-name-to-source.tab.values.at
│ │ │ │ │ ├── class-fq-name-to-source.tab_i
│ │ │ │ │ ├── class-fq-name-to-source.tab_i.len
│ │ │ │ │ ├── constants.tab
│ │ │ │ │ ├── constants.tab.keystream
│ │ │ │ │ ├── constants.tab.keystream.len
│ │ │ │ │ ├── constants.tab.len
│ │ │ │ │ ├── constants.tab.values.at
│ │ │ │ │ ├── constants.tab_i
│ │ │ │ │ ├── constants.tab_i.len
│ │ │ │ │ ├── internal-name-to-source.tab
│ │ │ │ │ ├── internal-name-to-source.tab.keystream
│ │ │ │ │ ├── internal-name-to-source.tab.keystream.len
│ │ │ │ │ ├── internal-name-to-source.tab.len
│ │ │ │ │ ├── internal-name-to-source.tab.values.at
│ │ │ │ │ ├── internal-name-to-source.tab_i
│ │ │ │ │ ├── internal-name-to-source.tab_i.len
│ │ │ │ │ ├── proto.tab
│ │ │ │ │ ├── proto.tab.keystream
│ │ │ │ │ ├── proto.tab.keystream.len
│ │ │ │ │ ├── proto.tab.len
│ │ │ │ │ ├── proto.tab.values.at
│ │ │ │ │ ├── proto.tab_i
│ │ │ │ │ ├── proto.tab_i.len
│ │ │ │ │ ├── source-to-classes.tab
│ │ │ │ │ ├── source-to-classes.tab.keystream
│ │ │ │ │ ├── source-to-classes.tab.keystream.len
│ │ │ │ │ ├── source-to-classes.tab.len
│ │ │ │ │ ├── source-to-classes.tab.values.at
│ │ │ │ │ ├── source-to-classes.tab_i
│ │ │ │ │ └── source-to-classes.tab_i.len
│ │ │ └── lookups
│ │ │ │ ├── counters.tab
│ │ │ │ ├── file-to-id.tab
│ │ │ │ ├── file-to-id.tab.keystream
│ │ │ │ ├── file-to-id.tab.keystream.len
│ │ │ │ ├── file-to-id.tab.len
│ │ │ │ ├── file-to-id.tab.values.at
│ │ │ │ ├── file-to-id.tab_i
│ │ │ │ ├── file-to-id.tab_i.len
│ │ │ │ ├── id-to-file.tab
│ │ │ │ ├── id-to-file.tab.keystream
│ │ │ │ ├── id-to-file.tab.keystream.len
│ │ │ │ ├── id-to-file.tab.len
│ │ │ │ ├── id-to-file.tab.values.at
│ │ │ │ ├── id-to-file.tab_i
│ │ │ │ ├── id-to-file.tab_i.len
│ │ │ │ ├── lookups.tab
│ │ │ │ ├── lookups.tab.keystream
│ │ │ │ ├── lookups.tab.keystream.len
│ │ │ │ ├── lookups.tab.len
│ │ │ │ ├── lookups.tab.values.at
│ │ │ │ ├── lookups.tab_i
│ │ │ │ └── lookups.tab_i.len
│ │ │ └── last-build.bin
│ ├── libs
│ │ └── buildSrc.jar
│ ├── pluginUnderTestMetadata
│ │ └── plugin-under-test-metadata.properties
│ ├── reports
│ │ └── plugin-development
│ │ │ └── validation-report.txt
│ └── tmp
│ │ └── jar
│ │ └── MANIFEST.MF
└── src
│ └── main
│ └── java
│ ├── AndroidTestDependencies.kt
│ ├── ApplicationId.kt
│ ├── Build.kt
│ ├── Compilers.kt
│ ├── Dependencies.kt
│ ├── SupportDependencies.kt
│ ├── TestDependencies.kt
│ └── Versions.kt
├── data
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── devm7mdibrahim
│ └── data
│ ├── datasource
│ ├── AuthDataSource.kt
│ ├── ChatDataSource.kt
│ ├── HomeDataSource.kt
│ ├── PreferenceDataSource.kt
│ └── SocketDataSource.kt
│ ├── di
│ ├── EndPointsModule.kt
│ ├── NetworkModule.kt
│ ├── PreferencesModule.kt
│ ├── RemoteDataSourcesModule.kt
│ ├── RepositoryModule.kt
│ ├── SocketModule.kt
│ └── StringsModule.kt
│ ├── local
│ ├── datasource
│ │ └── PreferenceDataSourceImpl.kt
│ └── utils
│ │ ├── PreferenceConstants.kt
│ │ └── SafeCacheCall.kt
│ ├── remote
│ ├── datasource
│ │ ├── AuthDataSourceImpl.kt
│ │ ├── ChatDataSourceImpl.kt
│ │ └── HomeDataSourceImpl.kt
│ ├── endpoints
│ │ ├── AuthEndPoints.kt
│ │ ├── ChatEndPoints.kt
│ │ └── HomeEndPoints.kt
│ └── utils
│ │ ├── NetworkConstants.kt
│ │ └── SafeApiCall.kt
│ ├── repository
│ ├── AuthRepositoryImpl.kt
│ ├── ChatRepositoryImpl.kt
│ ├── HomeRepositoryImpl.kt
│ └── PreferenceRepositoryImpl.kt
│ ├── socket
│ └── datasource
│ │ └── SocketDataSourceImpl.kt
│ └── utils
│ └── MultiPartUtil.kt
├── domain
├── .gitignore
├── build.gradle
└── src
│ └── main
│ └── java
│ └── com
│ └── devm7mdibrahim
│ └── domain
│ ├── entities
│ ├── AuthData.kt
│ ├── BaseResponse.kt
│ ├── ChatResponse.kt
│ ├── MessagesItem.kt
│ ├── Pagination.kt
│ ├── RoomsItem.kt
│ └── RoomsResponse.kt
│ ├── exceptions
│ ├── LocalExceptions.kt
│ ├── NetworkExceptions.kt
│ └── ValidationException.kt
│ ├── repository
│ ├── AuthRepository.kt
│ ├── ChatRepository.kt
│ ├── HomeRepository.kt
│ └── PreferenceRepository.kt
│ ├── usecases
│ ├── LoginUseCase.kt
│ └── RegisterUseCase.kt
│ └── util
│ ├── CommonValidation.kt
│ ├── Constants.kt
│ └── DataState.kt
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── presentation
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── devm7mdibrahim
│ │ └── presentation
│ │ ├── base
│ │ ├── BaseActivity.kt
│ │ ├── BaseBottomSheetFragment.kt
│ │ ├── BaseDialogFragment.kt
│ │ ├── BaseFragment.kt
│ │ ├── BaseRecyclerAdapter.kt
│ │ ├── BaseViewHolder.kt
│ │ └── BaseViewModel.kt
│ │ ├── cycles
│ │ ├── auth_cycle
│ │ │ ├── activity
│ │ │ │ └── AuthActivity.kt
│ │ │ └── fragment
│ │ │ │ ├── login
│ │ │ │ ├── LoginFragment.kt
│ │ │ │ └── LoginViewModel.kt
│ │ │ │ └── register
│ │ │ │ ├── RegisterFragment.kt
│ │ │ │ └── RegisterViewModel.kt
│ │ ├── home_cycle
│ │ │ ├── activity
│ │ │ │ └── HomeActivity.kt
│ │ │ └── fragment
│ │ │ │ └── home_container
│ │ │ │ ├── HomeContainerFragment.kt
│ │ │ │ ├── HomeContainerViewModel.kt
│ │ │ │ ├── home
│ │ │ │ ├── HomeFragment.kt
│ │ │ │ └── HomeViewModel.kt
│ │ │ │ ├── notifications
│ │ │ │ ├── NotificationsFragment.kt
│ │ │ │ └── NotificationsViewModel.kt
│ │ │ │ └── profile
│ │ │ │ ├── ProfileFragment.kt
│ │ │ │ └── ProfileViewModel.kt
│ │ └── splash_cycle
│ │ │ ├── activity
│ │ │ └── SplashActivity.kt
│ │ │ └── fragment
│ │ │ └── SplashFragment.kt
│ │ └── utils
│ │ ├── CommonErrorHandling.kt
│ │ └── Constants.kt
│ └── res
│ ├── anim
│ ├── fade_in.xml
│ ├── fade_out.xml
│ ├── slide_in_left.xml
│ ├── slide_in_right.xml
│ ├── slide_out_left.xml
│ └── slide_out_right.xml
│ ├── color
│ └── bottom_nav_color.xml
│ ├── layout
│ ├── activity_auth.xml
│ ├── activity_home.xml
│ ├── activity_splash.xml
│ ├── base_toolbar.xml
│ ├── fragment_home.xml
│ ├── fragment_home_container.xml
│ ├── fragment_login.xml
│ ├── fragment_notifications.xml
│ ├── fragment_profile.xml
│ ├── fragment_register.xml
│ └── fragment_splash.xml
│ ├── menu
│ └── home_menu.xml
│ ├── navigation
│ ├── auth_graph.xml
│ ├── home_container_graph.xml
│ ├── home_graph.xml
│ └── splash_graph.xml
│ ├── values-ar
│ └── strings.xml
│ └── values
│ ├── colors.xml
│ ├── google_maps_api.xml
│ ├── strings.xml
│ ├── styles.xml
│ └── themes.xml
├── settings.gradle
└── utils
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
└── main
├── AndroidManifest.xml
├── java
└── com
│ └── devm7mdibrahim
│ └── utils
│ ├── common
│ ├── NetworkHelper.kt
│ ├── PaginationHelper.kt
│ └── ProgressUtil.kt
│ ├── di
│ ├── ActivityModule.kt
│ └── GlideModule.kt
│ ├── extensions
│ ├── AlertExtensions.kt
│ ├── CommonExtensions.kt
│ ├── ExceptionsExtensions.kt
│ ├── FirebaseExtensions.kt
│ ├── FragmentExtensions.kt
│ ├── IntentExtensions.kt
│ ├── JsonExtensions.kt
│ ├── KeyboardExtensions.kt
│ ├── NavigationExtension.kt
│ ├── ThemeExtentions.kt
│ ├── ToastExtenstions.kt
│ └── ViewExtensions.kt
│ ├── file
│ └── FileUtils.kt
│ └── spinner
│ ├── MaterialSpinnerUtil.kt
│ └── SpinnerUtil.kt
└── res
├── drawable
├── bg_top_rounded_white.xml
└── ic_back.xml
├── layout
└── progress.xml
├── values-ar
└── strings.xml
└── values
├── colors.xml
├── strings.xml
└── styles.xml
/.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/.name:
--------------------------------------------------------------------------------
1 | base-android
--------------------------------------------------------------------------------
/.idea/compiler.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 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
24 |
25 |
--------------------------------------------------------------------------------
/.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 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Config:
--------------------------------------------------------------------------------
1 | BaseUrl = https://baseurl.com
2 | SocketPort = 4000
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # base-android
2 |
3 | - This is the base code that I prefer to work in small and medium projects.
4 |
5 | - using clean architecture and MVVM architecture pattern
6 | - coding in kotlin language
7 |
8 | # Modules
9 | - Domain: contains business logic
10 | - Data: contains data sources
11 | - presentation: contains ui
12 | - utils: contains common utils functions that are useful for fast coding
13 |
14 | # Technologies
15 | - Dagger-Hilt for dependency injection
16 | - Retrofit and Okhttp for network
17 | - Socket-io for realtime
18 | - Datastore for saving small data in (key-value)
19 | - ViewBinding for binding views
20 | - Navigation-Component for navigation between screens
21 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'org.jetbrains.kotlin.android'
4 | id 'kotlin-kapt'
5 | id 'dagger.hilt.android.plugin'
6 | id 'com.google.gms.google-services'
7 | id 'com.google.firebase.crashlytics'
8 | id 'androidx.navigation.safeargs.kotlin'
9 | }
10 |
11 | android {
12 | compileSdk 31
13 |
14 | defaultConfig {
15 | applicationId ApplicationId.id
16 | minSdk 21
17 | targetSdk 31
18 | versionCode 1
19 | versionName "1.0"
20 |
21 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
22 | }
23 |
24 | buildTypes {
25 | release {
26 | minifyEnabled false
27 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
28 | }
29 | }
30 | compileOptions {
31 | sourceCompatibility JavaVersion.VERSION_1_8
32 | targetCompatibility JavaVersion.VERSION_1_8
33 | }
34 | kotlinOptions {
35 | jvmTarget = '1.8'
36 | }
37 |
38 | buildFeatures {
39 | viewBinding true
40 | }
41 | }
42 |
43 | dependencies {
44 | api project(':presentation')
45 | api project(':data')
46 | api project(':domain')
47 | api project(':utils')
48 |
49 | implementation Compilers.hilt_android
50 | kapt Compilers.hilt_android_compiler
51 | kapt Compilers.hilt_android_lifecycle_compiler
52 |
53 | implementation Dependencies.firebase_analytics
54 | implementation Dependencies.firebase_crashlytics
55 | implementation Dependencies.firebase_messaging
56 | implementation Dependencies.firebase_core
57 | implementation Dependencies.firebase_iid
58 | }
--------------------------------------------------------------------------------
/app/google-services.json:
--------------------------------------------------------------------------------
1 | {
2 | "project_info": {
3 | "project_number": "35622279526",
4 | "project_id": "base-android-27992",
5 | "storage_bucket": "base-android-27992.appspot.com"
6 | },
7 | "client": [
8 | {
9 | "client_info": {
10 | "mobilesdk_app_id": "1:35622279526:android:b4def4dc1449b3d1f3d0a7",
11 | "android_client_info": {
12 | "package_name": "com.devm7mdibrahim.baseandroid"
13 | }
14 | },
15 | "oauth_client": [
16 | {
17 | "client_id": "35622279526-kepnaj5e8hvhqmlhk3i20ui539ib46r6.apps.googleusercontent.com",
18 | "client_type": 3
19 | }
20 | ],
21 | "api_key": [
22 | {
23 | "current_key": "AIzaSyCQC_iW96x0V2jC3LdwiBqfVWrFobvjDqM"
24 | }
25 | ],
26 | "services": {
27 | "appinvite_service": {
28 | "other_platform_oauth_client": [
29 | {
30 | "client_id": "35622279526-kepnaj5e8hvhqmlhk3i20ui539ib46r6.apps.googleusercontent.com",
31 | "client_type": 3
32 | }
33 | ]
34 | }
35 | }
36 | }
37 | ],
38 | "configuration_version": "1"
39 | }
--------------------------------------------------------------------------------
/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/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
19 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
35 |
36 |
39 |
42 |
43 |
48 |
49 |
50 |
51 |
52 |
53 |
56 |
57 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/app/src/main/java/com/devm7mdibrahim/base_android/BaseApp.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.base_android
2 |
3 | import android.app.NotificationChannel
4 | import android.app.NotificationManager
5 | import android.content.Context
6 | import android.media.AudioAttributes
7 | import android.media.RingtoneManager
8 | import android.os.Build
9 | import com.devm7mdibrahim.data.remote.utils.NetworkConstants.Languages.ARABIC
10 | import com.devm7mdibrahim.utils.extensions.ThemeHelper
11 | import com.akexorcist.localizationactivity.ui.LocalizationApplication
12 | import dagger.hilt.android.HiltAndroidApp
13 | import java.util.*
14 |
15 | @HiltAndroidApp
16 | class BaseApp : LocalizationApplication() {
17 |
18 | private lateinit var notificationManager: NotificationManager
19 |
20 | companion object {
21 | const val CHANNEL_ID = "base_channel_id"
22 | const val CHANNEL_NAME = "base_channel"
23 | }
24 |
25 | override fun getDefaultLanguage(base: Context): Locale {
26 | return Locale(ARABIC)
27 | }
28 |
29 | override fun onCreate() {
30 | super.onCreate()
31 | ThemeHelper.applyTheme(ThemeHelper.ThemeMode.LIGHT)
32 | }
33 |
34 | override fun attachBaseContext(base: Context) {
35 | super.attachBaseContext(base)
36 | notificationManager =
37 | base.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
38 |
39 | createAppChannel()
40 | }
41 |
42 | private fun createAppChannel() {
43 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
44 |
45 | val notificationChannel = NotificationChannel(
46 | CHANNEL_ID,
47 | CHANNEL_NAME,
48 | NotificationManager.IMPORTANCE_HIGH
49 | )
50 |
51 | val defaultSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
52 |
53 | notificationChannel.setSound(
54 | defaultSound,
55 | AudioAttributes.Builder()
56 | .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
57 | .setUsage(AudioAttributes.USAGE_MEDIA)
58 | .build()
59 | )
60 |
61 | notificationManager.createNotificationChannel(notificationChannel)
62 | }
63 | }
64 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devm7mdibrahim/base_android/fcm/NotificationItem.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.base_android.fcm
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | data class NotificationItem(
6 | @SerializedName("message_ar") val messageAr: String? = "",
7 | @SerializedName("message_en") val messageEn: String? = "",
8 | @SerializedName("title_ar") val titleAr: String? = "",
9 | @SerializedName("title_en") val titleEn: String? = "",
10 | @SerializedName("type") val type: String? = "",
11 | )
12 |
--------------------------------------------------------------------------------
/app/src/main/java/com/devm7mdibrahim/base_android/fcm/NotificationKey.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.base_android.fcm
2 |
3 | object NotificationKey {
4 | const val NEW_ORDER = "new_order"
5 | const val NEW_MESSAGE = "new_message"
6 | }
--------------------------------------------------------------------------------
/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/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/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/app/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/app/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | google()
4 | gradlePluginPortal()
5 | mavenCentral()
6 | maven { url 'https://jitpack.io' }
7 | }
8 |
9 | dependencies {
10 | classpath Build.build_tools
11 | classpath Build.kotlin_gradle_plugin
12 | classpath Build.google_services
13 | classpath Build.crashlytics_gradle
14 | classpath Build.hilt_gradle
15 | classpath Build.navigation
16 | }
17 | }
18 |
19 | allprojects {
20 | repositories {
21 | google()
22 | mavenCentral()
23 | maven { url "https://maven.google.com" }
24 | maven { url 'https://jitpack.io' }
25 | }
26 | }
27 |
28 | task clean(type: Delete) {
29 | delete rootProject.buildDir
30 | }
--------------------------------------------------------------------------------
/buildSrc/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import org.gradle.kotlin.dsl.`kotlin-dsl`
2 |
3 | plugins {
4 | `kotlin-dsl`
5 | }
6 | repositories {
7 | mavenCentral()
8 | }
--------------------------------------------------------------------------------
/buildSrc/build/classes/kotlin/main/AndroidTestDependencies.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/classes/kotlin/main/AndroidTestDependencies.class
--------------------------------------------------------------------------------
/buildSrc/build/classes/kotlin/main/ApplicationId.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/classes/kotlin/main/ApplicationId.class
--------------------------------------------------------------------------------
/buildSrc/build/classes/kotlin/main/Build.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/classes/kotlin/main/Build.class
--------------------------------------------------------------------------------
/buildSrc/build/classes/kotlin/main/Compilers.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/classes/kotlin/main/Compilers.class
--------------------------------------------------------------------------------
/buildSrc/build/classes/kotlin/main/Dependencies.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/classes/kotlin/main/Dependencies.class
--------------------------------------------------------------------------------
/buildSrc/build/classes/kotlin/main/META-INF/buildSrc.kotlin_module:
--------------------------------------------------------------------------------
1 | " *
--------------------------------------------------------------------------------
/buildSrc/build/classes/kotlin/main/SupportDependencies.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/classes/kotlin/main/SupportDependencies.class
--------------------------------------------------------------------------------
/buildSrc/build/classes/kotlin/main/TestDependencies.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/classes/kotlin/main/TestDependencies.class
--------------------------------------------------------------------------------
/buildSrc/build/classes/kotlin/main/Versions.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/classes/kotlin/main/Versions.class
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/buildSrcjar-classes.txt:
--------------------------------------------------------------------------------
1 | /Users/aait/StudioProjects/base-android/buildSrc/build/classes/kotlin/main/AndroidTestDependencies.class:/Users/aait/StudioProjects/base-android/buildSrc/build/classes/kotlin/main/ApplicationId.class:/Users/aait/StudioProjects/base-android/buildSrc/build/classes/kotlin/main/Build.class:/Users/aait/StudioProjects/base-android/buildSrc/build/classes/kotlin/main/Compilers.class:/Users/aait/StudioProjects/base-android/buildSrc/build/classes/kotlin/main/Dependencies.class:/Users/aait/StudioProjects/base-android/buildSrc/build/classes/kotlin/main/SupportDependencies.class:/Users/aait/StudioProjects/base-android/buildSrc/build/classes/kotlin/main/TestDependencies.class:/Users/aait/StudioProjects/base-android/buildSrc/build/classes/kotlin/main/Versions.class
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/build-history.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/build-history.bin
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.keystream.len:
--------------------------------------------------------------------------------
1 | i
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.len:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.len
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.values.at:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab.values.at
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab_i:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab_i
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab_i.len:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/inputs/source-to-output.tab_i.len
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len:
--------------------------------------------------------------------------------
1 | q
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.len:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.len
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab.values.at:
--------------------------------------------------------------------------------
1 | / Header Record For PersistentHashMapValueStorage
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab_i:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab_i
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab_i.len:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-attributes.tab_i.len
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len:
--------------------------------------------------------------------------------
1 | q
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at:
--------------------------------------------------------------------------------
1 | / Header Record For PersistentHashMapValueStorage7 6$PROJECT_DIR$/src/main/java/AndroidTestDependencies.kt- ,$PROJECT_DIR$/src/main/java/ApplicationId.kt% $$PROJECT_DIR$/src/main/java/Build.kt) ($PROJECT_DIR$/src/main/java/Compilers.kt, +$PROJECT_DIR$/src/main/java/Dependencies.kt3 2$PROJECT_DIR$/src/main/java/SupportDependencies.kt0 /$PROJECT_DIR$/src/main/java/TestDependencies.kt( '$PROJECT_DIR$/src/main/java/Versions.kt, +$PROJECT_DIR$/src/main/java/Dependencies.kt( '$PROJECT_DIR$/src/main/java/Versions.kt
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i.len:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i.len
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.keystream.len:
--------------------------------------------------------------------------------
1 | q
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.len:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.len
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.values.at:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab.values.at
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab_i:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab_i
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab_i.len:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/constants.tab_i.len
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len:
--------------------------------------------------------------------------------
1 | q
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at:
--------------------------------------------------------------------------------
1 | / Header Record For PersistentHashMapValueStorage7 6$PROJECT_DIR$/src/main/java/AndroidTestDependencies.kt- ,$PROJECT_DIR$/src/main/java/ApplicationId.kt% $$PROJECT_DIR$/src/main/java/Build.kt) ($PROJECT_DIR$/src/main/java/Compilers.kt, +$PROJECT_DIR$/src/main/java/Dependencies.kt3 2$PROJECT_DIR$/src/main/java/SupportDependencies.kt0 /$PROJECT_DIR$/src/main/java/TestDependencies.kt( '$PROJECT_DIR$/src/main/java/Versions.kt, +$PROJECT_DIR$/src/main/java/Dependencies.kt( '$PROJECT_DIR$/src/main/java/Versions.kt
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i.len:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i.len
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.keystream:
--------------------------------------------------------------------------------
1 | AndroidTestDependencies
ApplicationIdBuild CompilersDependenciesSupportDependenciesTestDependenciesVersions.kotlin_module
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.keystream.len:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.keystream.len
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.len:
--------------------------------------------------------------------------------
1 | �
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.values.at:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab.values.at
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab_i:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab_i
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab_i.len:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/proto.tab_i.len
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream.len:
--------------------------------------------------------------------------------
1 | i
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.len:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.len
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at:
--------------------------------------------------------------------------------
1 | / Header Record For PersistentHashMapValueStorage' AndroidTestDependencies.kotlin_module
ApplicationId.kotlin_module Build.kotlin_module Compilers.kotlin_module Dependencies.kotlin_module# SupportDependencies.kotlin_module TestDependencies.kotlin_module Versions.kotlin_module Dependencies.kotlin_module Versions.kotlin_module
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab_i:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab_i
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab_i.len:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/jvm/kotlin/source-to-classes.tab_i.len
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/counters.tab:
--------------------------------------------------------------------------------
1 | 10
2 | 0
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.keystream.len:
--------------------------------------------------------------------------------
1 | i
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.len:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.len
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab.values.at:
--------------------------------------------------------------------------------
1 | / Header Record For PersistentHashMapValueStorage
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab_i:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab_i
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab_i.len:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/file-to-id.tab_i.len
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.keystream.len:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.len:
--------------------------------------------------------------------------------
1 | �
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab.values.at:
--------------------------------------------------------------------------------
1 | / Header Record For PersistentHashMapValueStorage7 6$PROJECT_DIR$/src/main/java/AndroidTestDependencies.kt- ,$PROJECT_DIR$/src/main/java/ApplicationId.kt% $$PROJECT_DIR$/src/main/java/Build.kt) ($PROJECT_DIR$/src/main/java/Compilers.kt, +$PROJECT_DIR$/src/main/java/Dependencies.kt3 2$PROJECT_DIR$/src/main/java/SupportDependencies.kt0 /$PROJECT_DIR$/src/main/java/TestDependencies.kt( '$PROJECT_DIR$/src/main/java/Versions.kt, +$PROJECT_DIR$/src/main/java/Dependencies.kt( '$PROJECT_DIR$/src/main/java/Versions.kt
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab_i:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab_i
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab_i.len:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/id-to-file.tab_i.len
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.keystream:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.keystream
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.keystream.len:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.keystream.len
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.len:
--------------------------------------------------------------------------------
1 | �
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.values.at:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab.values.at
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab_i:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab_i
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab_i.len:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/caches-jvm/lookups/lookups.tab_i.len
--------------------------------------------------------------------------------
/buildSrc/build/kotlin/compileKotlin/last-build.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/kotlin/compileKotlin/last-build.bin
--------------------------------------------------------------------------------
/buildSrc/build/libs/buildSrc.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/libs/buildSrc.jar
--------------------------------------------------------------------------------
/buildSrc/build/pluginUnderTestMetadata/plugin-under-test-metadata.properties:
--------------------------------------------------------------------------------
1 | implementation-classpath=/Users/aait/StudioProjects/base-android/buildSrc/build/classes/java/main\:/Users/aait/StudioProjects/base-android/buildSrc/build/classes/groovy/main\:/Users/aait/StudioProjects/base-android/buildSrc/build/classes/kotlin/main\:/Users/aait/StudioProjects/base-android/buildSrc/build/resources/main
2 |
--------------------------------------------------------------------------------
/buildSrc/build/reports/plugin-development/validation-report.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/buildSrc/build/reports/plugin-development/validation-report.txt
--------------------------------------------------------------------------------
/buildSrc/build/tmp/jar/MANIFEST.MF:
--------------------------------------------------------------------------------
1 | Manifest-Version: 1.0
2 |
3 |
--------------------------------------------------------------------------------
/buildSrc/src/main/java/AndroidTestDependencies.kt:
--------------------------------------------------------------------------------
1 | object AndroidTestDependencies{
2 | const val kotlin_test = "org.jetbrains.kotlin:kotlin-test-junit:${Versions.kotlin}"
3 | const val coroutines_test = "org.jetbrains.kotlinx:kotlinx-coroutines-test:${Versions.coroutines_version}"
4 | const val espresso_core = "androidx.test.espresso:espresso-core:${Versions.espresso_core}"
5 | const val espresso_contrib = "androidx.test.espresso:espresso-contrib:${Versions.espresso_core}"
6 | const val idling_resource = "androidx.test.espresso:espresso-idling-resource:${Versions.espresso_idling_resource}"
7 | const val test_runner = "androidx.test:runner:${Versions.test_runner}"
8 | const val test_rules = "androidx.test:rules:${Versions.test_runner}"
9 | const val text_core_ktx = "androidx.test:core-ktx:${Versions.test_core}"
10 | const val mockk_android = "io.mockk:mockk-android:${Versions.mockk_version}"
11 | const val fragment_testing = "androidx.fragment:fragment-testing:${Versions.fragment_version}"
12 | const val androidx_test_ext = "androidx.test.ext:junit-ktx:${Versions.androidx_test_ext}"
13 | const val navigation_testing = "androidx.navigation:navigation-testing:${Versions.nav_components}"
14 |
15 | const val instrumentation_runner = "com.codingwithmitch.cleannotes.framework.MockTestRunner"
16 | }
--------------------------------------------------------------------------------
/buildSrc/src/main/java/ApplicationId.kt:
--------------------------------------------------------------------------------
1 | object ApplicationId {
2 | const val id = "com.devm7mdibrahim.baseandroid"
3 | }
--------------------------------------------------------------------------------
/buildSrc/src/main/java/Build.kt:
--------------------------------------------------------------------------------
1 | object Build {
2 | const val build_tools = "com.android.tools.build:gradle:7.2.1"
3 | const val kotlin_gradle_plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.0"
4 | const val google_services = "com.google.gms:google-services:${Versions.play_services}"
5 | const val junit5 = "de.mannodermaus.gradle.plugins:android-junit5:1.3.2.0"
6 | const val navigation = "androidx.navigation:navigation-safe-args-gradle-plugin:${Versions.nav_version}"
7 | const val crashlytics_gradle = "com.google.firebase:firebase-crashlytics-gradle:${Versions.crashlytics_gradle}"
8 | const val hilt_gradle = "com.google.dagger:hilt-android-gradle-plugin:2.38.1"
9 | }
--------------------------------------------------------------------------------
/buildSrc/src/main/java/Compilers.kt:
--------------------------------------------------------------------------------
1 | object Compilers {
2 | const val room_compiler = "androidx.room:room-compiler:${Versions.room}"
3 | const val lifecycle_compiler = "androidx.lifecycle:lifecycle-compiler:${Versions.lifecycle_version}"
4 |
5 | const val dagger = "com.google.dagger:dagger:${Versions.hiltVersion}"
6 | const val hilt_android = "com.google.dagger:hilt-android:${Versions.hiltVersion}"
7 | const val hilt_android_compiler = "com.google.dagger:hilt-android-compiler:${Versions.hiltVersion}"
8 | const val hilt_android_lifecycle_compiler =
9 | "androidx.hilt:hilt-compiler:${Versions.hiltAndroidXVersionCompiler}"
10 | }
--------------------------------------------------------------------------------
/buildSrc/src/main/java/SupportDependencies.kt:
--------------------------------------------------------------------------------
1 | object SupportDependencies {
2 | const val support_lib = "androidx.legacy:legacy-support-v4:1.0.0"
3 | const val appcompat = "androidx.appcompat:appcompat:${Versions.appcompat}"
4 | const val constraintlayout = "androidx.constraintlayout:constraintlayout:${Versions.constraintlayout}"
5 | const val material_design = "com.google.android.material:material:${Versions.material_design}"
6 | const val swipe_refresh_layout = "androidx.swiperefreshlayout:swiperefreshlayout:${Versions.swipe_refresh_layout}"
7 | const val circular_image_view = "de.hdodenhof:circleimageview:${Versions.circular_image_view}"
8 |
9 | const val sdp_library = "com.intuit.sdp:sdp-android:1.0.6"
10 | const val ssp_library = "com.intuit.ssp:ssp-android:1.0.6"
11 | }
--------------------------------------------------------------------------------
/buildSrc/src/main/java/TestDependencies.kt:
--------------------------------------------------------------------------------
1 | object TestDependencies {
2 | const val jupiter_api = "org.junit.jupiter:junit-jupiter-api:${Versions.junit_jupiter_version}"
3 | const val jupiter_params = "org.junit.jupiter:junit-jupiter-params:${Versions.junit_jupiter_version}"
4 | const val jupiter_engine = "org.junit.jupiter:junit-jupiter-engine:${Versions.junit_jupiter_version}"
5 | const val mockk = "io.mockk:mockk:${Versions.mockk_version}"
6 | const val junit4 = "junit:junit:${Versions.junit_4_version}"
7 | }
--------------------------------------------------------------------------------
/buildSrc/src/main/java/Versions.kt:
--------------------------------------------------------------------------------
1 | object Versions {
2 | const val gradle = "7.2.1"
3 | const val compilesdk = 30
4 | const val buildTool = 30
5 | const val buildToolsVersion = "30.0.3"
6 | const val minsdk = 21
7 | const val targetsdk = 30
8 | const val version_code = 1
9 | const val version_name = "1.0"
10 | const val kotlin = "1.5.0"
11 | const val java = "1.8"
12 | const val ktx = "1.2.0"
13 | const val multidex = "2.0.1"
14 | const val dagger = "2.25.4"
15 | const val nav_components = "2.4.1"
16 | const val material_dialogs = "3.2.1"
17 | const val room = "2.3.0"
18 | const val datastore = "1.0.0-beta01"
19 | const val appcompat = "1.1.0-rc01"
20 | const val constraintlayout = "1.1.3"
21 | const val material_design = "1.1.0"
22 | const val play_core = "1.7.1"
23 | const val play_services = "4.3.4"
24 | const val nav_version = "2.4.1"
25 | const val leak_canary = "2.0-alpha-3"
26 | const val swipe_refresh_layout = "1.1.0-alpha03"
27 | const val circular_image_view = "3.1.0"
28 |
29 | const val firebase_analytics = "17.4.1"
30 | const val firebase_crashlytics = "17.0.0"
31 | const val firebase_messaging = "22.0.0"
32 | const val firebase_auth = "19.3.0"
33 | const val firebase_core = "19.0.2"
34 |
35 | const val espresso_core = "3.1.1"
36 | const val espresso_idling_resource = "3.2.0"
37 | const val mockk_version = "1.9.2"
38 | const val test_runner = "1.2.0"
39 | const val test_core = "1.2.0"
40 | const val coroutines_version = "1.3.0"
41 | const val coroutines_play_services = "1.3.2"
42 | const val lifecycle_version = "2.2.0-alpha03"
43 | const val retrofit2_version = "2.9.0"
44 | const val moshi = "1.9.3"
45 | const val markdown_processor = "0.1.3"
46 | const val junit_jupiter_version = "5.6.0"
47 | const val junit_4_version = "4.12"
48 | const val fragment_version = "1.2.0"
49 | const val androidx_test_ext = "1.1.1"
50 | const val crashlytics_gradle = "2.7.1"
51 | const val hiltVersion = "2.38.1"
52 | const val hiltAndroidXVersionCompiler = "1.0.0"
53 | const val logging_interceptor = "3.0.0"
54 | const val rxjava_version = "3.0.0"
55 | const val rxjavaAndroid_version = "3.0.11"
56 | const val reactivestreams_version = "1.1.1"
57 | const val rxjava2adapter_version = "2.5.0"
58 | const val version_kotlin_coroutines = "1.3.7"
59 | const val version_retrofit_coroutines_adapter = "0.9.2"
60 | const val circle_image = "3.1.0"
61 |
62 | const val javaxAnnotationVersion = "1.0"
63 | const val javaxInjectVersion = "1"
64 | }
--------------------------------------------------------------------------------
/data/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/data/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'org.jetbrains.kotlin.android'
4 | id 'kotlin-kapt'
5 | }
6 |
7 |
8 | def myConfigPropertiesFile = rootProject.file("config")
9 | def myConfigProperties = new Properties()
10 | myConfigProperties.load(new FileInputStream(myConfigPropertiesFile))
11 |
12 | android {
13 | compileSdk 31
14 |
15 | defaultConfig {
16 | minSdk 21
17 | targetSdk 31
18 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
19 | consumerProguardFiles "consumer-rules.pro"
20 | }
21 |
22 | compileOptions {
23 | sourceCompatibility JavaVersion.VERSION_1_8
24 | targetCompatibility JavaVersion.VERSION_1_8
25 | }
26 |
27 | kotlinOptions {
28 | jvmTarget = '1.8'
29 | }
30 |
31 | buildTypes {
32 | debug {
33 | buildConfigField("String", "BASE_URL","\"${myConfigProperties['BaseUrl']}\"")
34 | buildConfigField("String", "SOCKET_PORT","\"${myConfigProperties['SocketPort']}\"")
35 | }
36 | release {
37 | buildConfigField("String", "BASE_URL","\"${myConfigProperties['BaseUrl']}\"")
38 | buildConfigField("String", "SOCKET_PORT","\"${myConfigProperties['SocketPort']}\"")
39 | }
40 | }
41 | kapt {
42 | javacOptions {
43 | // These options are normally set automatically via the Hilt Gradle plugin, but we
44 | // set them manually to workaround a bug in the Kotlin 1.5.20
45 | option("-Adagger.fastInit=ENABLED")
46 | option("-Adagger.hilt.android.internal.disableAndroidSuperclassValidation=true")
47 | }
48 | }
49 | }
50 |
51 |
52 | dependencies {
53 | api project(':domain')
54 |
55 | api Dependencies.datastore
56 | api Dependencies.datastore_preference
57 |
58 | api Dependencies.retrofit
59 | api Dependencies.logging_interceptor
60 | api Dependencies.moshi_converter
61 | api Dependencies.moshi_kotlin
62 | api Dependencies.gson
63 |
64 | api Dependencies.room_runtime
65 | api Dependencies.room_ktx
66 | kapt Compilers.room_compiler
67 |
68 | api Dependencies.socket_io
69 |
70 | implementation Dependencies.coroutine
71 | implementation Dependencies.coroutine_android
72 | implementation Dependencies.coroutine_adapter
73 |
74 | implementation Compilers.hilt_android
75 | kapt Compilers.hilt_android_compiler
76 | kapt Compilers.hilt_android_lifecycle_compiler
77 | }
--------------------------------------------------------------------------------
/data/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/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/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/src/main/java/com/devm7mdibrahim/data/datasource/AuthDataSource.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.data.datasource
2 |
3 | import com.devm7mdibrahim.domain.entities.AuthData
4 | import com.devm7mdibrahim.domain.entities.BaseResponse
5 |
6 | interface AuthDataSource {
7 |
8 | suspend fun login(
9 | phone: String,
10 | password: String,
11 | deviceId: String
12 | ): BaseResponse
13 |
14 | suspend fun register(
15 | name: String,
16 | phone: String,
17 | email: String,
18 | password: String,
19 | avatar: String?,
20 | ): BaseResponse
21 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/devm7mdibrahim/data/datasource/ChatDataSource.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.data.datasource
2 |
3 | import com.devm7mdibrahim.domain.entities.*
4 |
5 | interface ChatDataSource {
6 | suspend fun getRooms(): BaseResponse
7 | suspend fun getChatMessages(roomId: Int): BaseResponse
8 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/devm7mdibrahim/data/datasource/HomeDataSource.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.data.datasource
2 |
3 | interface HomeDataSource {
4 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/devm7mdibrahim/data/datasource/PreferenceDataSource.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.data.datasource
2 |
3 | import kotlinx.coroutines.flow.Flow
4 |
5 | interface PreferenceDataSource {
6 | suspend fun getValue(key: String, default: Any?): Flow
7 | suspend fun setValue(key: String, value: Any?)
8 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/devm7mdibrahim/data/datasource/SocketDataSource.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.data.datasource
2 |
3 | import kotlinx.coroutines.flow.Flow
4 | import org.json.JSONObject
5 |
6 | interface SocketDataSource {
7 | fun connectSocket(): Flow
8 | fun disconnectSocket()
9 | fun openChannel(channel: String): Flow>
10 | fun setEmit(emitType: String, jsonObject: JSONObject?)
11 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/devm7mdibrahim/data/di/EndPointsModule.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.data.di
2 |
3 | import com.devm7mdibrahim.data.remote.endpoints.AuthEndPoints
4 | import com.devm7mdibrahim.data.remote.endpoints.ChatEndPoints
5 | import com.devm7mdibrahim.data.remote.endpoints.HomeEndPoints
6 | import dagger.Module
7 | import dagger.Provides
8 | import dagger.hilt.InstallIn
9 | import dagger.hilt.components.SingletonComponent
10 | import retrofit2.Retrofit
11 | import javax.inject.Singleton
12 |
13 | @Module
14 | @InstallIn(SingletonComponent::class)
15 | object EndPointsModule {
16 |
17 | @Provides
18 | @Singleton
19 | fun provideAuthEndPoints(retrofit: Retrofit): AuthEndPoints =
20 | retrofit.create(AuthEndPoints::class.java)
21 |
22 | @Provides
23 | @Singleton
24 | fun provideHomeEndPoints(retrofit: Retrofit): HomeEndPoints =
25 | retrofit.create(HomeEndPoints::class.java)
26 |
27 | @Provides
28 | @Singleton
29 | fun provideChatEndPoints(retrofit: Retrofit): ChatEndPoints =
30 | retrofit.create(ChatEndPoints::class.java)
31 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/devm7mdibrahim/data/di/PreferencesModule.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.data.di
2 |
3 | import android.content.Context
4 | import androidx.datastore.core.DataStore
5 | import androidx.datastore.preferences.core.PreferenceDataStoreFactory
6 | import androidx.datastore.preferences.core.Preferences
7 | import androidx.datastore.preferences.preferencesDataStoreFile
8 | import com.devm7mdibrahim.data.datasource.PreferenceDataSource
9 | import com.devm7mdibrahim.data.local.datasource.PreferenceDataSourceImpl
10 | import com.devm7mdibrahim.data.repository.PreferenceRepositoryImpl
11 | import com.devm7mdibrahim.domain.repository.PreferenceRepository
12 | import dagger.Module
13 | import dagger.Provides
14 | import dagger.hilt.InstallIn
15 | import dagger.hilt.android.qualifiers.ApplicationContext
16 | import dagger.hilt.components.SingletonComponent
17 | import javax.inject.Singleton
18 |
19 | @Module
20 | @InstallIn(SingletonComponent::class)
21 | object PreferencesModule {
22 |
23 | private const val PREFERENCE_NAME = "app_preferences"
24 |
25 | @Provides
26 | @Singleton
27 | fun providePreferencesDataStore(@ApplicationContext appContext: Context): DataStore =
28 | PreferenceDataStoreFactory.create(
29 | produceFile = {
30 | appContext.preferencesDataStoreFile(PREFERENCE_NAME)
31 | }
32 | )
33 |
34 | @Provides
35 | @Singleton
36 | fun providePreferencesDataSource(dataStore: DataStore): PreferenceDataSource =
37 | PreferenceDataSourceImpl(dataStore)
38 |
39 | @Provides
40 | @Singleton
41 | fun providePreferencesRepository(preferencesDataSource: PreferenceDataSource): PreferenceRepository =
42 | PreferenceRepositoryImpl(preferencesDataSource)
43 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/devm7mdibrahim/data/di/RemoteDataSourcesModule.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.data.di
2 |
3 | import com.devm7mdibrahim.data.datasource.AuthDataSource
4 | import com.devm7mdibrahim.data.datasource.ChatDataSource
5 | import com.devm7mdibrahim.data.datasource.HomeDataSource
6 | import com.devm7mdibrahim.data.remote.datasource.AuthDataSourceImpl
7 | import com.devm7mdibrahim.data.remote.datasource.ChatDataSourceImpl
8 | import com.devm7mdibrahim.data.remote.datasource.HomeDataSourceImpl
9 | import com.devm7mdibrahim.data.remote.endpoints.AuthEndPoints
10 | import com.devm7mdibrahim.data.remote.endpoints.ChatEndPoints
11 | import com.devm7mdibrahim.data.remote.endpoints.HomeEndPoints
12 | import dagger.Module
13 | import dagger.Provides
14 | import dagger.hilt.InstallIn
15 | import dagger.hilt.components.SingletonComponent
16 | import javax.inject.Singleton
17 |
18 | @Module
19 | @InstallIn(SingletonComponent::class)
20 | object RemoteDataSourcesModule {
21 |
22 | @Provides
23 | @Singleton
24 | fun provideAuthRemoteDataSource(authEndPoints: AuthEndPoints): AuthDataSource =
25 | AuthDataSourceImpl(authEndPoints)
26 |
27 | @Provides
28 | @Singleton
29 | fun provideHomeRemoteDataSource(homeEndPoints: HomeEndPoints): HomeDataSource =
30 | HomeDataSourceImpl(homeEndPoints)
31 |
32 | @Provides
33 | @Singleton
34 | fun provideChatRemoteDataSource(chatEndPoints: ChatEndPoints): ChatDataSource =
35 | ChatDataSourceImpl(chatEndPoints)
36 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/devm7mdibrahim/data/di/RepositoryModule.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.data.di
2 |
3 | import com.devm7mdibrahim.data.datasource.AuthDataSource
4 | import com.devm7mdibrahim.data.datasource.ChatDataSource
5 | import com.devm7mdibrahim.data.datasource.HomeDataSource
6 | import com.devm7mdibrahim.data.datasource.SocketDataSource
7 | import com.devm7mdibrahim.data.repository.AuthRepositoryImpl
8 | import com.devm7mdibrahim.data.repository.ChatRepositoryImpl
9 | import com.devm7mdibrahim.data.repository.HomeRepositoryImpl
10 | import com.devm7mdibrahim.domain.repository.AuthRepository
11 | import com.devm7mdibrahim.domain.repository.ChatRepository
12 | import com.devm7mdibrahim.domain.repository.HomeRepository
13 | import dagger.Module
14 | import dagger.Provides
15 | import dagger.hilt.InstallIn
16 | import dagger.hilt.components.SingletonComponent
17 | import javax.inject.Singleton
18 |
19 | @Module
20 | @InstallIn(SingletonComponent::class)
21 | object RepositoryModule {
22 |
23 | @Provides
24 | @Singleton
25 | fun provideAuthRepository(authDataSource: AuthDataSource): AuthRepository =
26 | AuthRepositoryImpl(authDataSource)
27 |
28 | @Provides
29 | @Singleton
30 | fun provideHomeRepository(homeDataSource: HomeDataSource): HomeRepository =
31 | HomeRepositoryImpl(homeDataSource)
32 |
33 | @Provides
34 | @Singleton
35 | fun provideChatRepository(chatDataSource: ChatDataSource, socketDataSource: SocketDataSource): ChatRepository =
36 | ChatRepositoryImpl(chatDataSource, socketDataSource)
37 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/devm7mdibrahim/data/di/SocketModule.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.data.di
2 |
3 | import com.devm7mdibrahim.data.datasource.SocketDataSource
4 | import com.devm7mdibrahim.data.socket.datasource.SocketDataSourceImpl
5 | import dagger.Module
6 | import dagger.Provides
7 | import dagger.hilt.InstallIn
8 | import dagger.hilt.components.SingletonComponent
9 | import io.socket.client.IO
10 | import io.socket.client.Socket
11 | import javax.inject.Singleton
12 |
13 | @Module
14 | @InstallIn(SingletonComponent::class)
15 | object SocketModule {
16 |
17 | @Provides
18 | @Singleton
19 | fun provideSocketDataSource(socket: Socket): SocketDataSource {
20 | return SocketDataSourceImpl(socket)
21 | }
22 |
23 | @Provides
24 | @Singleton
25 | fun provideSocket(@StringsModule.SocketBaseUrl socketBaseUrl: String): Socket {
26 | return IO.socket(socketBaseUrl)
27 | }
28 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/devm7mdibrahim/data/di/StringsModule.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.data.di
2 |
3 | import com.devm7mdibrahim.data.BuildConfig
4 | import com.devm7mdibrahim.data.remote.utils.NetworkConstants.API_VERSION
5 | import dagger.Module
6 | import dagger.Provides
7 | import dagger.hilt.InstallIn
8 | import dagger.hilt.components.SingletonComponent
9 | import javax.inject.Qualifier
10 |
11 | @Module
12 | @InstallIn(SingletonComponent::class)
13 | object StringsModule {
14 |
15 | @Qualifier
16 | @Retention(AnnotationRetention.BINARY)
17 | annotation class BaseUrl
18 |
19 | @Qualifier
20 | @Retention(AnnotationRetention.BINARY)
21 | annotation class RemoteBaseUrl
22 |
23 | @Qualifier
24 | @Retention(AnnotationRetention.BINARY)
25 | annotation class SocketPort
26 |
27 | @Qualifier
28 | @Retention(AnnotationRetention.BINARY)
29 | annotation class SocketBaseUrl
30 |
31 | @Provides
32 | @BaseUrl
33 | fun provideBaseUrl(): String = BuildConfig.BASE_URL
34 |
35 | @Provides
36 | @RemoteBaseUrl
37 | fun provideRemoteBaseUrl(@BaseUrl baseUrl: String): String = "$baseUrl${API_VERSION}"
38 |
39 | @Provides
40 | @SocketPort
41 | fun provideSocketPort(): String = BuildConfig.SOCKET_PORT
42 |
43 | @Provides
44 | @SocketBaseUrl
45 | fun provideSocketBaseUrl(@BaseUrl baseUrl: String, @SocketPort socketPort: String): String =
46 | "${baseUrl}:${socketPort}"
47 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/devm7mdibrahim/data/local/datasource/PreferenceDataSourceImpl.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.data.local.datasource
2 |
3 | import androidx.datastore.core.DataStore
4 | import androidx.datastore.preferences.core.*
5 | import com.devm7mdibrahim.data.datasource.PreferenceDataSource
6 | import kotlinx.coroutines.flow.Flow
7 | import kotlinx.coroutines.flow.map
8 | import javax.inject.Inject
9 |
10 | class PreferenceDataSourceImpl @Inject constructor(private val dataStore: DataStore) :
11 | PreferenceDataSource {
12 |
13 | override suspend fun getValue(key: String, default: Any?): Flow {
14 | return dataStore.data.map {
15 | when (default) {
16 | is String -> {
17 | it[stringPreferencesKey(key)] ?: default
18 | }
19 |
20 | is Double -> {
21 | it[doublePreferencesKey(key)] ?: default
22 | }
23 |
24 | is Int -> {
25 | it[intPreferencesKey(key)] ?: default
26 | }
27 |
28 | is Float -> {
29 | it[floatPreferencesKey(key)] ?: default
30 | }
31 |
32 | is Boolean -> {
33 | it[booleanPreferencesKey(key)] ?: default
34 | }
35 |
36 | is Long -> {
37 | it[longPreferencesKey(key)] ?: default
38 | }
39 | else -> default
40 | }
41 | }
42 | }
43 |
44 | override suspend fun setValue(key: String, value: Any?) {
45 | dataStore.edit {
46 | when (value) {
47 | is String -> {
48 | it[stringPreferencesKey(key)] = value
49 | }
50 |
51 | is Double -> {
52 | it[doublePreferencesKey(key)] = value
53 | }
54 |
55 | is Int -> {
56 | it[intPreferencesKey(key)] = value
57 | }
58 |
59 | is Float -> {
60 | it[floatPreferencesKey(key)] = value
61 | }
62 |
63 | is Boolean -> {
64 | it[booleanPreferencesKey(key)] = value
65 | }
66 |
67 | is Long -> {
68 | it[longPreferencesKey(key)] = value
69 | }
70 | }
71 | }
72 | }
73 | }
74 |
75 |
--------------------------------------------------------------------------------
/data/src/main/java/com/devm7mdibrahim/data/local/utils/PreferenceConstants.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.data.local.utils
2 |
3 | object PreferenceConstants {
4 | const val PREFERENCE_NAME = "base_preferences"
5 | const val IS_ARABIC = "isArabic"
6 | const val LANGUAGE = "language"
7 | const val TOKEN = "token"
8 | const val USER_DATA = "userData"
9 | const val FIREBASE_TOKEN = "firebaseToken"
10 | const val ADDRESS = "address"
11 | const val LATITUDE = "latitude"
12 | const val LONGITUDE = "longitude"
13 | const val IS_ACTIVATED = "is_activated"
14 | const val IS_PROFILE_COMPLETED = "is_profile_completed"
15 | const val IS_FIRST_TIME = "is_first_time"
16 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/devm7mdibrahim/data/local/utils/SafeCacheCall.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.data.local.utils
2 |
3 | import com.devm7mdibrahim.domain.exceptions.LocalExceptions
4 | import com.devm7mdibrahim.domain.util.DataState
5 | import kotlinx.coroutines.CoroutineDispatcher
6 | import kotlinx.coroutines.TimeoutCancellationException
7 | import kotlinx.coroutines.flow.*
8 | import kotlinx.coroutines.withTimeout
9 |
10 | const val CACHE_TIMEOUT = 30000L
11 |
12 | suspend fun safeCacheCall(
13 | dispatcher: CoroutineDispatcher,
14 | cacheCall: suspend () -> T?
15 | ): Flow> = flow {
16 | withTimeout(CACHE_TIMEOUT) {
17 | val response = cacheCall.invoke()
18 |
19 | if (response != null) {
20 | emit(DataState.Success(response))
21 | } else {
22 | emit(DataState.Error(LocalExceptions.UnknownException))
23 | }
24 | }
25 | }.onStart {
26 | emit(DataState.Loading)
27 | }.catch {
28 | when (it) {
29 | is TimeoutCancellationException -> {
30 | emit(DataState.Error(LocalExceptions.TimeoutException))
31 | }
32 | else -> {
33 | emit(DataState.Error(LocalExceptions.UnknownException))
34 | }
35 | }
36 | }.flowOn(dispatcher)
--------------------------------------------------------------------------------
/data/src/main/java/com/devm7mdibrahim/data/remote/datasource/AuthDataSourceImpl.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.data.remote.datasource
2 |
3 | import com.devm7mdibrahim.data.datasource.AuthDataSource
4 | import com.devm7mdibrahim.data.remote.endpoints.AuthEndPoints
5 | import com.devm7mdibrahim.data.remote.utils.NetworkConstants.NetworkParams.AVATAR
6 | import com.devm7mdibrahim.data.utils.MultiPartUtil.prepareImagePart
7 | import com.devm7mdibrahim.data.utils.MultiPartUtil.toMultiPart
8 | import com.devm7mdibrahim.domain.entities.AuthData
9 | import com.devm7mdibrahim.domain.entities.BaseResponse
10 | import javax.inject.Inject
11 |
12 | class AuthDataSourceImpl @Inject constructor(private val authEndPoints: AuthEndPoints): AuthDataSource {
13 |
14 | override suspend fun login(
15 | phone: String,
16 | password: String,
17 | deviceId: String
18 | ): BaseResponse {
19 | return authEndPoints.login(
20 | phone = phone,
21 | password = password,
22 | deviceId = deviceId
23 | )
24 | }
25 |
26 | override suspend fun register(
27 | name: String,
28 | phone: String,
29 | email: String,
30 | password: String,
31 | avatar: String?
32 | ): BaseResponse {
33 | return authEndPoints.register(
34 | name = name.toMultiPart(),
35 | phone = phone.toMultiPart(),
36 | email = email.toMultiPart(),
37 | password = password.toMultiPart(),
38 | avatar = avatar?.let { prepareImagePart(AVATAR, it) }
39 | )
40 | }
41 |
42 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/devm7mdibrahim/data/remote/datasource/ChatDataSourceImpl.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.data.remote.datasource
2 |
3 | import com.devm7mdibrahim.data.datasource.ChatDataSource
4 | import com.devm7mdibrahim.data.remote.endpoints.ChatEndPoints
5 | import com.devm7mdibrahim.domain.entities.*
6 | import javax.inject.Inject
7 |
8 | class ChatDataSourceImpl @Inject constructor(private val chatEndPoints: ChatEndPoints) :
9 | ChatDataSource {
10 |
11 | override suspend fun getRooms(): BaseResponse {
12 | return chatEndPoints.getRooms()
13 | }
14 |
15 | override suspend fun getChatMessages(roomId: Int): BaseResponse {
16 | return chatEndPoints.getChatMessages(roomId)
17 | }
18 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/devm7mdibrahim/data/remote/datasource/HomeDataSourceImpl.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.data.remote.datasource
2 |
3 | import com.devm7mdibrahim.data.datasource.HomeDataSource
4 | import com.devm7mdibrahim.data.remote.endpoints.HomeEndPoints
5 | import javax.inject.Inject
6 |
7 | class HomeDataSourceImpl @Inject constructor(private val homeEndPoints: HomeEndPoints) :
8 | HomeDataSource {
9 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/devm7mdibrahim/data/remote/endpoints/AuthEndPoints.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.data.remote.endpoints
2 |
3 | import com.devm7mdibrahim.data.remote.utils.NetworkConstants.EndPoints.LOGIN
4 | import com.devm7mdibrahim.data.remote.utils.NetworkConstants.EndPoints.REGISTER
5 | import com.devm7mdibrahim.data.remote.utils.NetworkConstants.NetworkParams.DEVICE_ID
6 | import com.devm7mdibrahim.data.remote.utils.NetworkConstants.NetworkParams.DEVICE_TYPE
7 | import com.devm7mdibrahim.data.remote.utils.NetworkConstants.NetworkParams.EMAIL
8 | import com.devm7mdibrahim.data.remote.utils.NetworkConstants.NetworkParams.NAME
9 | import com.devm7mdibrahim.data.remote.utils.NetworkConstants.NetworkParams.PASSWORD
10 | import com.devm7mdibrahim.data.remote.utils.NetworkConstants.NetworkParams.PHONE
11 | import com.devm7mdibrahim.data.remote.utils.NetworkConstants.NetworkParams.TYPE_ANDROID
12 | import com.devm7mdibrahim.domain.entities.AuthData
13 | import com.devm7mdibrahim.domain.entities.BaseResponse
14 | import okhttp3.MultipartBody
15 | import okhttp3.RequestBody
16 | import retrofit2.http.*
17 |
18 | interface AuthEndPoints {
19 |
20 | @FormUrlEncoded
21 | @POST(LOGIN)
22 | suspend fun login(
23 | @Field(PHONE) phone: String,
24 | @Field(PASSWORD) password: String,
25 | @Field(DEVICE_ID) deviceId: String,
26 | @Field(DEVICE_TYPE) deviceType: String = TYPE_ANDROID
27 | ): BaseResponse
28 |
29 | @Multipart
30 | @POST(REGISTER)
31 | suspend fun register(
32 | @Part(NAME) name: RequestBody,
33 | @Part(PHONE) phone: RequestBody,
34 | @Part(EMAIL) email: RequestBody,
35 | @Part(PASSWORD) password: RequestBody,
36 | @Part avatar: MultipartBody.Part?,
37 | ): BaseResponse
38 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/devm7mdibrahim/data/remote/endpoints/ChatEndPoints.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.data.remote.endpoints
2 |
3 | import com.devm7mdibrahim.data.remote.utils.NetworkConstants.EndPoints.CONVERSATION
4 | import com.devm7mdibrahim.data.remote.utils.NetworkConstants.EndPoints.ROOMS
5 | import com.devm7mdibrahim.data.remote.utils.NetworkConstants.EndPoints.ROOM_ID
6 | import com.devm7mdibrahim.domain.entities.BaseResponse
7 | import com.devm7mdibrahim.domain.entities.ChatResponse
8 | import com.devm7mdibrahim.domain.entities.RoomsResponse
9 | import retrofit2.http.Field
10 | import retrofit2.http.FormUrlEncoded
11 | import retrofit2.http.GET
12 | import retrofit2.http.POST
13 |
14 | interface ChatEndPoints {
15 | @GET(ROOMS)
16 | suspend fun getRooms(): BaseResponse
17 |
18 | @FormUrlEncoded
19 | @POST(CONVERSATION)
20 | suspend fun getChatMessages(@Field(ROOM_ID) roomId: Int): BaseResponse
21 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/devm7mdibrahim/data/remote/endpoints/HomeEndPoints.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.data.remote.endpoints
2 |
3 | interface HomeEndPoints {
4 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/devm7mdibrahim/data/remote/utils/NetworkConstants.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.data.remote.utils
2 |
3 | object NetworkConstants {
4 | const val LANGUAGE = "lang"
5 | const val BEARER = "Bearer "
6 | const val AUTHORIZATION = "Authorization"
7 | const val NETWORK_TIMEOUT = 60000L
8 | const val API_VERSION = "/api/"
9 |
10 | object Languages {
11 | const val ARABIC = "ar"
12 | const val ENGLISH = "en"
13 | }
14 |
15 | object RequestKeys{
16 | const val SUCCESS = "success"
17 | const val FAIL = "fail"
18 | const val NEED_ACTIVE = "needActive"
19 | const val UN_AUTH = "unauthenticated"
20 | const val BLOCKED = "blocked"
21 | const val EXCEPTION = "exception"
22 | }
23 |
24 | object FailRequestCode {
25 | const val FAIL = 400
26 | const val UN_AUTH = 401
27 | const val BLOCKED = 423
28 | const val EXCEPTION = 500
29 | }
30 |
31 | object NetworkParams {
32 | const val PHONE = "phone"
33 | const val PASSWORD = "password"
34 | const val DEVICE_ID = "device_id"
35 | const val DEVICE_TYPE = "device_type"
36 | const val TYPE_ANDROID = "android"
37 | const val EMAIL = "email"
38 | const val MSG = "message"
39 | const val NAME = "name"
40 | const val AVATAR = "avatar"
41 | const val CODE = "code"
42 | const val LAT = "lat"
43 | const val LNG = "long"
44 | const val ADDRESS = "address"
45 | const val PAGE = "page"
46 | }
47 |
48 | object EndPoints {
49 | const val LOGIN = "login"
50 | const val REGISTER = "register"
51 | const val ROOMS = "rooms"
52 | const val CONVERSATION = "conversation"
53 | const val ROOM_ID = "room_id"
54 | }
55 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/devm7mdibrahim/data/remote/utils/SafeApiCall.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.data.remote.utils
2 |
3 | import com.devm7mdibrahim.data.remote.utils.NetworkConstants.FailRequestCode.BLOCKED
4 | import com.devm7mdibrahim.data.remote.utils.NetworkConstants.FailRequestCode.EXCEPTION
5 | import com.devm7mdibrahim.data.remote.utils.NetworkConstants.FailRequestCode.FAIL
6 | import com.devm7mdibrahim.data.remote.utils.NetworkConstants.FailRequestCode.UN_AUTH
7 | import com.devm7mdibrahim.data.remote.utils.NetworkConstants.NETWORK_TIMEOUT
8 | import com.devm7mdibrahim.domain.entities.BaseResponse
9 | import com.devm7mdibrahim.domain.exceptions.NetworkExceptions
10 | import com.devm7mdibrahim.domain.util.DataState
11 | import com.google.gson.Gson
12 | import kotlinx.coroutines.Dispatchers
13 | import kotlinx.coroutines.TimeoutCancellationException
14 | import kotlinx.coroutines.flow.*
15 | import kotlinx.coroutines.withTimeout
16 | import retrofit2.HttpException
17 | import java.io.IOException
18 | import java.net.UnknownHostException
19 |
20 | suspend fun safeApiCall(
21 | apiCall: suspend () -> T
22 | ): Flow> = flow {
23 | withTimeout(NETWORK_TIMEOUT) {
24 | val response = apiCall.invoke()
25 | emit(handleSuccess(response))
26 | }
27 | }.onStart {
28 | emit(DataState.Loading)
29 | }.catch {
30 | emit(handleError(it))
31 | }.flowOn(Dispatchers.IO)
32 |
33 | fun handleSuccess(response: T): DataState {
34 | return if (response != null) {
35 | DataState.Success(response)
36 | } else {
37 | DataState.Error(NetworkExceptions.UnknownException)
38 | }
39 | }
40 |
41 | fun handleError(it: Throwable): DataState {
42 | it.printStackTrace()
43 | return when (it) {
44 | is TimeoutCancellationException -> {
45 | DataState.Error(NetworkExceptions.TimeoutException)
46 | }
47 |
48 | is UnknownHostException -> {
49 | DataState.Error(NetworkExceptions.ConnectionException)
50 | }
51 |
52 | is IOException -> {
53 | DataState.Error(NetworkExceptions.UnknownException)
54 | }
55 |
56 | is HttpException -> {
57 | DataState.Error(convertErrorBody(it))
58 | }
59 |
60 | else -> {
61 | DataState.Error(NetworkExceptions.UnknownException)
62 | }
63 | }
64 | }
65 |
66 | private fun convertErrorBody(throwable: HttpException): Exception {
67 | val errorBody = throwable.response()?.errorBody()?.charStream()
68 | val response = Gson().fromJson(errorBody, BaseResponse::class.java)
69 | return when (throwable.code()) {
70 | FAIL -> NetworkExceptions.CustomException(response.msg)
71 | UN_AUTH, BLOCKED -> NetworkExceptions.AuthorizationException
72 | EXCEPTION -> NetworkExceptions.ServerException
73 | else -> NetworkExceptions.UnknownException
74 | }
75 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/devm7mdibrahim/data/repository/AuthRepositoryImpl.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.data.repository
2 |
3 | import com.devm7mdibrahim.data.datasource.AuthDataSource
4 | import com.devm7mdibrahim.data.remote.utils.safeApiCall
5 | import com.devm7mdibrahim.domain.entities.AuthData
6 | import com.devm7mdibrahim.domain.entities.BaseResponse
7 | import com.devm7mdibrahim.domain.repository.AuthRepository
8 | import com.devm7mdibrahim.domain.util.DataState
9 | import kotlinx.coroutines.flow.Flow
10 | import kotlinx.coroutines.flow.flow
11 | import javax.inject.Inject
12 |
13 | class AuthRepositoryImpl @Inject constructor(private val authDataSource: AuthDataSource) :
14 | AuthRepository {
15 | override suspend fun login(
16 | phone: String,
17 | password: String,
18 | deviceId: String
19 | ): Flow>> = safeApiCall {
20 | authDataSource.login(
21 | phone = phone,
22 | password = password,
23 | deviceId = deviceId
24 | )
25 | }
26 |
27 | override suspend fun register(
28 | name: String,
29 | phone: String,
30 | email: String,
31 | password: String,
32 | avatar: String?
33 | ): Flow>> = safeApiCall {
34 | authDataSource.register(
35 | name = name,
36 | phone = phone,
37 | email = email,
38 | password = password,
39 | avatar = avatar
40 | )
41 | }
42 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/devm7mdibrahim/data/repository/ChatRepositoryImpl.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.data.repository
2 |
3 | import com.devm7mdibrahim.data.datasource.ChatDataSource
4 | import com.devm7mdibrahim.data.datasource.SocketDataSource
5 | import com.devm7mdibrahim.data.remote.utils.safeApiCall
6 | import com.devm7mdibrahim.domain.entities.BaseResponse
7 | import com.devm7mdibrahim.domain.entities.ChatResponse
8 | import com.devm7mdibrahim.domain.entities.RoomsResponse
9 | import com.devm7mdibrahim.domain.repository.ChatRepository
10 | import com.devm7mdibrahim.domain.util.DataState
11 | import kotlinx.coroutines.flow.Flow
12 | import kotlinx.coroutines.flow.collect
13 | import kotlinx.coroutines.flow.emitAll
14 | import kotlinx.coroutines.flow.flow
15 | import org.json.JSONObject
16 | import javax.inject.Inject
17 |
18 | class ChatRepositoryImpl @Inject constructor(
19 | private val chatDataSource: ChatDataSource,
20 | private val socketDataSource: SocketDataSource
21 | ) : ChatRepository {
22 |
23 | override suspend fun getRooms(): Flow>> = safeApiCall {
24 | chatDataSource.getRooms()
25 | }
26 |
27 | override suspend fun getChatMessages(roomId: Int): Flow>> =
28 | safeApiCall {
29 | chatDataSource.getChatMessages(roomId)
30 | }
31 |
32 |
33 | override fun connectSocket(): Flow = flow {
34 | socketDataSource.connectSocket().collect {
35 | emit(it)
36 | }
37 | }
38 |
39 | override fun disconnectSocket() = socketDataSource.disconnectSocket()
40 |
41 | override suspend fun addUser(key: String, jsonObject: JSONObject) {
42 | socketDataSource.setEmit(key, jsonObject)
43 | }
44 |
45 | override suspend fun exitChat(key: String, jsonObject: JSONObject) {
46 | socketDataSource.setEmit(key, jsonObject)
47 | }
48 |
49 | override suspend fun sendMessage(key: String, jsonObject: JSONObject) {
50 | socketDataSource.setEmit(key, jsonObject)
51 | }
52 |
53 | override suspend fun onMessageReceived(key: String): Flow> = flow {
54 | emitAll(socketDataSource.openChannel(key))
55 | }
56 |
57 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/devm7mdibrahim/data/repository/HomeRepositoryImpl.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.data.repository
2 |
3 | import com.devm7mdibrahim.data.datasource.HomeDataSource
4 | import com.devm7mdibrahim.domain.repository.HomeRepository
5 | import javax.inject.Inject
6 |
7 | class HomeRepositoryImpl @Inject constructor(private val homeDataSource: HomeDataSource) :
8 | HomeRepository {
9 |
10 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/devm7mdibrahim/data/socket/datasource/SocketDataSourceImpl.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.data.socket.datasource
2 |
3 | import com.devm7mdibrahim.data.datasource.SocketDataSource
4 | import io.socket.client.Socket
5 | import kotlinx.coroutines.GlobalScope
6 | import kotlinx.coroutines.flow.Flow
7 | import kotlinx.coroutines.flow.MutableStateFlow
8 | import kotlinx.coroutines.flow.collect
9 | import kotlinx.coroutines.flow.flow
10 | import kotlinx.coroutines.launch
11 | import org.json.JSONObject
12 | import javax.inject.Inject
13 |
14 | class SocketDataSourceImpl @Inject constructor(
15 | private val socket: Socket
16 | ) : SocketDataSource {
17 |
18 | private val connectFlow = MutableStateFlow(false)
19 | private val messagesFlow = MutableStateFlow(emptyList())
20 |
21 | override fun connectSocket(): Flow = flow {
22 | if (!socket.connected()) {
23 | socket.connect()
24 |
25 | socket.on(Socket.EVENT_CONNECT) {
26 | GlobalScope.launch { connectFlow.emit(true) }
27 | socket.off(Socket.EVENT_CONNECT)
28 | }
29 |
30 | socket.on(Socket.EVENT_CONNECT_ERROR) { connectSocket() }
31 |
32 | } else {
33 | GlobalScope.launch { connectFlow.emit(true) }
34 | }
35 |
36 | connectFlow.collect {
37 | emit(it)
38 | }
39 | }
40 |
41 | override fun disconnectSocket() {
42 | if (socket.connected()) {
43 | socket.disconnect()
44 | }
45 |
46 | GlobalScope.launch { messagesFlow.emit(emptyList()) }
47 | }
48 |
49 | override fun openChannel(
50 | channel: String
51 | ): Flow> = flow {
52 | socket.off()
53 | socket.on(channel) {
54 | GlobalScope.launch {
55 | it.map { it.toString() }.let { messages ->
56 | messagesFlow.emit(messages)
57 | }
58 | }
59 | }
60 |
61 | messagesFlow.collect {
62 | emit(it)
63 | }
64 | }
65 |
66 | override fun setEmit(
67 | emitType: String,
68 | jsonObject: JSONObject?
69 | ) {
70 | if (socket.connected()) {
71 | socket.emit(emitType, jsonObject)
72 | } else {
73 | GlobalScope.launch {
74 | connectSocket().collect {
75 | if (it) {
76 | socket.emit(emitType, jsonObject)
77 | }
78 | }
79 | }
80 | }
81 | }
82 | }
--------------------------------------------------------------------------------
/data/src/main/java/com/devm7mdibrahim/data/utils/MultiPartUtil.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.data.utils
2 |
3 | import okhttp3.MediaType
4 | import okhttp3.MultipartBody
5 | import okhttp3.RequestBody
6 | import java.io.File
7 |
8 | object MultiPartUtil {
9 |
10 | fun String.toMultiPart(): RequestBody {
11 | return RequestBody.create(
12 | MediaType.parse("text/plain"),
13 | this
14 | )
15 | }
16 |
17 | fun prepareImagePart(
18 | partName: String,
19 | path: String
20 | ): MultipartBody.Part {
21 | val file = File(path)
22 | val requestFile = RequestBody.create(
23 | MediaType.parse("image/*"),
24 | file
25 | )
26 | return MultipartBody.Part.createFormData(partName, partName, requestFile)
27 | }
28 |
29 | fun preparePDFPart(
30 | partName: String,
31 | path: String
32 | ): MultipartBody.Part {
33 | val file = File(path)
34 | val requestFile = RequestBody.create(
35 | MediaType.parse("pdf/*"),
36 | file
37 | )
38 | return MultipartBody.Part.createFormData(partName, partName, requestFile)
39 | }
40 |
41 | fun prepareAudioPart(
42 | partName: String,
43 | path: String
44 | ): MultipartBody.Part {
45 | val file = File(path)
46 | val requestFile = RequestBody.create(
47 | MediaType.parse("audio/*"),
48 | file
49 | )
50 | return MultipartBody.Part.createFormData(partName, partName, requestFile)
51 | }
52 |
53 |
54 | fun prepareVideoPart(
55 | partName: String,
56 | path: String
57 | ): MultipartBody.Part {
58 | val file = File(path)
59 | val requestFile = RequestBody.create(
60 | MediaType.parse("video/*"),
61 | file
62 | )
63 | return MultipartBody.Part.createFormData(partName, partName, requestFile)
64 | }
65 | }
--------------------------------------------------------------------------------
/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_8
8 | targetCompatibility = JavaVersion.VERSION_1_8
9 | }
10 |
11 | dependencies {
12 | implementation Dependencies.javaxAnnotation
13 | implementation Dependencies.javaxInject
14 |
15 | implementation Dependencies.coroutine
16 | implementation Dependencies.coroutine_android
17 |
18 | implementation Dependencies.moshi_kotlin
19 | api Dependencies.json_org
20 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/devm7mdibrahim/domain/entities/AuthData.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.domain.entities
2 |
3 | data class AuthData(
4 | val token: String,
5 | val user: UserData
6 | )
7 |
8 | data class UserData(
9 | val name: String,
10 | val phone: String,
11 | val email: String
12 | )
13 |
--------------------------------------------------------------------------------
/domain/src/main/java/com/devm7mdibrahim/domain/entities/BaseResponse.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.domain.entities
2 |
3 | import com.squareup.moshi.Json
4 | import com.squareup.moshi.JsonClass
5 | import java.io.Serializable
6 |
7 | @JsonClass(generateAdapter = true)
8 | data class BaseResponse(
9 | @Json(name = "key") val key: String,
10 | @Json(name = "data") val data: T?,
11 | @Json(name = "msg") val msg: String,
12 | @Json(name = "code") val code: Int,
13 | ) : Serializable
--------------------------------------------------------------------------------
/domain/src/main/java/com/devm7mdibrahim/domain/entities/ChatResponse.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.domain.entities
2 |
3 | data class ChatResponse(
4 | val messages: List
5 | )
--------------------------------------------------------------------------------
/domain/src/main/java/com/devm7mdibrahim/domain/entities/MessagesItem.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.domain.entities
2 |
3 | import com.squareup.moshi.Json
4 |
5 | data class MessagesItem(
6 | @Json(name = "sender_type") val senderType: String
7 | )
8 |
9 |
--------------------------------------------------------------------------------
/domain/src/main/java/com/devm7mdibrahim/domain/entities/Pagination.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.domain.entities
2 |
3 | import com.squareup.moshi.Json
4 |
5 | data class Pagination(
6 | @Json(name = "total") val total: Int = 0,
7 | @Json(name = "count") val count: Int = 0,
8 | @Json(name = "per_page") val perPage: Int = 0,
9 | @Json(name = "next_page_url") val nextPageUrl: String = "",
10 | @Json(name = "perv_page_url") val pervPageUrl: String = "",
11 | @Json(name = "current_page") val currentPage: Int = 0,
12 | @Json(name = "total_pages") val totalPages: Int = 0
13 | )
--------------------------------------------------------------------------------
/domain/src/main/java/com/devm7mdibrahim/domain/entities/RoomsItem.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.domain.entities
2 |
3 | data class RoomsItem(
4 | val id: Int
5 | )
--------------------------------------------------------------------------------
/domain/src/main/java/com/devm7mdibrahim/domain/entities/RoomsResponse.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.domain.entities
2 |
3 | data class RoomsResponse (
4 | val rooms: List
5 | )
--------------------------------------------------------------------------------
/domain/src/main/java/com/devm7mdibrahim/domain/exceptions/LocalExceptions.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.domain.exceptions
2 |
3 | sealed class LocalExceptions : Exception() {
4 | object UnknownException : LocalExceptions()
5 | object TimeoutException : LocalExceptions()
6 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/devm7mdibrahim/domain/exceptions/NetworkExceptions.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.domain.exceptions
2 |
3 | sealed class NetworkExceptions : Exception() {
4 | object UnknownException : NetworkExceptions()
5 | object ServerException : NetworkExceptions()
6 | object NotFoundException : NetworkExceptions()
7 | object TimeoutException : NetworkExceptions()
8 | object ConnectionException : NetworkExceptions()
9 | object AuthorizationException : NetworkExceptions()
10 | data class CustomException(val msg: String) : NetworkExceptions()
11 | data class NeedActiveException(val msg: String) : NetworkExceptions()
12 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/devm7mdibrahim/domain/exceptions/ValidationException.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.domain.exceptions
2 |
3 | sealed class ValidationException: Exception(){
4 | object InValidPhoneException : ValidationException()
5 | object InValidNameException : ValidationException()
6 | object InValidPriceException : ValidationException()
7 | object InValidTextException : ValidationException()
8 | object InValidPasswordException : ValidationException()
9 | object InValidConfirmationPasswordException : ValidationException()
10 | object InValidEmailAddressException : ValidationException()
11 | object InValidCountryIsoException : ValidationException()
12 | object InValidDeviceIdException : ValidationException()
13 | object InValidVerificationCodeException : ValidationException()
14 | }
15 |
--------------------------------------------------------------------------------
/domain/src/main/java/com/devm7mdibrahim/domain/repository/AuthRepository.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.domain.repository
2 |
3 | import com.devm7mdibrahim.domain.entities.AuthData
4 | import com.devm7mdibrahim.domain.entities.BaseResponse
5 | import com.devm7mdibrahim.domain.util.DataState
6 | import kotlinx.coroutines.flow.Flow
7 |
8 | interface AuthRepository {
9 |
10 | suspend fun login(
11 | phone: String,
12 | password: String,
13 | deviceId: String
14 | ): Flow>>
15 |
16 | suspend fun register(
17 | name: String,
18 | phone: String,
19 | email: String,
20 | password: String,
21 | avatar: String?
22 | ): Flow>>
23 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/devm7mdibrahim/domain/repository/ChatRepository.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.domain.repository
2 |
3 | import com.devm7mdibrahim.domain.entities.BaseResponse
4 | import com.devm7mdibrahim.domain.entities.ChatResponse
5 | import com.devm7mdibrahim.domain.entities.RoomsResponse
6 | import com.devm7mdibrahim.domain.util.DataState
7 | import kotlinx.coroutines.flow.Flow
8 | import org.json.JSONObject
9 |
10 | interface ChatRepository {
11 |
12 | suspend fun getRooms(): Flow>>
13 | suspend fun getChatMessages(roomId: Int): Flow>>
14 |
15 | fun connectSocket(): Flow
16 | fun disconnectSocket()
17 |
18 | suspend fun addUser(key: String, jsonObject: JSONObject)
19 | suspend fun exitChat(key: String, jsonObject: JSONObject)
20 |
21 | suspend fun sendMessage(key: String, jsonObject: JSONObject)
22 | suspend fun onMessageReceived(key: String): Flow>
23 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/devm7mdibrahim/domain/repository/HomeRepository.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.domain.repository
2 |
3 | interface HomeRepository {
4 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/devm7mdibrahim/domain/repository/PreferenceRepository.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.domain.repository
2 |
3 | import kotlinx.coroutines.flow.Flow
4 |
5 | interface PreferenceRepository {
6 | suspend fun getLanguage(): Flow
7 | suspend fun setLanguage(lang: String)
8 |
9 | suspend fun getIsArabicLanguage(): Flow
10 |
11 | suspend fun getToken():Flow
12 | suspend fun setToken(mToken: String)
13 |
14 | suspend fun getUserData(): Flow
15 | suspend fun setUserData(userData: String)
16 |
17 | suspend fun getFirebaseToken(): Flow
18 | suspend fun setFirebaseToken(token: String)
19 |
20 | suspend fun getAddress(): Flow
21 | suspend fun setAddress(address: String)
22 |
23 | suspend fun getLatitude(): Flow
24 | suspend fun setLatitude(latitude: Double)
25 |
26 | suspend fun getLongitude(): Flow
27 | suspend fun setLongitude(longitude: Double)
28 |
29 | suspend fun getIsActivated(): Flow
30 | suspend fun setIsActivated(active: Boolean)
31 |
32 | suspend fun getIsProfileCompleted(): Flow
33 | suspend fun setIsProfileCompleted(completed: Boolean)
34 |
35 | suspend fun getIsFirstTime(): Flow
36 | suspend fun setIsFirstTime(firstTime: Boolean)
37 |
38 | suspend fun onLogout()
39 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/devm7mdibrahim/domain/usecases/LoginUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.domain.usecases
2 |
3 | import com.devm7mdibrahim.domain.entities.AuthData
4 | import com.devm7mdibrahim.domain.entities.BaseResponse
5 | import com.devm7mdibrahim.domain.exceptions.ValidationException
6 | import com.devm7mdibrahim.domain.repository.AuthRepository
7 | import com.devm7mdibrahim.domain.util.CommonValidation.isValidPassword
8 | import com.devm7mdibrahim.domain.util.CommonValidation.isValidPhone
9 | import com.devm7mdibrahim.domain.util.DataState
10 | import kotlinx.coroutines.flow.Flow
11 | import kotlinx.coroutines.flow.emitAll
12 | import kotlinx.coroutines.flow.flow
13 | import javax.inject.Inject
14 |
15 | class LoginUseCase @Inject constructor(
16 | private val authRepository: AuthRepository
17 | ) {
18 | suspend operator fun invoke(
19 | phone: String,
20 | password: String,
21 | deviceId: String
22 | ): Flow>> = flow {
23 | when {
24 | !phone.isValidPhone() -> emit(DataState.Error(ValidationException.InValidPhoneException))
25 | !password.isValidPassword() -> emit(DataState.Error(ValidationException.InValidPasswordException))
26 | else -> emitAll(
27 | authRepository.login(
28 | phone = phone,
29 | password = password,
30 | deviceId = deviceId
31 | )
32 | )
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/devm7mdibrahim/domain/usecases/RegisterUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.domain.usecases
2 |
3 | import com.devm7mdibrahim.domain.entities.AuthData
4 | import com.devm7mdibrahim.domain.entities.BaseResponse
5 | import com.devm7mdibrahim.domain.exceptions.ValidationException
6 | import com.devm7mdibrahim.domain.repository.AuthRepository
7 | import com.devm7mdibrahim.domain.util.CommonValidation.isValidName
8 | import com.devm7mdibrahim.domain.util.CommonValidation.isValidPassword
9 | import com.devm7mdibrahim.domain.util.CommonValidation.isValidPhone
10 | import com.devm7mdibrahim.domain.util.DataState
11 | import kotlinx.coroutines.flow.Flow
12 | import kotlinx.coroutines.flow.emitAll
13 | import kotlinx.coroutines.flow.flow
14 | import javax.inject.Inject
15 |
16 | class RegisterUseCase @Inject constructor(
17 | private val authRepository: AuthRepository
18 | ) {
19 | suspend operator fun invoke(
20 | name: String,
21 | phone: String,
22 | email: String,
23 | password: String,
24 | avatar: String?
25 | ): Flow>> = flow {
26 | when {
27 | !name.isValidName() -> emit(DataState.Error(ValidationException.InValidNameException))
28 | !phone.isValidPhone() -> emit(DataState.Error(ValidationException.InValidPhoneException))
29 | !email.isValidPhone() -> emit(DataState.Error(ValidationException.InValidEmailAddressException))
30 | !password.isValidPassword() -> emit(DataState.Error(ValidationException.InValidPasswordException))
31 | else -> emitAll(
32 | authRepository.register(
33 | name = name,
34 | phone = phone,
35 | email = email,
36 | password = password,
37 | avatar = avatar
38 | )
39 | )
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/devm7mdibrahim/domain/util/CommonValidation.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.domain.util
2 |
3 | import java.util.regex.Pattern
4 |
5 | object CommonValidation {
6 |
7 | fun String?.isValidPhone(): Boolean {
8 | return this?.isNotEmpty() == true && this.length >= 9
9 | }
10 |
11 | fun String?.isValidName(): Boolean {
12 | return this?.isNotEmpty() == true && this.length >= 3
13 | }
14 |
15 | fun String?.isValidText(): Boolean {
16 | return this?.isNotEmpty() == true && this.length >= 3
17 | }
18 |
19 | fun String?.isValidPassword(): Boolean {
20 | return this?.isNotEmpty() == true && this.length >= 6
21 | }
22 |
23 | fun String?.isValidPrice(): Boolean {
24 | return this?.isNotEmpty() == true
25 | }
26 |
27 | fun String?.isValidConfirmPassword(password: String): Boolean {
28 | return this?.isNotEmpty() == true && this == password
29 | }
30 |
31 | fun String?.isValidEmailAddress(): Boolean {
32 | val regex: Pattern = Pattern.compile(
33 | "[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?",
34 | Pattern.CASE_INSENSITIVE
35 | )
36 | return regex.matcher(this.toString()).matches()
37 | }
38 |
39 | fun String?.isValidCountryIso(): Boolean {
40 | return !this.isNullOrEmpty()
41 | }
42 |
43 | fun String?.isValidDeviceId(): Boolean {
44 | return !this.isNullOrEmpty()
45 | }
46 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/devm7mdibrahim/domain/util/Constants.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.domain.util
2 |
3 | object Constants {
4 | const val SUCCESS = "success"
5 | const val FAIL = "fail"
6 | const val ACTIVE = "active"
7 | const val BLOCK = "block"
8 | const val PENDING = "pending"
9 |
10 | const val SUCCESS_CODE = 200
11 | const val FAIL_CODE = 401
12 | const val UNAUTHORIZED_CODE = 419
13 | }
--------------------------------------------------------------------------------
/domain/src/main/java/com/devm7mdibrahim/domain/util/DataState.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.domain.util
2 |
3 | sealed class DataState {
4 | data class Success(val data: T) : DataState()
5 | data class Error(val throwable: Throwable) : DataState()
6 | object Loading : DataState()
7 | object Idle : DataState()
8 | }
--------------------------------------------------------------------------------
/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 | android.enableJetifier=true
19 | android.useNewApkCreator=true
20 | # Kotlin code style for this project: "official" or "obsolete":
21 | kotlin.code.style=official
22 | # Enables namespacing of each library's R class so that its R class includes only the
23 | # resources declared in the library itself and none from the library's dependencies,
24 | # thereby reducing the size of the R class for that library
25 | android.nonTransitiveRClass=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Jan 31 12:59:52 EET 2022
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-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 |
--------------------------------------------------------------------------------
/presentation/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/presentation/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'org.jetbrains.kotlin.android'
4 | id 'kotlin-kapt'
5 | id 'dagger.hilt.android.plugin'
6 | id 'androidx.navigation.safeargs.kotlin'
7 | }
8 |
9 | android {
10 | compileSdk 31
11 |
12 | defaultConfig {
13 | minSdk 21
14 | targetSdk 31
15 |
16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
17 | }
18 |
19 | buildTypes {
20 | release {
21 | minifyEnabled false
22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
23 | }
24 | }
25 | compileOptions {
26 | sourceCompatibility JavaVersion.VERSION_1_8
27 | targetCompatibility JavaVersion.VERSION_1_8
28 | }
29 | kotlinOptions {
30 | jvmTarget = '1.8'
31 | }
32 |
33 | buildFeatures {
34 | viewBinding true
35 | }
36 | }
37 |
38 | dependencies {
39 |
40 | implementation project(':domain')
41 | implementation project(':utils')
42 |
43 | implementation 'androidx.legacy:legacy-support-v4:1.0.0'
44 | implementation 'androidx.core:core-ktx:1.7.0'
45 | implementation 'androidx.appcompat:appcompat:1.4.1'
46 | implementation 'com.google.android.material:material:1.5.0'
47 | implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
48 |
49 | api Dependencies.navigation_fragment
50 | api Dependencies.navigation_ui
51 |
52 | api 'com.akexorcist:localization:1.2.10'
53 | implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.4.1'
54 | implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1'
55 | implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1'
56 |
57 | implementation Compilers.hilt_android
58 | kapt Compilers.hilt_android_compiler
59 | kapt Compilers.hilt_android_lifecycle_compiler
60 | }
--------------------------------------------------------------------------------
/presentation/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/presentation/consumer-rules.pro
--------------------------------------------------------------------------------
/presentation/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
--------------------------------------------------------------------------------
/presentation/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/presentation/src/main/java/com/devm7mdibrahim/presentation/base/BaseActivity.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.presentation.base
2 |
3 | import com.akexorcist.localizationactivity.ui.LocalizationActivity
4 |
5 | abstract class BaseActivity : LocalizationActivity() {
6 |
7 | override fun onSupportNavigateUp(): Boolean {
8 | onBackPressed()
9 | return true
10 | }
11 | }
--------------------------------------------------------------------------------
/presentation/src/main/java/com/devm7mdibrahim/presentation/base/BaseBottomSheetFragment.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.presentation.base
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import androidx.viewbinding.ViewBinding
8 | import com.devm7mdibrahim.domain.entities.BaseResponse
9 | import com.devm7mdibrahim.domain.exceptions.NetworkExceptions
10 | import com.devm7mdibrahim.domain.util.DataState
11 | import com.devm7mdibrahim.presentation.utils.getIsCommonException
12 | import com.devm7mdibrahim.utils.common.ProgressUtil
13 | import com.devm7mdibrahim.utils.extensions.ToastType
14 | import com.devm7mdibrahim.utils.extensions.showToast
15 | import com.google.android.material.bottomsheet.BottomSheetDialogFragment
16 | import javax.inject.Inject
17 |
18 | abstract class BaseBottomSheetFragment(private val inflate: Inflate) :
19 | BottomSheetDialogFragment() {
20 |
21 | @Inject
22 | lateinit var progressUtil: ProgressUtil
23 |
24 | abstract val viewModel: BaseViewModel
25 |
26 | private var _binding: VB? = null
27 | val binding get() = _binding!!
28 |
29 | override fun onCreate(savedInstanceState: Bundle?) {
30 | super.onCreate(savedInstanceState)
31 | setStyle(STYLE_NORMAL, com.devm7mdibrahim.utils.R.style.bottomSheetDialogStyle)
32 | startObserver()
33 | }
34 |
35 | override fun onCreateView(
36 | inflater: LayoutInflater,
37 | container: ViewGroup?,
38 | savedInstanceState: Bundle?
39 | ): View? {
40 | if (_binding == null) {
41 | _binding = inflate.invoke(inflater, container, false)
42 | onCreateBinding()
43 | }
44 |
45 | handleClicks()
46 | return binding.root
47 | }
48 |
49 | open fun onCreateBinding() {}
50 |
51 | open fun handleClicks() {}
52 |
53 | open fun startObserver() {}
54 |
55 | override fun onDestroyView() {
56 | super.onDestroyView()
57 | _binding = null
58 | }
59 |
60 | protected fun DataState.applyCommonSideEffects(
61 | showLoading: Boolean = true,
62 | showSuccessToast: Boolean = true,
63 | onSuccess: (T) -> Unit = {}
64 | ) {
65 | when (this) {
66 | is DataState.Loading -> {
67 | if (showLoading) progressUtil.showProgress()
68 | }
69 |
70 | is DataState.Success -> {
71 | if (showSuccessToast) requireContext().showToast(
72 | (data as BaseResponse<*>).msg,
73 | ToastType.SUCCESS
74 | )
75 | onSuccess(this.data)
76 | }
77 |
78 | is DataState.Error -> {
79 | progressUtil.hideProgress()
80 | handleError(throwable)
81 | }
82 |
83 | DataState.Idle -> {
84 | progressUtil.hideProgress()
85 | }
86 | }
87 | }
88 |
89 | private fun handleError(throwable: Throwable) {
90 | when (throwable) {
91 | is NetworkExceptions.CustomException -> {
92 | requireContext().showToast(throwable.msg)
93 | }
94 |
95 | else -> {
96 | requireContext().showToast(getString(throwable.getIsCommonException()))
97 | }
98 | }
99 | }
100 | }
--------------------------------------------------------------------------------
/presentation/src/main/java/com/devm7mdibrahim/presentation/base/BaseDialogFragment.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.presentation.base
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.DialogFragment
8 | import androidx.viewbinding.ViewBinding
9 | import com.devm7mdibrahim.domain.entities.BaseResponse
10 | import com.devm7mdibrahim.domain.exceptions.NetworkExceptions
11 | import com.devm7mdibrahim.domain.util.DataState
12 | import com.devm7mdibrahim.presentation.utils.getIsCommonException
13 | import com.devm7mdibrahim.utils.common.ProgressUtil
14 | import com.devm7mdibrahim.utils.extensions.ToastType
15 | import com.devm7mdibrahim.utils.extensions.showToast
16 | import javax.inject.Inject
17 |
18 | abstract class BaseDialogFragment(private val inflate: Inflate) :
19 | DialogFragment() {
20 |
21 | private var _binding: VB? = null
22 | val binding get() = _binding!!
23 |
24 | @Inject
25 | lateinit var progressUtil: ProgressUtil
26 |
27 | abstract val viewModel: BaseViewModel
28 |
29 | override fun onCreateView(
30 | inflater: LayoutInflater,
31 | container: ViewGroup?,
32 | savedInstanceState: Bundle?
33 | ): View? {
34 | if (_binding == null) {
35 | _binding = inflate.invoke(inflater, container, false)
36 | onCreateView()
37 | }
38 |
39 | return binding.root
40 | }
41 |
42 | override fun onCreate(savedInstanceState: Bundle?) {
43 | super.onCreate(savedInstanceState)
44 | startObserver()
45 | }
46 |
47 | open fun startObserver() {
48 |
49 | }
50 |
51 | open fun onCreateView() {
52 |
53 | }
54 |
55 | protected fun DataState.applyCommonSideEffects(
56 | showLoading: Boolean = true,
57 | showSuccessToast: Boolean = true,
58 | onSuccess: (T) -> Unit = {}
59 | ) {
60 | when (this) {
61 | is DataState.Loading -> {
62 | if (showLoading) progressUtil.showProgress()
63 | }
64 |
65 | is DataState.Success -> {
66 | if (showSuccessToast) requireContext().showToast(
67 | (data as BaseResponse<*>).msg,
68 | ToastType.SUCCESS
69 | )
70 | onSuccess(this.data)
71 | }
72 |
73 | is DataState.Error -> {
74 | progressUtil.hideProgress()
75 | handleError(throwable)
76 | }
77 |
78 | DataState.Idle -> {
79 | progressUtil.hideProgress()
80 | }
81 | }
82 | }
83 |
84 | private fun handleError(throwable: Throwable) {
85 | when (throwable) {
86 | is NetworkExceptions.CustomException -> {
87 | requireContext().showToast(throwable.msg)
88 | }
89 |
90 | else -> {
91 | requireContext().showToast(getString(throwable.getIsCommonException()))
92 | }
93 | }
94 | }
95 |
96 | override fun onDestroyView() {
97 | super.onDestroyView()
98 | _binding = null
99 | }
100 | }
--------------------------------------------------------------------------------
/presentation/src/main/java/com/devm7mdibrahim/presentation/base/BaseRecyclerAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.presentation.base
2 |
3 | import androidx.recyclerview.widget.DiffUtil
4 | import androidx.recyclerview.widget.ListAdapter
5 | import androidx.viewbinding.ViewBinding
6 |
7 | abstract class BaseRecyclerAdapter>
8 | (callback: DiffUtil.ItemCallback) :
9 | ListAdapter(callback) {
10 |
11 | override fun onBindViewHolder(holder: VIEW_HOLDER, position: Int) {
12 | holder.doBindings((getItem(position)))
13 | holder.bind()
14 | }
15 |
16 | override fun submitList(items: List?) {
17 | super.submitList(items ?: emptyList())
18 | }
19 | }
--------------------------------------------------------------------------------
/presentation/src/main/java/com/devm7mdibrahim/presentation/base/BaseViewHolder.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.presentation.base
2 |
3 | import androidx.recyclerview.widget.RecyclerView
4 | import androidx.viewbinding.ViewBinding
5 |
6 | abstract class BaseViewHolder constructor(viewBinding: VIEW_BINDING) :
7 | RecyclerView.ViewHolder(viewBinding.root) {
8 |
9 | private var item: MODEL? = null
10 |
11 | fun doBindings(data: MODEL?) {
12 | this.item = data
13 | }
14 |
15 | abstract fun bind()
16 |
17 | fun getRowItem(): MODEL? {
18 | return item
19 | }
20 | }
--------------------------------------------------------------------------------
/presentation/src/main/java/com/devm7mdibrahim/presentation/base/BaseViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.presentation.base
2 |
3 | import androidx.lifecycle.ViewModel
4 | import com.devm7mdibrahim.domain.repository.PreferenceRepository
5 | import dagger.hilt.android.lifecycle.HiltViewModel
6 | import javax.inject.Inject
7 |
8 | @HiltViewModel
9 | open class BaseViewModel @Inject constructor(): ViewModel() {
10 |
11 | @Inject
12 | lateinit var preferenceRepository: PreferenceRepository
13 | }
--------------------------------------------------------------------------------
/presentation/src/main/java/com/devm7mdibrahim/presentation/cycles/auth_cycle/activity/AuthActivity.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.presentation.cycles.auth_cycle.activity
2 |
3 | import android.os.Bundle
4 | import com.devm7mdibrahim.presentation.R
5 | import com.devm7mdibrahim.presentation.base.BaseActivity
6 | import dagger.hilt.android.AndroidEntryPoint
7 |
8 | @AndroidEntryPoint
9 | class AuthActivity : BaseActivity() {
10 | override fun onCreate(savedInstanceState: Bundle?) {
11 | super.onCreate(savedInstanceState)
12 | setContentView(R.layout.activity_auth)
13 | }
14 | }
--------------------------------------------------------------------------------
/presentation/src/main/java/com/devm7mdibrahim/presentation/cycles/auth_cycle/fragment/login/LoginFragment.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.presentation.cycles.auth_cycle.fragment.login
2 |
3 | import androidx.fragment.app.viewModels
4 | import androidx.lifecycle.lifecycleScope
5 | import com.devm7mdibrahim.domain.entities.AuthData
6 | import com.devm7mdibrahim.domain.exceptions.ValidationException
7 | import com.devm7mdibrahim.domain.util.DataState
8 | import com.devm7mdibrahim.presentation.R
9 | import com.devm7mdibrahim.presentation.base.BaseFragment
10 | import com.devm7mdibrahim.presentation.databinding.FragmentLoginBinding
11 | import com.devm7mdibrahim.utils.extensions.*
12 | import dagger.hilt.android.AndroidEntryPoint
13 | import kotlinx.coroutines.flow.first
14 |
15 | @AndroidEntryPoint
16 | class LoginFragment : BaseFragment(FragmentLoginBinding::inflate) {
17 |
18 | override val viewModel by viewModels()
19 |
20 | override fun startObserver() {
21 | super.startObserver()
22 | loginObserver()
23 | }
24 |
25 | override fun handleClicks() {
26 | super.handleClicks()
27 |
28 | binding.btnLogin.onClick {
29 | login()
30 | }
31 | }
32 |
33 | private fun login() {
34 | lifecycleScope.launchWhenCreated {
35 | viewModel.loginResponse.emit(DataState.Idle)
36 | viewModel.login(
37 | phone = binding.etPhone.fetchText(),
38 | password = binding.etPassword.fetchText(),
39 | deviceId = viewModel.preferenceRepository.getFirebaseToken().first(),
40 | )
41 | }
42 | }
43 |
44 | private fun loginObserver() {
45 | collectLifecycleFlow(viewModel.loginResponse) {
46 | when (it) {
47 | is DataState.Error -> {
48 | when (it.throwable) {
49 | is ValidationException.InValidPhoneException -> {
50 | requireContext().showToast(getString(R.string.error_invalid_phone))
51 | }
52 | is ValidationException.InValidPasswordException -> {
53 | requireContext().showToast(getString(R.string.error_invalid_password))
54 | }
55 | else -> {
56 | it.applyCommonSideEffects()
57 | }
58 | }
59 | }
60 | else -> {
61 | it.applyCommonSideEffects { response ->
62 | response.data?.let { userData -> saveUserData(userData) }
63 | }
64 | }
65 | }
66 | }
67 | }
68 |
69 | private fun saveUserData(data: AuthData) {
70 | lifecycleScope.launchWhenCreated {
71 | viewModel.preferenceRepository.setToken(data.token)
72 | viewModel.preferenceRepository.setUserData(data.user.toJson())
73 | }
74 | }
75 | }
--------------------------------------------------------------------------------
/presentation/src/main/java/com/devm7mdibrahim/presentation/cycles/auth_cycle/fragment/login/LoginViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.presentation.cycles.auth_cycle.fragment.login
2 |
3 | import androidx.lifecycle.viewModelScope
4 | import com.devm7mdibrahim.domain.entities.AuthData
5 | import com.devm7mdibrahim.domain.entities.BaseResponse
6 | import com.devm7mdibrahim.domain.usecases.LoginUseCase
7 | import com.devm7mdibrahim.domain.util.DataState
8 | import com.devm7mdibrahim.presentation.base.BaseViewModel
9 | import dagger.hilt.android.lifecycle.HiltViewModel
10 | import kotlinx.coroutines.flow.MutableStateFlow
11 | import kotlinx.coroutines.flow.launchIn
12 | import kotlinx.coroutines.flow.onEach
13 | import kotlinx.coroutines.launch
14 | import javax.inject.Inject
15 |
16 | @HiltViewModel
17 | class LoginViewModel @Inject constructor(private val loginUseCase: LoginUseCase) : BaseViewModel() {
18 |
19 | private val _loginResponse =
20 | MutableStateFlow>>(DataState.Idle)
21 | val loginResponse: MutableStateFlow>>
22 | get() = _loginResponse
23 |
24 | fun login(phone: String, password: String, deviceId: String) {
25 | viewModelScope.launch {
26 | loginUseCase(
27 | phone = phone,
28 | password = password,
29 | deviceId = deviceId
30 | ).onEach {
31 | _loginResponse.value = it
32 | }.launchIn(viewModelScope)
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/presentation/src/main/java/com/devm7mdibrahim/presentation/cycles/auth_cycle/fragment/register/RegisterFragment.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.presentation.cycles.auth_cycle.fragment.register
2 |
3 | import androidx.fragment.app.viewModels
4 | import androidx.lifecycle.lifecycleScope
5 | import com.devm7mdibrahim.domain.exceptions.ValidationException
6 | import com.devm7mdibrahim.domain.util.DataState
7 | import com.devm7mdibrahim.presentation.R
8 | import com.devm7mdibrahim.presentation.base.BaseFragment
9 | import com.devm7mdibrahim.presentation.databinding.FragmentRegisterBinding
10 | import com.devm7mdibrahim.utils.extensions.onPrintLog
11 | import com.devm7mdibrahim.utils.extensions.showToast
12 | import dagger.hilt.android.AndroidEntryPoint
13 | import kotlinx.coroutines.flow.collect
14 |
15 | @AndroidEntryPoint
16 | class RegisterFragment : BaseFragment(FragmentRegisterBinding::inflate) {
17 |
18 | private var avatar: String? = null
19 | override val viewModel by viewModels()
20 |
21 | override fun startObserver() {
22 | super.startObserver()
23 | registerListener()
24 | }
25 |
26 | private fun register() {
27 | lifecycleScope.launchWhenCreated {
28 | viewModel.registerResponse.emit(DataState.Idle)
29 | viewModel.register(
30 | name = "Mohamed",
31 | phone = "01024510687",
32 | email = "dev.m7mdibrahim@gmail.com",
33 | password = "123456",
34 | avatar = avatar
35 | )
36 | }
37 | }
38 |
39 | private fun registerListener() {
40 | lifecycleScope.launchWhenCreated {
41 | viewModel.registerResponse.collect { it ->
42 | when (it) {
43 | is DataState.Error -> {
44 | when (it.throwable) {
45 | is ValidationException.InValidPhoneException -> {
46 | requireContext().showToast(getString(R.string.error_invalid_phone))
47 | }
48 | is ValidationException.InValidPasswordException -> {
49 | requireContext().showToast(getString(R.string.error_invalid_password))
50 | }
51 | is ValidationException.InValidNameException -> {
52 | requireContext().showToast(getString(R.string.error_invalid_name))
53 | }
54 | is ValidationException.InValidEmailAddressException -> {
55 | requireContext().showToast(getString(R.string.error_invalid_email))
56 | }
57 | else -> {
58 | it.applyCommonSideEffects()
59 | }
60 | }
61 | }
62 | else -> {
63 | it.applyCommonSideEffects {
64 | it.data?.onPrintLog("userData")
65 | }
66 | }
67 | }
68 | }
69 | }
70 | }
71 |
72 | }
--------------------------------------------------------------------------------
/presentation/src/main/java/com/devm7mdibrahim/presentation/cycles/auth_cycle/fragment/register/RegisterViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.presentation.cycles.auth_cycle.fragment.register
2 |
3 | import androidx.lifecycle.viewModelScope
4 | import com.devm7mdibrahim.domain.entities.AuthData
5 | import com.devm7mdibrahim.domain.entities.BaseResponse
6 | import com.devm7mdibrahim.domain.usecases.RegisterUseCase
7 | import com.devm7mdibrahim.domain.util.DataState
8 | import com.devm7mdibrahim.presentation.base.BaseViewModel
9 | import dagger.hilt.android.lifecycle.HiltViewModel
10 | import kotlinx.coroutines.flow.MutableStateFlow
11 | import kotlinx.coroutines.flow.launchIn
12 | import kotlinx.coroutines.flow.onEach
13 | import kotlinx.coroutines.launch
14 | import javax.inject.Inject
15 |
16 | @HiltViewModel
17 | class RegisterViewModel @Inject constructor(private val registerUseCase: RegisterUseCase) :
18 | BaseViewModel() {
19 |
20 | private val _registerResponse =
21 | MutableStateFlow>>(DataState.Idle)
22 | val registerResponse: MutableStateFlow>>
23 | get() = _registerResponse
24 |
25 | fun register(name: String, phone: String, email: String, password: String, avatar: String?) {
26 | viewModelScope.launch {
27 | registerUseCase(
28 | name = name,
29 | phone = phone,
30 | email = email,
31 | password = password,
32 | avatar = avatar
33 | ).onEach {
34 | _registerResponse.value = it
35 | }.launchIn(viewModelScope)
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/presentation/src/main/java/com/devm7mdibrahim/presentation/cycles/home_cycle/activity/HomeActivity.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.presentation.cycles.home_cycle.activity
2 |
3 | import android.os.Bundle
4 | import com.devm7mdibrahim.presentation.R
5 | import com.devm7mdibrahim.presentation.base.BaseActivity
6 | import dagger.hilt.android.AndroidEntryPoint
7 |
8 | @AndroidEntryPoint
9 | class HomeActivity : BaseActivity() {
10 | override fun onCreate(savedInstanceState: Bundle?) {
11 | super.onCreate(savedInstanceState)
12 | setContentView(R.layout.activity_home)
13 | }
14 | }
--------------------------------------------------------------------------------
/presentation/src/main/java/com/devm7mdibrahim/presentation/cycles/home_cycle/fragment/home_container/HomeContainerFragment.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.presentation.cycles.home_cycle.fragment.home_container
2 |
3 | import androidx.fragment.app.viewModels
4 | import androidx.navigation.Navigation
5 | import androidx.navigation.ui.NavigationUI
6 | import androidx.navigation.ui.setupWithNavController
7 | import com.devm7mdibrahim.presentation.R
8 | import com.devm7mdibrahim.presentation.base.BaseFragment
9 | import com.devm7mdibrahim.presentation.databinding.FragmentHomeContainerBinding
10 | import dagger.hilt.android.AndroidEntryPoint
11 |
12 | @AndroidEntryPoint
13 | class HomeContainerFragment :
14 | BaseFragment(FragmentHomeContainerBinding::inflate) {
15 |
16 | override val viewModel by viewModels()
17 |
18 | override fun onResume() {
19 | super.onResume()
20 | setupBottomNavigationView()
21 | }
22 |
23 | private fun setupBottomNavigationView() {
24 | val navController = Navigation.findNavController(requireActivity(), R.id.home_container)
25 | NavigationUI.setupWithNavController(binding.navView, navController)
26 | binding.navView.setupWithNavController(navController)
27 | }
28 | }
--------------------------------------------------------------------------------
/presentation/src/main/java/com/devm7mdibrahim/presentation/cycles/home_cycle/fragment/home_container/HomeContainerViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.presentation.cycles.home_cycle.fragment.home_container
2 |
3 | import com.devm7mdibrahim.presentation.base.BaseViewModel
4 | import dagger.hilt.android.lifecycle.HiltViewModel
5 | import javax.inject.Inject
6 |
7 | @HiltViewModel
8 | class HomeContainerViewModel @Inject constructor() : BaseViewModel() {
9 |
10 | }
--------------------------------------------------------------------------------
/presentation/src/main/java/com/devm7mdibrahim/presentation/cycles/home_cycle/fragment/home_container/home/HomeFragment.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.presentation.cycles.home_cycle.fragment.home_container.home
2 |
3 | import androidx.fragment.app.viewModels
4 | import com.devm7mdibrahim.presentation.base.BaseFragment
5 | import com.devm7mdibrahim.presentation.databinding.FragmentHomeBinding
6 | import dagger.hilt.android.AndroidEntryPoint
7 |
8 | @AndroidEntryPoint
9 | class HomeFragment : BaseFragment(FragmentHomeBinding::inflate) {
10 |
11 | override val viewModel by viewModels()
12 |
13 | }
--------------------------------------------------------------------------------
/presentation/src/main/java/com/devm7mdibrahim/presentation/cycles/home_cycle/fragment/home_container/home/HomeViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.presentation.cycles.home_cycle.fragment.home_container.home
2 |
3 | import com.devm7mdibrahim.presentation.base.BaseViewModel
4 | import dagger.hilt.android.lifecycle.HiltViewModel
5 | import javax.inject.Inject
6 |
7 | @HiltViewModel
8 | class HomeViewModel @Inject constructor() : BaseViewModel() {
9 |
10 | }
--------------------------------------------------------------------------------
/presentation/src/main/java/com/devm7mdibrahim/presentation/cycles/home_cycle/fragment/home_container/notifications/NotificationsFragment.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.presentation.cycles.home_cycle.fragment.home_container.notifications
2 |
3 | import androidx.fragment.app.viewModels
4 | import com.devm7mdibrahim.presentation.base.BaseFragment
5 | import com.devm7mdibrahim.presentation.databinding.FragmentNotificationsBinding
6 | import dagger.hilt.android.AndroidEntryPoint
7 |
8 | @AndroidEntryPoint
9 | class NotificationsFragment : BaseFragment(FragmentNotificationsBinding::inflate) {
10 |
11 | override val viewModel by viewModels()
12 |
13 | }
--------------------------------------------------------------------------------
/presentation/src/main/java/com/devm7mdibrahim/presentation/cycles/home_cycle/fragment/home_container/notifications/NotificationsViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.presentation.cycles.home_cycle.fragment.home_container.notifications
2 |
3 | import com.devm7mdibrahim.presentation.base.BaseViewModel
4 | import dagger.hilt.android.lifecycle.HiltViewModel
5 | import javax.inject.Inject
6 |
7 | @HiltViewModel
8 | class NotificationsViewModel @Inject constructor(): BaseViewModel() {
9 |
10 | }
--------------------------------------------------------------------------------
/presentation/src/main/java/com/devm7mdibrahim/presentation/cycles/home_cycle/fragment/home_container/profile/ProfileFragment.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.presentation.cycles.home_cycle.fragment.home_container.profile
2 |
3 | import androidx.fragment.app.viewModels
4 | import com.devm7mdibrahim.presentation.base.BaseFragment
5 | import com.devm7mdibrahim.presentation.databinding.FragmentProfileBinding
6 | import dagger.hilt.android.AndroidEntryPoint
7 |
8 | @AndroidEntryPoint
9 | class ProfileFragment : BaseFragment(FragmentProfileBinding::inflate) {
10 |
11 | override val viewModel by viewModels()
12 |
13 | }
--------------------------------------------------------------------------------
/presentation/src/main/java/com/devm7mdibrahim/presentation/cycles/home_cycle/fragment/home_container/profile/ProfileViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.presentation.cycles.home_cycle.fragment.home_container.profile
2 |
3 | import com.devm7mdibrahim.presentation.base.BaseViewModel
4 | import dagger.hilt.android.lifecycle.HiltViewModel
5 | import javax.inject.Inject
6 |
7 | @HiltViewModel
8 | class ProfileViewModel @Inject constructor() : BaseViewModel() {
9 |
10 | }
--------------------------------------------------------------------------------
/presentation/src/main/java/com/devm7mdibrahim/presentation/cycles/splash_cycle/activity/SplashActivity.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.presentation.cycles.splash_cycle.activity
2 |
3 | import android.annotation.SuppressLint
4 | import android.os.Bundle
5 | import com.devm7mdibrahim.presentation.R
6 | import com.devm7mdibrahim.presentation.base.BaseActivity
7 | import dagger.hilt.android.AndroidEntryPoint
8 |
9 | @SuppressLint("CustomSplashScreen")
10 | @AndroidEntryPoint
11 | class SplashActivity : BaseActivity() {
12 |
13 | override fun onCreate(savedInstanceState: Bundle?) {
14 | super.onCreate(savedInstanceState)
15 | setContentView(R.layout.activity_splash)
16 | }
17 | }
--------------------------------------------------------------------------------
/presentation/src/main/java/com/devm7mdibrahim/presentation/cycles/splash_cycle/fragment/SplashFragment.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.presentation.cycles.splash_cycle.fragment
2 |
3 | import android.content.Intent
4 | import androidx.fragment.app.viewModels
5 | import androidx.lifecycle.lifecycleScope
6 | import com.devm7mdibrahim.presentation.base.BaseFragment
7 | import com.devm7mdibrahim.presentation.base.BaseViewModel
8 | import com.devm7mdibrahim.presentation.cycles.auth_cycle.activity.AuthActivity
9 | import com.devm7mdibrahim.presentation.cycles.home_cycle.activity.HomeActivity
10 | import com.devm7mdibrahim.presentation.databinding.FragmentSplashBinding
11 | import dagger.hilt.android.AndroidEntryPoint
12 | import kotlinx.coroutines.delay
13 | import kotlinx.coroutines.flow.first
14 |
15 | @AndroidEntryPoint
16 | class SplashFragment : BaseFragment(FragmentSplashBinding::inflate) {
17 |
18 | override val viewModel by viewModels()
19 |
20 | override fun onResume() {
21 | super.onResume()
22 |
23 | lifecycleScope.launchWhenResumed {
24 | delay(2000)
25 |
26 | viewModel.preferenceRepository.getToken().first { token ->
27 | if (token.isNotEmpty()) {
28 | openHomeActivity()
29 | } else {
30 | openAuthActivity()
31 | }
32 |
33 | return@first true
34 | }
35 | }
36 | }
37 |
38 | private fun openHomeActivity() {
39 | Intent(requireActivity(), HomeActivity::class.java)
40 | .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK).also {
41 | startActivity(it)
42 | }
43 | }
44 |
45 | private fun openAuthActivity() {
46 | Intent(requireActivity(), AuthActivity::class.java)
47 | .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK).also {
48 | startActivity(it)
49 | }
50 | }
51 |
52 | }
--------------------------------------------------------------------------------
/presentation/src/main/java/com/devm7mdibrahim/presentation/utils/CommonErrorHandling.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.presentation.utils
2 |
3 | import com.devm7mdibrahim.domain.exceptions.NetworkExceptions
4 | import com.devm7mdibrahim.presentation.R
5 |
6 |
7 | fun Throwable.getIsCommonException(): Int {
8 | when (this) {
9 | is NetworkExceptions.ConnectionException -> {
10 | return R.string.error_connection
11 | }
12 |
13 | is NetworkExceptions.NotFoundException -> {
14 | return R.string.error_not_found
15 | }
16 |
17 | is NetworkExceptions.ServerException -> {
18 | return R.string.error_server
19 | }
20 |
21 | is NetworkExceptions.TimeoutException -> {
22 | return R.string.error_timeout
23 | }
24 |
25 | is NetworkExceptions.UnknownException -> {
26 | return R.string.error_unknown
27 | }
28 |
29 | else -> {
30 | return R.string.error_unknown
31 | }
32 | }
33 | }
--------------------------------------------------------------------------------
/presentation/src/main/java/com/devm7mdibrahim/presentation/utils/Constants.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.presentation.utils
2 |
3 | object Constants {
4 |
5 | object ChatKeys{
6 | const val SUBSCRIBE_ROOM = "subscribe-room"
7 | const val UNSUBSCRIBE_ROOM = "unsubscribe-room"
8 |
9 | const val USER_ID = "user_id"
10 | const val ROOM_ID = "room_id"
11 |
12 | const val MESSAGE = "message"
13 | const val MESSAGE_TYPE = "message_type"
14 | const val MESSAGE_TEXT = "text"
15 | const val SEND_MESSAGE = "sendChatMessage"
16 | const val RECEIVE_MESSAGE = "receiveChatMessage"
17 | }
18 | }
--------------------------------------------------------------------------------
/presentation/src/main/res/anim/fade_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/presentation/src/main/res/anim/fade_out.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/presentation/src/main/res/anim/slide_in_left.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
--------------------------------------------------------------------------------
/presentation/src/main/res/anim/slide_in_right.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
--------------------------------------------------------------------------------
/presentation/src/main/res/anim/slide_out_left.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
--------------------------------------------------------------------------------
/presentation/src/main/res/anim/slide_out_right.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
--------------------------------------------------------------------------------
/presentation/src/main/res/color/bottom_nav_color.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/presentation/src/main/res/layout/activity_auth.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
18 |
19 |
--------------------------------------------------------------------------------
/presentation/src/main/res/layout/activity_home.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
15 |
16 |
--------------------------------------------------------------------------------
/presentation/src/main/res/layout/activity_splash.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
18 |
19 |
--------------------------------------------------------------------------------
/presentation/src/main/res/layout/base_toolbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
27 |
28 |
41 |
42 |
--------------------------------------------------------------------------------
/presentation/src/main/res/layout/fragment_home.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/presentation/src/main/res/layout/fragment_home_container.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
16 |
17 |
33 |
--------------------------------------------------------------------------------
/presentation/src/main/res/layout/fragment_login.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
17 |
18 |
19 |
29 |
30 |
41 |
--------------------------------------------------------------------------------
/presentation/src/main/res/layout/fragment_notifications.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/presentation/src/main/res/layout/fragment_profile.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/presentation/src/main/res/layout/fragment_register.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/presentation/src/main/res/layout/fragment_splash.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/presentation/src/main/res/menu/home_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/presentation/src/main/res/navigation/auth_graph.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
16 |
23 |
24 |
--------------------------------------------------------------------------------
/presentation/src/main/res/navigation/home_container_graph.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
10 |
14 |
18 |
--------------------------------------------------------------------------------
/presentation/src/main/res/navigation/home_graph.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
--------------------------------------------------------------------------------
/presentation/src/main/res/navigation/splash_graph.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
--------------------------------------------------------------------------------
/presentation/src/main/res/values-ar/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Base Modules
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 |
--------------------------------------------------------------------------------
/presentation/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #FAEA27
5 | #99C056
6 | #FFD903
7 | #FFD903
8 | #99C056
9 | #FFFFFFFF
10 |
11 |
12 | #FAEA27
13 | #0B3434
14 | #99C056
15 | #8DA34E
16 |
17 | #77FAEA27
18 |
19 |
20 | #2C52A2
21 | #9FDAF7
22 | #FFD903
23 | #f2f2f2
24 |
25 |
26 | #e22b2b
27 | #fc8b8d
28 | #CDD4D9
29 | #f2f2f2
30 | #c4c4c4
31 | #a8a8a8
32 | #7d7d7d
33 | #5c5c5c
34 |
35 | #686868
36 | #EEEEEE
37 | #4FD477
38 | #E2DDD0
39 | #000
40 | #1F2327
41 | #8D8D8D
42 | #33FFD903
43 | #575757
44 | #EFEFEF
45 | #33EFEFEF
46 | #CB0529
47 | #EEEEEE
48 | #6B6B6B
49 | #DFE0E0
50 | #FFCE00
51 | #FBFAF8
52 | #FBFAF8
53 | #BA94C1
54 | #CDD4D9
55 | #9FFFFFFF
56 | #393939
57 | #E30613
58 | #FC0000
59 | #F6F6F6
60 | #F2F2F2
61 | #666767
62 | #707070
63 | #08324D
64 | #D31E37
65 | #464646
66 | #989898
67 | #82A94C
68 | #F8F8F8
69 | #FF0000
70 |
71 |
--------------------------------------------------------------------------------
/presentation/src/main/res/values/google_maps_api.xml:
--------------------------------------------------------------------------------
1 |
2 | AIzaSyD5eKqs2_QBnxgMePLiEmBpz7WXr_aPuFA
3 |
--------------------------------------------------------------------------------
/presentation/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Base Modules
3 | There are no chats
4 | OK
5 | Cancel
6 | SAR
7 | No internet connection
8 | Alert
9 | Are you sure you want to logout?
10 | You must login to continue
11 | Your account has been blocked or deleted. In the event of an error, please contact the application administration.
12 |
13 | Timeout, please try again
14 | Something went wrong, please try again
15 | Something went wrong, please try again later
16 | Something went wrong, please try again later
17 | No internet connection
18 | UnAuthorized user
19 |
20 | Invalid phone number
21 | Invalid user name
22 | Invalid password
23 | Invalid confirmation password
24 | Invalid email address
25 | Invalid device id
26 | Please enter the verification code before confirm
27 |
28 | This text is an example of a text that can be replaced in the same space,
29 | this text was generated from the Arabic text generator,
30 | this text is an example of text that can be replaced in the same space,
31 | this text was generated from the Arabic text generator,
32 | this text is an example of a text that can be replaced To replace in the same space,
33 | it has been taken over
34 |
--------------------------------------------------------------------------------
/presentation/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
15 |
16 |
19 |
20 |
24 |
25 |
40 |
41 |
--------------------------------------------------------------------------------
/presentation/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
17 |
18 |
19 |
38 |
39 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = "base-android"
2 | include ':app'
3 | include ':presentation'
4 | include ':data'
5 | include ':domain'
6 | include ':utils'
--------------------------------------------------------------------------------
/utils/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/utils/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'org.jetbrains.kotlin.android'
4 | id 'kotlin-kapt'
5 | }
6 |
7 | android {
8 | compileSdk 31
9 |
10 | defaultConfig {
11 | minSdk 21
12 | targetSdk 31
13 |
14 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
15 | consumerProguardFiles "consumer-rules.pro"
16 | }
17 |
18 | buildTypes {
19 | release {
20 | minifyEnabled false
21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
22 | }
23 | }
24 | compileOptions {
25 | sourceCompatibility JavaVersion.VERSION_1_8
26 | targetCompatibility JavaVersion.VERSION_1_8
27 | }
28 | kotlinOptions {
29 | jvmTarget = '1.8'
30 | }
31 | }
32 |
33 | dependencies {
34 |
35 | implementation Compilers.hilt_android
36 | kapt Compilers.hilt_android_compiler
37 | kapt Compilers.hilt_android_lifecycle_compiler
38 |
39 | implementation Dependencies.navigation_fragment
40 | implementation Dependencies.navigation_ui
41 |
42 | implementation Dependencies.firebase_analytics
43 | implementation Dependencies.firebase_crashlytics
44 |
45 | api 'androidx.core:core-ktx:1.7.0'
46 | api 'androidx.appcompat:appcompat:1.4.2'
47 | api 'com.google.android.material:material:1.6.1'
48 | api 'androidx.legacy:legacy-support-v4:1.0.0'
49 | implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1'
50 |
51 | api 'com.github.bumptech.glide:glide:4.12.0'
52 | kapt 'com.github.bumptech.glide:compiler:4.12.0'
53 |
54 | api "io.nlopez.smartlocation:rx:3.3.3"
55 | api 'com.karumi:dexter:6.2.2'
56 | api 'com.akexorcist:localization:1.2.10'
57 | api "org.greenrobot:eventbus:3.2.0"
58 |
59 | api 'com.tuyenmonkey:mkloader:1.4.0'
60 | api 'com.github.GrenderG:Toasty:1.5.2'
61 | api "de.hdodenhof:circleimageview:3.1.0"
62 | api 'com.makeramen:roundedimageview:2.3.0'
63 | api 'com.github.iwgang:countdownview:2.1.6'
64 | api 'com.alimuzaffar.lib:pinentryedittext:2.0.6'
65 |
66 | api "com.intuit.sdp:sdp-android:1.0.6"
67 | api "com.intuit.ssp:ssp-android:1.0.6"
68 |
69 | //google services
70 | api "com.google.android.gms:play-services-maps:18.0.2"
71 | api "com.google.maps:google-maps-services:0.1.20"
72 | api "com.google.android.gms:play-services-location:20.0.0"
73 | api "com.google.android.libraries.places:places:2.6.0"
74 | api "com.google.android.gms:play-services-places:17.0.0"
75 | implementation Dependencies.firebase_messaging
76 | }
--------------------------------------------------------------------------------
/utils/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devm7mdibrahim/MVVM-CleanArchitecture/a9cec8c10c271bfa756863e2fa71b5977e802a0f/utils/consumer-rules.pro
--------------------------------------------------------------------------------
/utils/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
--------------------------------------------------------------------------------
/utils/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/utils/src/main/java/com/devm7mdibrahim/utils/common/NetworkHelper.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.utils.common
2 |
3 | import android.content.Context
4 | import android.net.ConnectivityManager
5 | import android.net.NetworkCapabilities
6 | import android.os.Build
7 | import dagger.hilt.android.qualifiers.ApplicationContext
8 | import javax.inject.Inject
9 | import javax.inject.Singleton
10 |
11 | @Singleton
12 | class NetworkHelper @Inject constructor(@ApplicationContext private val context: Context) {
13 |
14 | @Suppress("DEPRECATION")
15 | fun isNetworkConnected(): Boolean {
16 | var result = false
17 | val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
18 |
19 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
20 | val networkCapabilities = connectivityManager.activeNetwork ?: return false
21 | val activeNetwork = connectivityManager.getNetworkCapabilities(networkCapabilities) ?: return false
22 |
23 | result = when {
24 | activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
25 | activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
26 | activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
27 | else -> false
28 | }
29 |
30 | } else {
31 | connectivityManager.run {
32 | connectivityManager.activeNetworkInfo?.run {
33 | result = when (type) {
34 | ConnectivityManager.TYPE_WIFI -> true
35 | ConnectivityManager.TYPE_MOBILE -> true
36 | ConnectivityManager.TYPE_ETHERNET -> true
37 | else -> false
38 | }
39 |
40 | }
41 | }
42 | }
43 |
44 | return result
45 | }
46 | }
--------------------------------------------------------------------------------
/utils/src/main/java/com/devm7mdibrahim/utils/common/PaginationHelper.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.utils.common
2 |
3 | import androidx.recyclerview.widget.LinearLayoutManager
4 | import androidx.recyclerview.widget.RecyclerView
5 |
6 |
7 | abstract class PaginationHelper(var layoutManager: LinearLayoutManager) :
8 | RecyclerView.OnScrollListener() {
9 |
10 | abstract fun isLastPage(): Boolean
11 |
12 | abstract fun isLoading(): Boolean
13 |
14 | override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
15 |
16 | recyclerView.let { super.onScrolled(it, dx, dy) }
17 |
18 | val visibleItemCount = layoutManager.childCount
19 | val totalItemCount = layoutManager.itemCount
20 | val firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition()
21 |
22 | if (dy > 0)
23 | if (!isLoading() && !isLastPage()) {
24 | if (visibleItemCount + firstVisibleItemPosition >= totalItemCount)
25 | if (visibleItemCount + firstVisibleItemPosition >= totalItemCount && firstVisibleItemPosition >= 0) {
26 | loadMoreItems()
27 | }
28 | }
29 | }
30 |
31 | abstract fun loadMoreItems()
32 |
33 | }
--------------------------------------------------------------------------------
/utils/src/main/java/com/devm7mdibrahim/utils/common/ProgressUtil.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.utils.common
2 |
3 | import android.app.AlertDialog
4 | import android.content.Context
5 | import android.graphics.Color
6 | import android.graphics.drawable.ColorDrawable
7 | import android.view.LayoutInflater
8 | import android.view.ViewGroup
9 | import android.view.Window
10 | import com.devm7mdibrahim.utils.R
11 | import javax.inject.Inject
12 | import javax.inject.Singleton
13 |
14 | @Singleton
15 | class ProgressUtil @Inject constructor(val context: Context) {
16 |
17 |
18 | private var dialog: AlertDialog? = null
19 |
20 | init {
21 | init()
22 | }
23 |
24 | private fun init() {
25 | dialog = AlertDialog.Builder(context).create()
26 | dialog?.apply {
27 | val inflate = LayoutInflater.from(context).inflate(R.layout.progress, findViewById(android.R.id.content),false)
28 | setView(inflate)
29 | requestWindowFeature(Window.FEATURE_NO_TITLE)
30 | setCancelable(false)
31 | }
32 |
33 | dialog?.window?.apply {
34 | setLayout(
35 | ViewGroup.LayoutParams.MATCH_PARENT,
36 | ViewGroup.LayoutParams.WRAP_CONTENT
37 | )
38 | setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
39 | }
40 | }
41 |
42 |
43 | fun showProgress() {
44 | if (dialog != null && dialog?.isShowing == false) {
45 | dialog?.show()
46 | }
47 | }
48 |
49 |
50 | fun hideProgress() {
51 | if (dialog?.isShowing == true) {
52 | dialog?.dismiss()
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/utils/src/main/java/com/devm7mdibrahim/utils/di/ActivityModule.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.utils.di
2 |
3 | import android.app.Activity
4 | import com.devm7mdibrahim.utils.common.ProgressUtil
5 | import dagger.Module
6 | import dagger.Provides
7 | import dagger.hilt.InstallIn
8 | import dagger.hilt.android.components.ActivityComponent
9 | import dagger.hilt.android.scopes.ActivityScoped
10 |
11 | @Module
12 | @InstallIn(ActivityComponent::class)
13 | object ActivityModule {
14 |
15 | @Provides
16 | @ActivityScoped
17 | fun provideProgressUtil(activity: Activity): ProgressUtil {
18 | return ProgressUtil(activity)
19 | }
20 |
21 | }
--------------------------------------------------------------------------------
/utils/src/main/java/com/devm7mdibrahim/utils/di/GlideModule.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.utils.di
2 |
3 | import android.content.Context
4 | import android.util.Log
5 | import com.bumptech.glide.GlideBuilder
6 | import com.bumptech.glide.annotation.GlideModule
7 |
8 | import com.bumptech.glide.module.AppGlideModule
9 |
10 |
11 | @GlideModule
12 | class GlideModule : AppGlideModule() {
13 | override fun applyOptions(context: Context, builder: GlideBuilder) {
14 | super.applyOptions(context, builder)
15 | builder.setLogLevel(Log.ERROR)
16 | }
17 | }
--------------------------------------------------------------------------------
/utils/src/main/java/com/devm7mdibrahim/utils/extensions/AlertExtensions.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.utils.extensions
2 |
3 | import android.app.AlertDialog
4 | import android.content.Context
5 | import com.devm7mdibrahim.utils.R
6 |
7 |
8 | fun Context.showAlertDialog(
9 | title: String? = null,
10 | msg: String? = null,
11 | drawable: Int? = null,
12 | listener: (Boolean) -> Unit
13 | ) {
14 | AlertDialog.Builder(this)
15 | .setCancelable(false)
16 | .setTitle(title ?: "")
17 | .setMessage(msg ?: "")
18 | .setPositiveButton(
19 | R.string.text_ok
20 | ) { _, _ ->
21 | listener(true)
22 | }
23 | .setNegativeButton(
24 | R.string.text_cancel
25 | ) { dialog, _ ->
26 | listener(false)
27 | dialog.cancel()
28 | }.setIcon(drawable ?: android.R.drawable.ic_dialog_alert)
29 | .show()
30 | }
31 |
32 | fun Context.openLoginDialog(listener: (Boolean) -> Unit) {
33 | showAlertDialog(
34 | getString(R.string.text_alert),
35 | getString(R.string.text_are_must_login_to_continue)
36 | ) {
37 | listener(it)
38 | }
39 | }
40 |
41 | fun Context.openAccountDeletedDialog(listener: (Boolean) -> Unit) {
42 | showAlertDialog(
43 | getString(R.string.text_alert),
44 | getString(R.string.block_massage)
45 | ) {
46 | listener(it)
47 | }
48 | }
49 |
50 | fun Context.openLogoutDialog(listener: (Boolean) -> Unit) {
51 | showAlertDialog(
52 | getString(R.string.text_alert),
53 | getString(R.string.text_are_you_sure_logout)
54 | ) {
55 | listener(it)
56 | }
57 | }
--------------------------------------------------------------------------------
/utils/src/main/java/com/devm7mdibrahim/utils/extensions/CommonExtensions.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.utils.extensions
2 |
3 | import android.content.Context
4 | import android.util.Log
5 | import com.devm7mdibrahim.utils.R
6 | import com.google.gson.Gson
7 |
8 |
9 | fun Any.onPrintLog(tag: String = "App LOG ==>>> ") {
10 | Log.d(tag, Gson().toJson(this))
11 | }
12 |
13 | fun Context.setPriceWithCurrency(
14 | price: String?,
15 | currency: String = getString(R.string.sar)
16 | ): String {
17 | if (price == null) return ""
18 | return buildString {
19 | append(price)
20 | append(" ")
21 | append(currency)
22 | }
23 | }
--------------------------------------------------------------------------------
/utils/src/main/java/com/devm7mdibrahim/utils/extensions/ExceptionsExtensions.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.utils.extensions
2 |
3 | import com.google.firebase.crashlytics.FirebaseCrashlytics
4 |
5 | fun Throwable.log() {
6 | printStackTrace()
7 | FirebaseCrashlytics.getInstance().recordException(this)
8 | }
9 |
10 | fun catch(action: () -> Unit) =
11 | try {
12 | action.invoke()
13 | } catch (throwable: Throwable) {
14 | throwable.log()
15 | }
--------------------------------------------------------------------------------
/utils/src/main/java/com/devm7mdibrahim/utils/extensions/FirebaseExtensions.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.utils.extensions
2 |
3 | import com.google.firebase.messaging.FirebaseMessaging
4 |
5 | fun getFirebaseToken(token : (String) -> Unit) {
6 | FirebaseMessaging.getInstance().token.addOnCompleteListener {
7 | if (it.isSuccessful) {
8 | token(it.result)
9 | } else {
10 | it.exception?.printStackTrace()
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/utils/src/main/java/com/devm7mdibrahim/utils/extensions/FragmentExtensions.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.utils.extensions
2 |
3 | import android.os.Bundle
4 | import androidx.fragment.app.Fragment
5 | import androidx.lifecycle.Lifecycle
6 | import androidx.lifecycle.lifecycleScope
7 | import androidx.lifecycle.repeatOnLifecycle
8 | import kotlinx.coroutines.flow.Flow
9 | import kotlinx.coroutines.flow.collect
10 | import kotlinx.coroutines.launch
11 |
12 | fun Fragment.setFragmentResult(requestKey: String, result: Bundle) {
13 | parentFragmentManager.setFragmentResult(requestKey, result)
14 | }
15 |
16 | fun Fragment.setFragmentResultListener(
17 | requestKey: String,
18 | listener: ((requestKey: String, bundle: Bundle) -> Unit)
19 | ) {
20 | parentFragmentManager.setFragmentResultListener(requestKey, this, listener)
21 | }
22 |
23 | fun Fragment.collectLifecycleFlow(flow: Flow, collect: suspend (T) -> Unit) {
24 | viewLifecycleOwner.lifecycleScope.launch {
25 | viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
26 | flow.collect(collect)
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/utils/src/main/java/com/devm7mdibrahim/utils/extensions/JsonExtensions.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.utils.extensions
2 |
3 | import com.google.gson.Gson
4 |
5 |
6 | fun T.toJson(): String {
7 | return Gson().toJson(this)
8 | }
9 |
10 | inline fun String.fromJson(): T {
11 | return Gson().fromJson(this, T::class.java)
12 | }
13 |
14 | inline fun fromJsonToList(jsonString: String): List {
15 | return Gson().fromJson(jsonString, emptyArray().javaClass).toList()
16 | }
--------------------------------------------------------------------------------
/utils/src/main/java/com/devm7mdibrahim/utils/extensions/KeyboardExtensions.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.utils.extensions
2 |
3 | import android.app.Activity
4 | import android.content.Context
5 | import android.view.View
6 | import android.view.inputmethod.InputMethodManager
7 |
8 |
9 | /**
10 | * Use only from Activities, don't use from Fragment (with getActivity) or from Dialog/DialogFragment
11 | */
12 | fun Activity.hideKeyboard() {
13 | val imm = getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
14 | val view = currentFocus ?: View(this)
15 | imm.hideSoftInputFromWindow(view.windowToken, 0)
16 | window.decorView
17 | }
18 |
19 | fun View.showKeyboard() {
20 | val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
21 | imm.showSoftInput(this, InputMethodManager.SHOW_FORCED)
22 | }
23 |
24 | /**
25 | * Use everywhere except from Activity (Custom View, Fragment, Dialogs, DialogFragments).
26 | */
27 | fun View.hideKeyboard() {
28 | val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
29 | imm.hideSoftInputFromWindow(windowToken, 0)
30 | }
31 |
--------------------------------------------------------------------------------
/utils/src/main/java/com/devm7mdibrahim/utils/extensions/NavigationExtension.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.utils.extensions
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import androidx.annotation.IdRes
6 | import androidx.appcompat.widget.Toolbar
7 | import androidx.fragment.app.Fragment
8 | import androidx.navigation.*
9 | import androidx.navigation.fragment.findNavController
10 |
11 | fun View.navigate(direction: NavDirections) {
12 | catch {
13 | findNavController().navigate(direction)
14 | }
15 | }
16 |
17 | fun View.navigate(@IdRes destination: Int, args: Bundle? = null) {
18 | catch {
19 | findNavController()
20 | .navigate(destination, args)
21 | }
22 | }
23 |
24 | fun Fragment.navigate(@IdRes destination: Int, args: Bundle? = null) {
25 | catch {
26 | findNavController().navigate(destination, args)
27 | }
28 | }
29 |
30 | fun Fragment.navigate(direction: NavDirections, options: NavOptions? = null) {
31 | catch {
32 | findNavController().navigate(direction, options)
33 | }
34 | }
35 |
36 | fun Fragment.navigate(direction: NavDirections, extras: Navigator.Extras) {
37 | catch {
38 | findNavController().navigate(direction, extras)
39 | }
40 | }
41 |
42 | fun Fragment.back() {
43 | catch {
44 | findNavController().popBackStack()
45 | }
46 | }
--------------------------------------------------------------------------------
/utils/src/main/java/com/devm7mdibrahim/utils/extensions/ThemeExtentions.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.utils.extensions
2 |
3 | import androidx.appcompat.app.AppCompatDelegate
4 |
5 | object ThemeHelper {
6 | fun applyTheme(theme: ThemeMode) {
7 | when (theme) {
8 | ThemeMode.LIGHT -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
9 | ThemeMode.DARK -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
10 | ThemeMode.BATTERY_SAVER -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY)
11 | ThemeMode.DEFAULT -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
12 | }
13 | }
14 |
15 | enum class ThemeMode { LIGHT, DARK, BATTERY_SAVER, DEFAULT }
16 | }
--------------------------------------------------------------------------------
/utils/src/main/java/com/devm7mdibrahim/utils/extensions/ToastExtenstions.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.utils.extensions
2 |
3 | import android.content.Context
4 | import android.widget.Toast
5 | import com.devm7mdibrahim.utils.R
6 | import es.dmoral.toasty.Toasty
7 |
8 | fun Context.showToast(message: String?, toastType: ToastType = ToastType.ERROR, withIcon: Boolean = true) {
9 | if (message.isNullOrEmpty()) return
10 | when (toastType) {
11 | ToastType.SUCCESS -> {
12 | Toasty.success(this, message, Toast.LENGTH_SHORT, withIcon).show()
13 | }
14 | ToastType.ERROR -> {
15 | Toasty.error(this, message, Toast.LENGTH_SHORT, withIcon).show()
16 | }
17 | ToastType.INFO -> {
18 | Toasty.info(this, message, Toast.LENGTH_SHORT, withIcon).show()
19 | }
20 | ToastType.WARNING -> {
21 | Toasty.warning(this, message, Toast.LENGTH_SHORT, withIcon).show()
22 | }
23 | }
24 | }
25 |
26 | fun Context.toastNoInternetConnection() {
27 | Toasty.error(
28 | this,
29 | getString(R.string.no_internet_connection),
30 | Toast.LENGTH_SHORT,
31 | true
32 | ).show()
33 | }
34 |
35 | enum class ToastType {
36 | SUCCESS, ERROR, WARNING, INFO
37 | }
38 |
--------------------------------------------------------------------------------
/utils/src/main/java/com/devm7mdibrahim/utils/file/FileUtils.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.utils.file
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.ContentResolver
5 | import android.content.Context
6 | import android.net.Uri
7 | import android.os.Environment
8 | import android.provider.OpenableColumns
9 | import kotlinx.coroutines.runBlocking
10 | import java.io.File
11 | import java.io.FileOutputStream
12 | import java.io.InputStream
13 | import java.io.OutputStream
14 |
15 | class FileUtils constructor(val context: Context) {
16 |
17 | fun saveFileInStorage(uri: Uri): String {
18 | var path = ""
19 | runBlocking {
20 | try {
21 | val file: File?
22 | val mimeType: String? = context.contentResolver.getType(uri)
23 | if (mimeType != null) {
24 | val inputStream: InputStream? = context.contentResolver.openInputStream(uri)
25 | val fileName = context.contentResolver.getFileName(uri)
26 |
27 | if (fileName != "") {
28 | file = File(
29 | context.getExternalFilesDir(
30 | Environment.DIRECTORY_DOWNLOADS
31 | )?.absolutePath.toString() + "/" + fileName
32 | )
33 | val output: OutputStream = FileOutputStream(file)
34 | output.use { it ->
35 | val buffer =
36 | ByteArray(inputStream?.available()!!)
37 | var read: Int
38 | while (inputStream.read(buffer).also { read = it } != -1) {
39 | it.write(buffer, 0, read)
40 | }
41 | it.flush()
42 | path = file.absolutePath //use this path
43 | }
44 | }
45 | }
46 | } catch (e: Exception) {
47 | e.printStackTrace()
48 | }
49 | }
50 | return path
51 | }
52 |
53 | @SuppressLint("Range")
54 | fun ContentResolver.getFileName(uri: Uri): String {
55 | var mName = ""
56 | val cursor = query(uri, null, null, null, null)
57 | cursor?.use {
58 | it.moveToFirst()
59 | mName = cursor.getString(it.getColumnIndex(OpenableColumns.DISPLAY_NAME))
60 | }
61 | return mName
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/utils/src/main/java/com/devm7mdibrahim/utils/spinner/MaterialSpinnerUtil.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.utils.spinner
2 |
3 | import android.content.Context
4 | import android.widget.AdapterView
5 | import android.widget.ArrayAdapter
6 | import android.widget.AutoCompleteTextView
7 |
8 | fun AutoCompleteTextView.init(
9 | context: Context,
10 | list: List,
11 | onItemSelected: (Int) -> Unit
12 | ) {
13 | val arrayAdapter =
14 | ArrayAdapter(context, android.R.layout.simple_list_item_1, list)
15 | setAdapter(arrayAdapter)
16 | onItemClickListener = AdapterView.OnItemClickListener { _, _, position, _ ->
17 | onItemSelected(position)
18 | }
19 | }
--------------------------------------------------------------------------------
/utils/src/main/java/com/devm7mdibrahim/utils/spinner/SpinnerUtil.kt:
--------------------------------------------------------------------------------
1 | package com.devm7mdibrahim.utils.spinner
2 |
3 | import android.content.Context
4 | import android.view.View
5 | import android.widget.AdapterView
6 | import android.widget.ArrayAdapter
7 | import android.widget.Spinner
8 |
9 | object SpinnerUtil {
10 |
11 | fun setSpinnerAdapter(
12 | context: Context,
13 | spinner: Spinner,
14 | list: List,
15 | onItemSelected: (Int) -> Unit
16 | ): ArrayAdapter {
17 |
18 | val arrayAdapter = ArrayAdapter(context, android.R.layout.simple_spinner_item, list)
19 | arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
20 | spinner.adapter = arrayAdapter
21 |
22 | spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
23 | override fun onItemSelected(p0: AdapterView<*>?, p1: View?, position: Int, p3: Long) {
24 | onItemSelected(position)
25 | }
26 |
27 | override fun onNothingSelected(p0: AdapterView<*>?) {
28 |
29 | }
30 | }
31 |
32 | return arrayAdapter
33 | }
34 | }
--------------------------------------------------------------------------------
/utils/src/main/res/drawable/bg_top_rounded_white.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/utils/src/main/res/drawable/ic_back.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/utils/src/main/res/layout/progress.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/utils/src/main/res/values-ar/strings.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 |
--------------------------------------------------------------------------------
/utils/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 | #F8F8F8
5 | #3DB9B4
6 | #F8F8F8
7 | #FFFFFF
8 | #000000
9 | #FFB72B
10 | #D40C0C
11 |
--------------------------------------------------------------------------------
/utils/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | OK
4 | Cancel
5 | SAR
6 | No internet connection
7 | Alert
8 | Are you sure you want to logout?
9 | You must login to continue
10 | Your account has been blocked or deleted. In the event of an error, please contact the application administration.
11 |
12 | Timeout, please try again
13 | Something went wrong, please try again
14 | Something went wrong, please try again later
15 | Something went wrong, please try again later
16 | No internet connection
17 | UnAuthorized user
18 |
19 | Invalid phone number
20 | Invalid user name
21 | Invalid password
22 | Invalid confirmation password
23 | Invalid email address
24 | Invalid device id
25 | Please enter the verification code before confirm
26 |
27 | This text is an example of a text that can be replaced in the same space,
28 | this text was generated from the Arabic text generator,
29 | this text is an example of text that can be replaced in the same space,
30 | this text was generated from the Arabic text generator,
31 | this text is an example of a text that can be replaced To replace in the same space,
32 | it has been taken over
33 |
--------------------------------------------------------------------------------