(
116 | val name: String,
117 | val adapter: JsonAdapter,
118 | val property: KProperty1,
119 | val parameter: KParameter?,
120 | ) {
121 | fun get(value: K) = property.get(value)
122 |
123 | fun set(result: K, value: P) {
124 | if (value !== ABSENT_VALUE) {
125 | (property as KMutableProperty1).set(result, value)
126 | }
127 | }
128 | }
129 |
130 | /** A simple [Map] that uses parameter indexes instead of sorting or hashing. */
131 | class IndexedParameterMap(val parameterKeys: List, val parameterValues: Array)
132 | : AbstractMap() {
133 |
134 | override val entries: Set>
135 | get() {
136 | val allPossibleEntries = parameterKeys.mapIndexed { index, value ->
137 | SimpleEntry(value, parameterValues[index])
138 | }
139 | return allPossibleEntries.filterTo(LinkedHashSet>()) {
140 | it.value !== ABSENT_VALUE && it.value!=null
141 | }
142 | }
143 |
144 | override fun containsKey(key: KParameter) = parameterValues[key.index] !== ABSENT_VALUE && parameterValues[key.index] !=null
145 |
146 | override fun get(key: KParameter): Any? {
147 | val value = parameterValues[key.index]
148 | return if (value !== ABSENT_VALUE) value else null
149 | }
150 | }
151 | }
152 |
153 | class MyKotlinJsonAdapterFactory : JsonAdapter.Factory {
154 | @ExperimentalStdlibApi
155 | override fun create(type: Type, annotations: MutableSet, moshi: Moshi)
156 | : JsonAdapter<*>? {
157 | if (annotations.isNotEmpty()) return null
158 |
159 | val rawType = Types.getRawType(type)
160 | if (rawType.isInterface) return null
161 | if (rawType.isEnum) return null
162 | if (!rawType.isAnnotationPresent(KOTLIN_METADATA)) return null
163 | if (Util.isPlatformType(rawType)) return null
164 | try {
165 | val generatedAdapter = generatedAdapter(moshi, type, rawType)
166 | if (generatedAdapter != null) {
167 | return generatedAdapter
168 | }
169 | } catch (e: RuntimeException) {
170 | if (e.cause !is ClassNotFoundException) {
171 | throw e
172 | }
173 | // Fall back to a reflective adapter when the generated adapter is not found.
174 | }
175 |
176 | if (rawType.isLocalClass) {
177 | throw IllegalArgumentException("Cannot serialize local class or object expression ${rawType.name}")
178 | }
179 | val rawTypeKotlin = rawType.kotlin
180 | if (rawTypeKotlin.isAbstract) {
181 | throw IllegalArgumentException("Cannot serialize abstract class ${rawType.name}")
182 | }
183 | if (rawTypeKotlin.isInner) {
184 | throw IllegalArgumentException("Cannot serialize inner class ${rawType.name}")
185 | }
186 | if (rawTypeKotlin.objectInstance != null) {
187 | throw IllegalArgumentException("Cannot serialize object declaration ${rawType.name}")
188 | }
189 |
190 | val constructor = rawTypeKotlin.primaryConstructor ?: return null
191 | val parametersByName = constructor.parameters.associateBy { it.name }
192 | constructor.isAccessible = true
193 |
194 | val bindingsByName = LinkedHashMap>()
195 |
196 | for (property in rawTypeKotlin.memberProperties) {
197 | val parameter = parametersByName[property.name]
198 |
199 | if (Modifier.isTransient(property.javaField?.modifiers ?: 0)) {
200 | if (parameter != null && !parameter.isOptional) {
201 | throw IllegalArgumentException(
202 | "No default value for transient constructor $parameter")
203 | }
204 | continue
205 | }
206 |
207 | if (parameter != null && parameter.type != property.returnType) {
208 | throw IllegalArgumentException("'${property.name}' has a constructor parameter of type " +
209 | "${parameter.type} but a property of type ${property.returnType}.")
210 | }
211 |
212 | if (property !is KMutableProperty1 && parameter == null) continue
213 |
214 | property.isAccessible = true
215 | var allAnnotations = property.annotations
216 | var jsonAnnotation = property.findAnnotation()
217 |
218 | if (parameter != null) {
219 | allAnnotations += parameter.annotations
220 | if (jsonAnnotation == null) {
221 | jsonAnnotation = parameter.findAnnotation()
222 | }
223 | }
224 |
225 | val name = jsonAnnotation?.name ?: property.name
226 | val resolvedPropertyType = resolve(type, rawType, property.returnType.javaType)
227 | val adapter = moshi.adapter(
228 | resolvedPropertyType, Util.jsonAnnotations(allAnnotations.toTypedArray()), property.name)
229 |
230 | bindingsByName[property.name] =
231 | MyKotlinJsonAdapter.Binding(
232 | name, adapter,
233 | property as KProperty1, parameter
234 | )
235 | }
236 |
237 | val bindings = ArrayList?>()
238 |
239 | for (parameter in constructor.parameters) {
240 | val binding = bindingsByName.remove(parameter.name)
241 | if (binding == null && !parameter.isOptional) {
242 | throw IllegalArgumentException("No property for required constructor $parameter")
243 | }
244 | bindings += binding
245 | }
246 |
247 | bindings += bindingsByName.values
248 |
249 | val options = JsonReader.Options.of(*bindings.map { it?.name ?: "\u0000" }.toTypedArray())
250 | return MyKotlinJsonAdapter(
251 | constructor,
252 | bindings,
253 | options
254 | ).nullSafe()
255 | }
256 | }
257 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/mvvmKotlinJetpackCompose/data/others/MenuItem.kt:
--------------------------------------------------------------------------------
1 | package com.example.mvvmKotlinJetpackCompose.data.others
2 |
3 | data class MenuItem(val icon:Int,val text:String)
4 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/mvvmKotlinJetpackCompose/data/prefs/AppPreferencesHelper.kt:
--------------------------------------------------------------------------------
1 | package com.example.mvvmKotlinJetpackCompose.data.prefs
2 |
3 | import android.content.Context
4 | import android.content.SharedPreferences
5 | import com.example.mvvmKotlinJetpackCompose.di.PreferenceInfo
6 | import com.example.mvvmKotlinJetpackCompose.util.*
7 | import dagger.hilt.android.qualifiers.ApplicationContext
8 | import javax.inject.Inject
9 |
10 | class AppPreferencesHelper @Inject constructor(
11 | @ApplicationContext val context: Context,
12 | @PreferenceInfo val prefFileName: String?,
13 | ) : PreferencesHelper {
14 |
15 |
16 | private var mPrefs: SharedPreferences =
17 | context.getSharedPreferences(prefFileName, Context.MODE_PRIVATE);
18 |
19 | override fun getCurrentUserId(): String? {
20 | val userId =
21 | mPrefs.getString(PREF_KEY_CURRENT_USER_ID, NULL_INDEX)
22 | return if (userId == NULL_INDEX) null else userId
23 | }
24 |
25 | override fun setCurrentUserId(userId: String?) {
26 | val id = userId ?: NULL_INDEX
27 | mPrefs.putAny(PREF_KEY_CURRENT_USER_ID, id)
28 |
29 | }
30 |
31 | override fun getCurrentUserName(): String? {
32 | return mPrefs.getString(PREF_KEY_CURRENT_USER_NAME, null)
33 | }
34 |
35 | override fun setCurrentUserName(userName: String?) {
36 | mPrefs.putAny(PREF_KEY_CURRENT_USER_NAME, userName)
37 |
38 | }
39 |
40 | override fun getCurrentUserEmail(): String? {
41 | return mPrefs.getString(PREF_KEY_CURRENT_USER_EMAIL, null)
42 | }
43 |
44 | override fun setCurrentUserEmail(email: String?) {
45 | mPrefs.putAny(PREF_KEY_CURRENT_USER_EMAIL, email)
46 |
47 | }
48 |
49 | override fun getCurrentUserProfilePicUrl(): String? {
50 | return mPrefs.getString(PREF_KEY_CURRENT_USER_PROFILE_PIC_URL, null)
51 | }
52 |
53 | override fun setCurrentUserProfilePicUrl(profilePicUrl: String?) {
54 |
55 | mPrefs.putAny(PREF_KEY_CURRENT_USER_PROFILE_PIC_URL, profilePicUrl)
56 |
57 | }
58 |
59 | override suspend fun getCurrentUserLoggedInMode(): Int {
60 | return mPrefs.getInt(PREF_KEY_USER_LOGGED_IN_MODE, LoggedInMode.LOGGED_IN_MODE_LOGGED_OUT.type)
61 | }
62 |
63 | override fun setCurrentUserLoggedInMode(mode: LoggedInMode) {
64 | mPrefs.putAny(PREF_KEY_USER_LOGGED_IN_MODE, mode.type)
65 |
66 | }
67 |
68 | override fun getAccessToken(): String? {
69 | return mPrefs.getString(PREF_KEY_ACCESS_TOKEN, null)
70 | }
71 |
72 | override fun setAccessToken(accessToken: String?) {
73 | mPrefs.putAny(PREF_KEY_ACCESS_TOKEN, accessToken)
74 | }
75 |
76 |
77 | override fun setUserLoggedIn(
78 | userId: String,
79 | userName: String,
80 | email: String,
81 | accessToken: String,
82 | profile: String
83 | ) {
84 |
85 | setCurrentUserId(userId)
86 | setCurrentUserName(userName)
87 | setCurrentUserEmail(email)
88 | setCurrentUserProfilePicUrl(profile)
89 | setAccessToken(accessToken)
90 | setCurrentUserLoggedInMode(LoggedInMode.LOGGED_IN_MODE_SERVER)
91 | }
92 |
93 | override fun updateUserInfo(
94 | accessToken: String?,
95 | userId: String?,
96 | loggedInMode: LoggedInMode,
97 | userName: String?,
98 | email: String?,
99 | profilePicPath: String?
100 | ) {
101 | setAccessToken(accessToken)
102 | setCurrentUserId(userId ?:"-1")
103 | setCurrentUserLoggedInMode(loggedInMode)
104 | setCurrentUserName(userName)
105 | setCurrentUserEmail(email)
106 | setCurrentUserProfilePicUrl(profilePicPath)
107 |
108 | }
109 |
110 | override fun clearAll() {
111 | mPrefs.edit().clear().apply()
112 | }
113 |
114 | private fun SharedPreferences.putAny(name: String, any: Any?) {
115 | when (any) {
116 | is String -> edit().putString(name, any).apply()
117 | is Int -> edit().putInt(name, any).apply()
118 | is Boolean -> edit().putBoolean(name,any).apply()
119 | is Float -> edit().putFloat(name,any).apply()
120 | }
121 | }
122 |
123 | private fun SharedPreferences.remove(name:String){
124 | edit().remove(name).apply()
125 | }
126 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/mvvmKotlinJetpackCompose/data/prefs/PreferencesHelper.kt:
--------------------------------------------------------------------------------
1 | package com.example.mvvmKotlinJetpackCompose.data.prefs
2 |
3 | import com.example.mvvmKotlinJetpackCompose.util.LoggedInMode
4 |
5 |
6 | interface PreferencesHelper {
7 |
8 | suspend fun getCurrentUserLoggedInMode(): Int?
9 |
10 | fun setCurrentUserLoggedInMode(mode: LoggedInMode)
11 |
12 | fun getCurrentUserId(): String?
13 |
14 | fun setCurrentUserId(userId: String?)
15 |
16 | fun getCurrentUserName(): String?
17 |
18 | fun setCurrentUserName(userName: String?)
19 |
20 | fun getCurrentUserEmail(): String?
21 |
22 | fun setCurrentUserEmail(email: String?)
23 |
24 | fun getCurrentUserProfilePicUrl(): String?
25 |
26 | fun setCurrentUserProfilePicUrl(profilePicUrl: String?)
27 |
28 | fun getAccessToken(): String?
29 |
30 | fun setAccessToken(accessToken: String?)
31 | fun setUserLoggedIn(
32 | userId: String,
33 | userName: String,
34 | email: String,
35 | accessToken: String,
36 | profile: String = ""
37 | )
38 |
39 | fun updateUserInfo(
40 | accessToken: String?,
41 | userId: String?,
42 | loggedInMode: LoggedInMode,
43 | userName: String?,
44 | email: String?,
45 | profilePicPath: String?)
46 |
47 | fun clearAll()
48 |
49 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/mvvmKotlinJetpackCompose/data/repos/DashboardRepository.kt:
--------------------------------------------------------------------------------
1 | package com.example.mvvmKotlinJetpackCompose.data.repos
2 |
3 | import com.example.mvvmKotlinJetpackCompose.data.network.ApiHelper
4 | import com.example.mvvmKotlinJetpackCompose.data.network.Resource
5 | import com.example.mvvmKotlinJetpackCompose.data.network.model.DashboardResponse
6 | import com.example.mvvmKotlinJetpackCompose.data.prefs.PreferencesHelper
7 | import com.example.mvvmKotlinJetpackCompose.ui.base.BaseRepository
8 | import com.example.mvvmKotlinJetpackCompose.util.LoggedInMode
9 | import com.example.mvvmKotlinJetpackCompose.util.coroutines.DispatcherProvider
10 | import kotlinx.coroutines.flow.flow
11 | import kotlinx.coroutines.flow.flowOn
12 | import javax.inject.Inject
13 |
14 | class DashboardRepository @Inject constructor(
15 | appDispatcher: DispatcherProvider,
16 | apiHelper: ApiHelper,
17 | preferencesHelper: PreferencesHelper,
18 | ) : BaseRepository(appDispatcher,apiHelper, preferencesHelper) {
19 |
20 | fun logout() {
21 |
22 | flow {
23 | setUserAsLoggedOut()
24 | }.flowOn(getAppDispatcher().computation())
25 |
26 | }
27 |
28 | suspend fun getDashboardData(): Resource {
29 |
30 | return getApiHelper().getDashboardData()
31 |
32 | }
33 |
34 |
35 | private fun setUserAsLoggedOut() {
36 | getPreferencesHelper().updateUserInfo(
37 | null,
38 | null,
39 | LoggedInMode.LOGGED_IN_MODE_LOGGED_OUT,
40 | null,
41 | null,
42 | null
43 | )
44 | }
45 |
46 |
47 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/mvvmKotlinJetpackCompose/data/repos/LoginRepository.kt:
--------------------------------------------------------------------------------
1 | package com.example.mvvmKotlinJetpackCompose.data.repos
2 |
3 | import com.example.mvvmKotlinJetpackCompose.data.network.ApiHelper
4 | import com.example.mvvmKotlinJetpackCompose.data.network.DataError
5 | import com.example.mvvmKotlinJetpackCompose.data.network.Resource
6 | import com.example.mvvmKotlinJetpackCompose.data.network.model.LoginResponse
7 | import com.example.mvvmKotlinJetpackCompose.data.prefs.PreferencesHelper
8 | import com.example.mvvmKotlinJetpackCompose.di.login.LoginScope
9 | import com.example.mvvmKotlinJetpackCompose.ui.base.BaseRepository
10 | import com.example.mvvmKotlinJetpackCompose.util.coroutines.AppDispatcherProvider
11 | import com.example.mvvmKotlinJetpackCompose.util.coroutines.DispatcherProvider
12 | import kotlinx.coroutines.delay
13 | import kotlinx.coroutines.flow.Flow
14 | import kotlinx.coroutines.flow.flow
15 | import kotlinx.coroutines.flow.flowOn
16 | import javax.inject.Inject
17 |
18 | @LoginScope
19 | class LoginRepository @Inject constructor(
20 | appDispatcherProvider: DispatcherProvider,
21 | apiHelper: ApiHelper,
22 | preferencesHelper: PreferencesHelper,
23 | ) : BaseRepository(appDispatcherProvider,apiHelper, preferencesHelper) {
24 |
25 |
26 | fun login(email: String, password: String): Flow> {
27 | val loginResult = getApiHelper().login(email, password)
28 |
29 | loginResult.data?.let {
30 | if (it.status) {
31 | val loginResponse = loginResult.data
32 |
33 | if (loginResponse.status) {
34 | val userId = loginResponse.data.userId
35 | val token = loginResponse.data.token
36 | val userType = loginResponse.data.userType
37 |
38 | getPreferencesHelper().setUserLoggedIn(
39 | userId = userId,
40 | userName = userType,
41 | email = userId, accessToken = token
42 | )
43 | getApiHelper().updateToken(token)
44 |
45 | }
46 | } else {
47 | return flow {
48 | emit(DataError(loginResult.data.message))
49 | }
50 | }
51 | }
52 |
53 | return flow {
54 | emit(loginResult)
55 | }
56 | }
57 |
58 | suspend fun isUserLoggedIn(): Flow {
59 |
60 | return flow {
61 | delay(3000)
62 |
63 | emit(getPreferencesHelper().getCurrentUserLoggedInMode())
64 | }.flowOn(getAppDispatcher().computation())
65 |
66 | }
67 |
68 |
69 |
70 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/mvvmKotlinJetpackCompose/di/AppModule.kt:
--------------------------------------------------------------------------------
1 | package com.example.mvvmKotlinJetpackCompose.di
2 |
3 | import com.example.mvvmKotlinJetpackCompose.data.network.ApiHelper
4 | import com.example.mvvmKotlinJetpackCompose.data.network.AppApiHelper
5 | import com.example.mvvmKotlinJetpackCompose.data.prefs.AppPreferencesHelper
6 | import com.example.mvvmKotlinJetpackCompose.data.prefs.PreferencesHelper
7 | import com.example.mvvmKotlinJetpackCompose.ui.base.BaseRepository
8 | import com.example.mvvmKotlinJetpackCompose.data.repos.DashboardRepository
9 | import com.example.mvvmKotlinJetpackCompose.util.PREF_NAME
10 | import com.example.mvvmKotlinJetpackCompose.util.coroutines.AppDispatcherProvider
11 | import com.example.mvvmKotlinJetpackCompose.util.coroutines.DispatcherProvider
12 | import dagger.Binds
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 | abstract class AppModule {
22 |
23 | companion object{
24 | @Provides
25 | @PreferenceInfo
26 | fun providePreferenceName(): String {
27 | return PREF_NAME
28 | }
29 |
30 | @Provides
31 | @EmptyString
32 | fun provideApiKey(): String {
33 | return ""
34 | }
35 |
36 | }
37 |
38 | @Binds
39 | @Singleton
40 | abstract fun provideApiHelper(appApiHelper: AppApiHelper): ApiHelper
41 |
42 | @Binds
43 | @Singleton
44 | abstract fun providePreferenceHelper(appPreferencesHelper: AppPreferencesHelper): PreferencesHelper
45 |
46 |
47 | @Binds
48 | @Singleton
49 | abstract fun provideDispatcher(dispatcherProvider: AppDispatcherProvider): DispatcherProvider
50 |
51 | @Binds
52 | @Singleton
53 | abstract fun provideDashboardRepo(dashboardRepository: DashboardRepository): BaseRepository
54 |
55 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/mvvmKotlinJetpackCompose/di/EmptyString.java:
--------------------------------------------------------------------------------
1 |
2 | package com.example.mvvmKotlinJetpackCompose.di;
3 |
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 |
7 | import javax.inject.Qualifier;
8 |
9 |
10 | @Qualifier
11 | @Retention(RetentionPolicy.RUNTIME)
12 | public @interface EmptyString {
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/mvvmKotlinJetpackCompose/di/ExternalLibAppModule.kt:
--------------------------------------------------------------------------------
1 | package com.example.mvvmKotlinJetpackCompose.di
2 |
3 | import com.example.mvvmKotlinJetpackCompose.BuildConfig
4 | import com.example.mvvmKotlinJetpackCompose.data.network.*
5 | import com.example.mvvmKotlinJetpackCompose.data.network.moshiFactories.MyKotlinJsonAdapterFactory
6 | import com.example.mvvmKotlinJetpackCompose.data.network.moshiFactories.MyStandardJsonAdapters
7 | import com.squareup.moshi.Moshi
8 | import dagger.Provides
9 | import dagger.Module
10 | import dagger.hilt.InstallIn
11 | import dagger.hilt.components.SingletonComponent
12 | import okhttp3.Interceptor
13 | import okhttp3.OkHttpClient
14 | import okhttp3.logging.HttpLoggingInterceptor
15 | import retrofit2.Retrofit
16 | import retrofit2.converter.moshi.MoshiConverterFactory
17 | import java.util.concurrent.TimeUnit
18 | import javax.inject.Singleton
19 |
20 | @Module
21 | @InstallIn(SingletonComponent::class)
22 | class ExternalLibAppModule {
23 |
24 | @Provides
25 | @Singleton
26 | fun provideHeaderInterceptor(protectedApiHeader : ApiHeader.ProtectedApiHeader): Interceptor{
27 | return Interceptor { chain ->
28 | val original = chain.request()
29 | val request = original.newBuilder()
30 | .header(contentType, contentTypeValue)
31 | .header("Authorization", "Bearer " + protectedApiHeader.accessToken)
32 | .method(original.method, original.body)
33 | .build()
34 |
35 | chain.proceed(request)
36 | }
37 |
38 | }
39 |
40 | @Provides
41 | @Singleton
42 | fun provideLoggingInterceptor(): HttpLoggingInterceptor {
43 | return HttpLoggingInterceptor().apply {
44 | if (BuildConfig.DEBUG) {
45 | level = HttpLoggingInterceptor.Level.BODY
46 | }
47 | }
48 | }
49 |
50 |
51 | @Provides
52 | @Singleton
53 | fun provideRetrofitClient(headerInterceptor : Interceptor,loggingInterceptor: HttpLoggingInterceptor) : OkHttpClient.Builder{
54 |
55 | val okHttpBuilder: OkHttpClient.Builder = OkHttpClient.Builder()
56 | okHttpBuilder.addInterceptor(headerInterceptor)
57 | okHttpBuilder.addInterceptor(loggingInterceptor)
58 | okHttpBuilder.connectTimeout(timeoutConnect.toLong(), TimeUnit.SECONDS)
59 | okHttpBuilder.readTimeout(timeoutRead.toLong(), TimeUnit.SECONDS)
60 | return okHttpBuilder
61 |
62 | }
63 |
64 | @Provides
65 | @Singleton
66 | fun provideRetrofit(okHttpBuilder: OkHttpClient.Builder, moshi: Moshi):Retrofit{
67 | return Retrofit.Builder()
68 | .baseUrl(baseUrl)
69 | .client(okHttpBuilder.build())
70 | .addConverterFactory(MoshiConverterFactory.create(moshi))
71 | .build()
72 | }
73 |
74 | @Provides
75 | @Singleton
76 | fun provideService(retrofit: Retrofit): Service {
77 | return retrofit.create(Service::class.java)
78 | }
79 |
80 |
81 | @Provides
82 | @Singleton
83 | fun provideMoshi():Moshi{
84 | return Moshi.Builder()
85 | .add(MyStandardJsonAdapters.FACTORY)
86 | .add(MyKotlinJsonAdapterFactory()).build()
87 | }
88 |
89 |
90 |
91 |
92 |
93 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/mvvmKotlinJetpackCompose/di/PreferenceInfo.java:
--------------------------------------------------------------------------------
1 |
2 | package com.example.mvvmKotlinJetpackCompose.di;
3 |
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 |
7 | import javax.inject.Qualifier;
8 |
9 |
10 | @Qualifier
11 | @Retention(RetentionPolicy.RUNTIME)
12 | public @interface PreferenceInfo {
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/mvvmKotlinJetpackCompose/di/login/LoginComponent.kt:
--------------------------------------------------------------------------------
1 | package com.example.mvvmKotlinJetpackCompose.di.login
2 |
3 | import com.example.mvvmKotlinJetpackCompose.di.login.LoginScope
4 | import dagger.hilt.DefineComponent
5 | import dagger.hilt.components.SingletonComponent
6 |
7 | @LoginScope
8 | @DefineComponent(parent = SingletonComponent::class)
9 | interface LoginComponent {
10 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/mvvmKotlinJetpackCompose/di/login/LoginComponentBuilder.kt:
--------------------------------------------------------------------------------
1 | package com.example.mvvmKotlinJetpackCompose.di.login
2 |
3 | import com.example.mvvmKotlinJetpackCompose.data.repos.LoginRepository
4 | import dagger.BindsInstance
5 | import dagger.hilt.DefineComponent
6 |
7 | @DefineComponent.Builder
8 | interface LoginComponentBuilder {
9 | fun bindLoginRepo(@BindsInstance loginRepository: LoginRepository): LoginComponentBuilder
10 | fun build(): LoginComponent?
11 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/mvvmKotlinJetpackCompose/di/login/LoginComponentManager.kt:
--------------------------------------------------------------------------------
1 | package com.example.mvvmKotlinJetpackCompose.di.login
2 |
3 | import com.example.mvvmKotlinJetpackCompose.data.network.ApiHelper
4 | import com.example.mvvmKotlinJetpackCompose.data.prefs.PreferencesHelper
5 | import com.example.mvvmKotlinJetpackCompose.data.repos.LoginRepository
6 | import com.example.mvvmKotlinJetpackCompose.util.coroutines.AppDispatcherProvider
7 | import com.example.mvvmKotlinJetpackCompose.util.coroutines.DispatcherProvider
8 | import javax.inject.Inject
9 | import javax.inject.Provider
10 | import javax.inject.Singleton
11 |
12 | @Singleton
13 | class LoginComponentManager @Inject constructor(
14 | private val appDispatcherProvider: DispatcherProvider,
15 | private val loginComponentProvider: Provider,
16 | private val apiHelper: ApiHelper,
17 | private val preferencesHelper: PreferencesHelper,
18 | )
19 | {
20 |
21 | var loginComponent: LoginComponent? = null
22 |
23 |
24 | fun getComponent():LoginComponent{
25 | if(loginComponent==null){
26 | val loginRepository = LoginRepository(appDispatcherProvider, apiHelper, preferencesHelper)
27 | loginComponent= loginComponentProvider.get().bindLoginRepo(loginRepository).build()
28 |
29 | }
30 |
31 | return loginComponent!!
32 | }
33 |
34 | fun destroyLoginComponent() {
35 | loginComponent = null
36 | }
37 | }
38 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/mvvmKotlinJetpackCompose/di/login/LoginEntryPoint.kt:
--------------------------------------------------------------------------------
1 | package com.example.mvvmKotlinJetpackCompose.di.login
2 |
3 | import com.example.mvvmKotlinJetpackCompose.data.repos.LoginRepository
4 | import dagger.hilt.EntryPoint
5 | import dagger.hilt.InstallIn
6 |
7 | @EntryPoint
8 | @InstallIn(LoginComponent::class)
9 | interface LoginEntryPoint {
10 | fun getLoginRepo(): LoginRepository
11 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/mvvmKotlinJetpackCompose/di/login/LoginScope.kt:
--------------------------------------------------------------------------------
1 | package com.example.mvvmKotlinJetpackCompose.di.login
2 |
3 | import javax.inject.Scope
4 |
5 | @Scope
6 | @Retention(value = AnnotationRetention.RUNTIME)
7 | annotation class LoginScope
--------------------------------------------------------------------------------
/app/src/main/java/com/example/mvvmKotlinJetpackCompose/ui/ViewModelFactory.kt:
--------------------------------------------------------------------------------
1 | package com.example.mvvmKotlinJetpackCompose.ui
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.ViewModelProvider
5 | import androidx.lifecycle.viewmodel.CreationExtras
6 | import com.example.mvvmKotlinJetpackCompose.data.repos.LoginRepository
7 | import com.example.mvvmKotlinJetpackCompose.ui.login.LoginViewModel
8 | import com.example.mvvmKotlinJetpackCompose.ui.splash.SplashViewModel
9 | import com.example.mvvmKotlinJetpackCompose.util.coroutines.DispatcherProvider
10 |
11 |
12 | class ViewModelFactory(
13 | private val repository: LoginRepository,
14 | ) : ViewModelProvider.Factory {
15 |
16 | @Suppress("UNCHECKED_CAST")
17 | override fun create(
18 | modelClass: Class,
19 | extras: CreationExtras
20 | ): T {
21 | if (modelClass.isAssignableFrom(LoginViewModel::class.java)) {
22 | return LoginViewModel(repository) as T
23 | }
24 | if (modelClass.isAssignableFrom(SplashViewModel::class.java)) {
25 | return SplashViewModel(repository) as T
26 | }
27 | throw IllegalArgumentException("Unknown ViewModel class")
28 | }
29 |
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/mvvmKotlinJetpackCompose/ui/base/BaseComponentActivity.kt:
--------------------------------------------------------------------------------
1 | package com.example.mvvmKotlinJetpackCompose.ui.base
2 |
3 |
4 | import android.content.Context
5 | import android.content.Intent
6 | import android.os.Bundle
7 | import androidx.activity.ComponentActivity
8 | import androidx.activity.compose.setContent
9 | import androidx.compose.foundation.background
10 | import androidx.compose.foundation.layout.Box
11 | import androidx.compose.foundation.layout.size
12 | import androidx.compose.foundation.shape.RoundedCornerShape
13 | import androidx.compose.material.*
14 | import androidx.compose.runtime.Composable
15 | import androidx.compose.runtime.livedata.observeAsState
16 | import androidx.compose.ui.Alignment
17 | import androidx.compose.ui.Modifier
18 | import androidx.compose.ui.graphics.Color
19 | import androidx.compose.ui.res.stringResource
20 | import androidx.compose.ui.unit.dp
21 | import androidx.compose.ui.unit.sp
22 | import androidx.compose.ui.window.Dialog
23 | import androidx.compose.ui.window.DialogProperties
24 | import com.example.mvvmKotlinJetpackCompose.R
25 | import com.example.mvvmKotlinJetpackCompose.data.network.DataError
26 | import com.example.mvvmKotlinJetpackCompose.data.network.Success
27 | import com.example.mvvmKotlinJetpackCompose.ui.theme.CoinTheme
28 | import com.example.mvvmKotlinJetpackCompose.ui.theme.White
29 |
30 | abstract class BaseComponentActivity> : ComponentActivity() {
31 |
32 | abstract val viewModel: VM
33 |
34 | //override in child class if you don't want to use global loading state
35 | open val wantToShowCustomLoading = false
36 |
37 | override fun onCreate(savedInstanceState: Bundle?) {
38 | super.onCreate(savedInstanceState)
39 | setContent {
40 | CoinTheme {
41 | ProvideCompose()
42 | SetUpLoadingDialog()
43 | SetUpErrorDialog()
44 | }
45 | }
46 |
47 |
48 | }
49 |
50 | @Composable
51 | private fun SetUpLoadingDialog() {
52 | if (!wantToShowCustomLoading) {
53 | val loadingValue = viewModel.showDialogLoadingPrivate.observeAsState()
54 |
55 | if (loadingValue.value == true) {
56 | ShowLoading()
57 | }
58 | }
59 |
60 | }
61 |
62 | @Composable
63 | private fun SetUpErrorDialog() {
64 | var dialogState = false
65 | var errorDescription = ""
66 | val vmLoadinState = viewModel.showMessageDialog.observeAsState()
67 | when (vmLoadinState.value) {
68 | is DataError -> {
69 | errorDescription = (vmLoadinState.value as DataError).errorDescription
70 | dialogState = true
71 | }
72 |
73 | is Success -> {
74 | dialogState = false
75 | }
76 |
77 | else -> {}
78 | }
79 | if (dialogState) {
80 | ShowErrorDialog(errorDescription)
81 |
82 | }
83 |
84 |
85 | }
86 |
87 |
88 | @Composable
89 | protected open fun ShowLoading() {
90 |
91 | Dialog(
92 | onDismissRequest = { viewModel.hideLoading() },
93 | DialogProperties(dismissOnBackPress = false, dismissOnClickOutside = false)
94 | ) {
95 | Box(
96 | contentAlignment = Alignment.Center,
97 | modifier = Modifier
98 | .size(100.dp)
99 | .background(White, shape = RoundedCornerShape(8.dp))
100 | ) {
101 | CircularProgressIndicator()
102 | }
103 | }
104 | }
105 |
106 |
107 | @Composable
108 | private fun ShowErrorDialog(errorDescription: String) {
109 |
110 | AlertDialog(
111 | onDismissRequest = {
112 | },
113 |
114 | title = {
115 | Text(stringResource(R.string.error), style = MaterialTheme.typography.h4)
116 | },
117 | text = {
118 | Text(errorDescription, fontSize = 16.sp)
119 | },
120 | confirmButton = {
121 | },
122 |
123 | dismissButton = {
124 | TextButton(
125 | onClick = {
126 | viewModel.hideMessageDialog(Success(""))
127 | }) {
128 | Text(
129 | "Ok",
130 | style = MaterialTheme.typography.body1,
131 | color = MaterialTheme.colors.onSecondary
132 | )
133 | }
134 | },
135 | backgroundColor = MaterialTheme.colors.secondary,
136 | contentColor = Color.White
137 | )
138 |
139 | }
140 |
141 |
142 | @Composable
143 | abstract fun ProvideCompose()
144 |
145 | @Composable
146 | abstract fun ProvideComposeLightPreview()
147 |
148 |
149 | inline fun Context.startActivity(block: Intent.() -> Unit = {}) {
150 |
151 | startActivity(Intent(this, T::class.java).apply(block))
152 | }
153 |
154 |
155 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/mvvmKotlinJetpackCompose/ui/base/BaseRepository.kt:
--------------------------------------------------------------------------------
1 | package com.example.mvvmKotlinJetpackCompose.ui.base
2 |
3 | import com.example.mvvmKotlinJetpackCompose.data.network.ApiHelper
4 | import com.example.mvvmKotlinJetpackCompose.data.prefs.PreferencesHelper
5 | import com.example.mvvmKotlinJetpackCompose.util.coroutines.DispatcherProvider
6 |
7 |
8 | open class BaseRepository(
9 | private val appDispatcher: DispatcherProvider,
10 | private val apiHelper: ApiHelper,
11 | private val preferencesHelper: PreferencesHelper
12 | ) {
13 |
14 | fun getAppDispatcher(): DispatcherProvider {
15 | return appDispatcher
16 | }
17 |
18 | fun getApiHelper(): ApiHelper {
19 |
20 | return apiHelper
21 | }
22 |
23 | fun getPreferencesHelper(): PreferencesHelper {
24 | return preferencesHelper
25 | }
26 |
27 | fun getUserId(): String {
28 | return getPreferencesHelper().getCurrentUserId() ?: ""
29 |
30 | }
31 |
32 |
33 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/mvvmKotlinJetpackCompose/ui/base/BaseUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.mvvmKotlinJetpackCompose.ui.base
2 |
3 | import com.example.mvvmKotlinJetpackCompose.util.coroutines.DispatcherProvider
4 |
5 | open class BaseUseCase( private val repository: R, private val appDispatcher: DispatcherProvider) {
6 | // add any common business logic
7 |
8 | fun getRepository():R{
9 | return repository
10 | }
11 |
12 | fun getAppDispatcher(): DispatcherProvider {
13 | return appDispatcher
14 | }
15 |
16 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/mvvmKotlinJetpackCompose/ui/base/BaseViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.example.mvvmKotlinJetpackCompose.ui.base
2 |
3 | import androidx.annotation.VisibleForTesting
4 | import androidx.annotation.VisibleForTesting.Companion.PRIVATE
5 | import androidx.lifecycle.LiveData
6 | import androidx.lifecycle.MutableLiveData
7 | import androidx.lifecycle.ViewModel
8 | import com.example.mvvmKotlinJetpackCompose.data.network.DataError
9 | import com.example.mvvmKotlinJetpackCompose.data.network.Resource
10 | import com.example.mvvmKotlinJetpackCompose.data.network.Success
11 | import com.example.mvvmKotlinJetpackCompose.util.SOMETHING_WENT_WRONG
12 | import com.example.mvvmKotlinJetpackCompose.util.coroutines.DispatcherProvider
13 | import kotlinx.coroutines.CoroutineExceptionHandler
14 |
15 | open class BaseViewModel(
16 | val anyType:T,
17 | ) : ViewModel() {
18 |
19 | @VisibleForTesting(otherwise = PRIVATE)
20 | val showDialogLoadingPrivate = MutableLiveData(false)
21 |
22 | val showMessageDialog = MutableLiveData>()
23 |
24 | private val onErrorDialogDismissPrivate = MutableLiveData>()
25 | val onErrorDialogDismiss: LiveData> get() = onErrorDialogDismissPrivate
26 |
27 | protected val exceptionHandler = CoroutineExceptionHandler { context, exception ->
28 | hideLoading()
29 | showMessageDialog(DataError(SOMETHING_WENT_WRONG))
30 |
31 | }
32 |
33 |
34 | fun isLoading(): Boolean {
35 | return showDialogLoadingPrivate.value!!
36 | }
37 |
38 |
39 | fun showLoading() {
40 | if (!showDialogLoadingPrivate.value!!) {
41 | showDialogLoadingPrivate.value = true
42 | }
43 |
44 | }
45 |
46 | fun hideLoading() {
47 | if (showDialogLoadingPrivate.value!!) {
48 | showDialogLoadingPrivate.value = false
49 | }
50 | }
51 |
52 |
53 |
54 |
55 | fun showMessageDialog(dataError: DataError) {
56 | showMessageDialog.value = dataError
57 | }
58 |
59 | fun showPostMessageDialog(dataError: DataError) {
60 | showMessageDialog.value = dataError
61 | }
62 |
63 | fun hideMessageDialog(success: Success) {
64 | showMessageDialog.value = success
65 |
66 | }
67 |
68 |
69 |
70 | }
71 |
72 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/mvvmKotlinJetpackCompose/ui/base/BaseViewModelRepository.kt:
--------------------------------------------------------------------------------
1 | package com.example.mvvmKotlinJetpackCompose.ui.base
2 |
3 | import com.example.mvvmKotlinJetpackCompose.util.coroutines.DispatcherProvider
4 |
5 |
6 | open class BaseViewModelRepository(repo : T )
7 | : BaseViewModel(repo){
8 |
9 |
10 | fun getRepository() : T{
11 |
12 | return anyType
13 | }
14 |
15 |
16 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/mvvmKotlinJetpackCompose/ui/base/BaseViewModelUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.mvvmKotlinJetpackCompose.ui.base
2 |
3 | import com.example.mvvmKotlinJetpackCompose.util.coroutines.DispatcherProvider
4 |
5 |
6 | open class BaseViewModelUseCase(private val useCase: T)
7 | : BaseViewModel(useCase){
8 |
9 |
10 | fun getUseCase() : T{
11 |
12 | return useCase
13 | }
14 |
15 |
16 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/mvvmKotlinJetpackCompose/ui/dashboard/DashboardActivity.kt:
--------------------------------------------------------------------------------
1 | package com.example.mvvmKotlinJetpackCompose.ui.dashboard
2 |
3 | import android.content.res.Configuration.UI_MODE_NIGHT_NO
4 | import androidx.activity.viewModels
5 | import androidx.compose.foundation.ExperimentalFoundationApi
6 | import androidx.compose.foundation.layout.fillMaxWidth
7 | import androidx.compose.foundation.shape.RoundedCornerShape
8 | import androidx.compose.material.*
9 | import androidx.compose.runtime.*
10 | import androidx.compose.ui.Modifier
11 | import androidx.compose.ui.res.painterResource
12 | import androidx.compose.ui.text.style.TextAlign
13 | import androidx.compose.ui.tooling.preview.Preview
14 | import androidx.compose.ui.unit.dp
15 | import androidx.navigation.compose.NavHost
16 | import androidx.navigation.compose.composable
17 | import androidx.navigation.compose.currentBackStackEntryAsState
18 | import androidx.navigation.compose.rememberNavController
19 | import com.example.mvvmKotlinJetpackCompose.R
20 | import com.example.mvvmKotlinJetpackCompose.data.network.DataError
21 | import com.example.mvvmKotlinJetpackCompose.data.network.Success
22 | import com.example.mvvmKotlinJetpackCompose.data.network.model.DashboardResponse
23 | import com.example.mvvmKotlinJetpackCompose.data.others.MenuItem
24 | import com.example.mvvmKotlinJetpackCompose.ui.base.BaseComponentActivity
25 | import com.example.mvvmKotlinJetpackCompose.ui.dashboard.compose.BottomNavData
26 | import com.example.mvvmKotlinJetpackCompose.ui.dashboard.compose.TopBar
27 | import com.example.mvvmKotlinJetpackCompose.ui.login.LoginActivity
28 | import com.example.mvvmKotlinJetpackCompose.util.observe
29 | import dagger.hilt.android.AndroidEntryPoint
30 |
31 | @AndroidEntryPoint
32 | class DashboardActivity : BaseComponentActivity() {
33 |
34 | override val viewModel: DashboardViewModel by viewModels()
35 |
36 |
37 |
38 | @ExperimentalFoundationApi
39 | @Composable
40 | override fun ProvideCompose() {
41 |
42 | val dashboardData = remember {
43 | mutableStateOf(DashboardResponse.Data())
44 | }
45 |
46 |
47 | val userId = remember { mutableStateOf("") }
48 |
49 | observe(viewModel.userIdData) {
50 | when (it) {
51 | is Success -> {
52 | userId.value = it.data!!
53 | }
54 | else -> {}
55 | }
56 | }
57 |
58 | observe(viewModel.dashboardData) {
59 | when (it) {
60 | is DataError -> {
61 |
62 | }
63 | is Success -> {
64 | it.data.let {
65 | dashboardData.value = it!!.data
66 | }
67 | }
68 | }
69 | }
70 |
71 | observe(viewModel.logoutData) {
72 | when (it.getContentIfNotHandled()) {
73 | is DataError -> println()
74 | is Success -> {
75 | startActivity()
76 | finish()
77 | }
78 | else -> {}
79 | }
80 |
81 | }
82 |
83 | val navController = rememberNavController()
84 | val navBackStackEntry by navController.currentBackStackEntryAsState()
85 | val currentRoute = navBackStackEntry?.destination?.route
86 |
87 | SetUpDashboardCompose(dashboardData.value,
88 | userId.value,
89 | currentRoute,
90 | {
91 | navController.navigate(it) {
92 | // Pop up to the start destination of the graph to
93 | // avoid building up a large stack of destinations
94 | // on the back stack as users select items
95 | navController.graph.startDestinationRoute?.let { route ->
96 | popUpTo(route) {
97 | saveState = true
98 | }
99 | }
100 | // Avoid multiple copies of the same destination when
101 | // reselecting the same item
102 | launchSingleTop = true
103 | // Restore state when reselecting a previously selected item
104 | restoreState = true
105 | }
106 |
107 | }) {
108 |
109 | NavHost(navController = navController,
110 | startDestination = BottomNavData.Home.route) {
111 |
112 | composable(route = BottomNavData.Home.route) {
113 | DashboardContent(viewModel.getMenuData()) {
114 |
115 | }
116 |
117 | }
118 |
119 | composable(route = BottomNavData.History.route) {
120 | Text(text = "History",
121 | modifier = Modifier.fillMaxWidth(),
122 | textAlign = TextAlign.Center)
123 | }
124 |
125 | composable(route = BottomNavData.Other.route) {
126 | Text(text = "Other",
127 | modifier = Modifier.fillMaxWidth(),
128 | textAlign = TextAlign.Center)
129 |
130 | }
131 |
132 |
133 |
134 | }
135 | }
136 |
137 |
138 | }
139 |
140 | @ExperimentalFoundationApi
141 | @Composable
142 | private fun SetUpDashboardCompose(
143 | dashboardData: DashboardResponse.Data,
144 | userId: String,
145 | currentRoute: String?,
146 | onItemClick: (String)->Unit={},
147 | SetupNavHost: @Composable () -> Unit,
148 | ) {
149 | val scaffoldState =
150 | rememberScaffoldState(rememberDrawerState(DrawerValue.Closed))
151 | val scope = rememberCoroutineScope()
152 |
153 | Scaffold(scaffoldState = scaffoldState,
154 | topBar = {
155 | TopBar(scope,
156 | scaffoldState,
157 | dashboardData.liqrToINR)
158 | },
159 | drawerShape = RoundedCornerShape(0.dp),
160 | drawerContent = {
161 | DrawerCompose(scope, scaffoldState,
162 | dashboardData.balanceLiqr.toString(),
163 | userId) { viewModel.logout() }
164 | },
165 | bottomBar = {
166 | BottomNavigation(
167 | backgroundColor = MaterialTheme.colors.onSecondary,
168 | contentColor = MaterialTheme.colors.onSecondary
169 | ) {
170 |
171 | val items=BottomNavData.values()
172 | items.forEach {
173 | BottomNavigationItem(
174 | icon = {
175 | Icon(painterResource(it.iconId ) ,
176 | contentDescription =it.title)
177 | },
178 | label = { Text(text = it.title) },
179 | selectedContentColor = MaterialTheme.colors.secondary,
180 | unselectedContentColor = MaterialTheme.colors.primary
181 | ,
182 | alwaysShowLabel = true,
183 | selected = currentRoute==it.route,
184 | onClick = {
185 | onItemClick(it.route)
186 |
187 | }
188 | )
189 | }
190 |
191 | }
192 |
193 |
194 | }) {
195 |
196 | SetupNavHost()
197 |
198 | }
199 | }
200 |
201 |
202 | @ExperimentalFoundationApi
203 | @Preview(showBackground = true,
204 | uiMode = UI_MODE_NIGHT_NO)
205 | @Composable
206 | override fun ProvideComposeLightPreview() {
207 |
208 | //jetpack compose compiler sometimes shows different colors
209 | SetUpDashboardCompose(DashboardResponse.Data(), "userId",
210 | "") {
211 |
212 | DashboardContent(listOf(
213 | MenuItem(R.drawable.ic_prepaid, "Prepaid"),
214 | MenuItem(R.drawable.ic_postpaid, "PostPaid"),
215 | MenuItem(R.drawable.ic_dtf, "Dth"),
216 | MenuItem(R.drawable.ic_datacard, "DataCard"),
217 | MenuItem(R.drawable.ic_gas, "Gas"),
218 | MenuItem(R.drawable.ic_water, "Water"),
219 | MenuItem(R.drawable.ic_electricity, "Electricity"),
220 | MenuItem(R.drawable.ic_billpayment, "Bill Payment"),
221 | MenuItem(R.drawable.ic_fund_recieve, "Fun receive"),
222 | MenuItem(R.drawable.ic_bus, "bus"),
223 | MenuItem(R.drawable.ic_flight, "flight"),
224 | MenuItem(R.drawable.ic_hotel_booking, "Hotel booking"),
225 | ))
226 | }
227 | }
228 |
229 |
230 | }
231 |
232 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/mvvmKotlinJetpackCompose/ui/dashboard/DashboardUseCase.kt:
--------------------------------------------------------------------------------
1 | package com.example.mvvmKotlinJetpackCompose.ui.dashboard
2 |
3 | import com.example.mvvmKotlinJetpackCompose.data.network.Resource
4 | import com.example.mvvmKotlinJetpackCompose.data.network.model.DashboardResponse
5 | import com.example.mvvmKotlinJetpackCompose.data.repos.DashboardRepository
6 | import com.example.mvvmKotlinJetpackCompose.ui.base.BaseUseCase
7 | import com.example.mvvmKotlinJetpackCompose.util.coroutines.DispatcherProvider
8 | import kotlinx.coroutines.flow.Flow
9 | import kotlinx.coroutines.flow.flow
10 | import kotlinx.coroutines.flow.flowOn
11 | import javax.inject.Inject
12 |
13 | class DashboardUseCase @Inject constructor(
14 | appDispatcher: DispatcherProvider,
15 | dashboardRepository: DashboardRepository
16 | ) : BaseUseCase(dashboardRepository, appDispatcher) {
17 | //add dashboard business logic
18 | suspend fun getDashboardData(): Resource {
19 |
20 | return getRepository().getDashboardData()
21 | }
22 |
23 | fun getUserId(): String {
24 |
25 | return getRepository().getUserId()
26 | }
27 |
28 | fun logout(){
29 | getRepository().logout()
30 |
31 |
32 | }
33 |
34 |
35 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/mvvmKotlinJetpackCompose/ui/dashboard/DashboardViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.example.mvvmKotlinJetpackCompose.ui.dashboard
2 |
3 | import androidx.annotation.VisibleForTesting
4 | import androidx.annotation.VisibleForTesting.Companion.PRIVATE
5 | import androidx.lifecycle.LiveData
6 | import androidx.lifecycle.MutableLiveData
7 | import androidx.lifecycle.viewModelScope
8 | import com.example.mvvmKotlinJetpackCompose.R
9 | import com.example.mvvmKotlinJetpackCompose.data.network.Resource
10 | import com.example.mvvmKotlinJetpackCompose.data.network.Success
11 | import com.example.mvvmKotlinJetpackCompose.data.network.model.DashboardResponse
12 | import com.example.mvvmKotlinJetpackCompose.data.others.MenuItem
13 | import com.example.mvvmKotlinJetpackCompose.data.repos.DashboardRepository
14 | import com.example.mvvmKotlinJetpackCompose.ui.base.BaseViewModelUseCase
15 | import com.example.mvvmKotlinJetpackCompose.util.SingleEvent
16 | import com.example.mvvmKotlinJetpackCompose.util.coroutines.DispatcherProvider
17 | import dagger.hilt.android.lifecycle.HiltViewModel
18 | import kotlinx.coroutines.flow.flow
19 | import kotlinx.coroutines.flow.flowOn
20 | import kotlinx.coroutines.launch
21 | import javax.inject.Inject
22 |
23 | @HiltViewModel
24 | class DashboardViewModel @Inject constructor(
25 | dashboardUseCase: DashboardUseCase
26 | ) : BaseViewModelUseCase(dashboardUseCase) {
27 |
28 | @VisibleForTesting(otherwise = PRIVATE)
29 | val dashboardDataPrivate = MutableLiveData>()
30 | val dashboardData: LiveData> get() = dashboardDataPrivate
31 |
32 |
33 | @VisibleForTesting(otherwise = PRIVATE)
34 | val userIdDataPrivate = MutableLiveData>()
35 | val userIdData: LiveData> get() = userIdDataPrivate
36 |
37 |
38 | @VisibleForTesting(otherwise = PRIVATE)
39 | val logoutPrivate = MutableLiveData>>()
40 | val logoutData: LiveData>> get() = logoutPrivate
41 |
42 | // init {
43 | // getDashBoarData()
44 | // }
45 |
46 | fun getDashBoarData() {
47 |
48 | viewModelScope.launch(exceptionHandler) {
49 | showLoading()
50 |
51 | val dashboardData = getUseCase().getDashboardData()
52 | dashboardDataPrivate.value = dashboardData
53 |
54 | val userId = getUseCase().getUserId()
55 | userIdDataPrivate.value = Success(userId)
56 |
57 | hideLoading()
58 |
59 | }
60 | }
61 |
62 |
63 | fun getMenuData(): List