Skip to content

Commit

Permalink
fix(ux/ui): sửa các lỗi nghiêm trọng liên quan đến hiệu suất, logic v…
Browse files Browse the repository at this point in the history
…à giao diện

todo: fix study schedule
  • Loading branch information
nqmgaming committed Dec 9, 2024
1 parent 538a07c commit adc1544
Show file tree
Hide file tree
Showing 19 changed files with 234 additions and 124 deletions.
57 changes: 0 additions & 57 deletions app/src/main/java/com/pwhs/quickmem/App.kt
Original file line number Diff line number Diff line change
@@ -1,34 +1,14 @@
package com.pwhs.quickmem

import android.app.Application
import com.google.firebase.messaging.FirebaseMessaging
import com.pwhs.quickmem.core.datastore.AppManager
import com.pwhs.quickmem.core.datastore.TokenManager
import com.pwhs.quickmem.data.dto.notification.DeviceTokenRequestDto
import com.pwhs.quickmem.data.remote.ApiService
import com.revenuecat.purchases.LogLevel
import com.revenuecat.purchases.Purchases
import com.revenuecat.purchases.PurchasesConfiguration
import dagger.hilt.android.HiltAndroidApp
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject

@HiltAndroidApp
class App : Application() {

@Inject
lateinit var tokenManager: TokenManager

@Inject
lateinit var appManager: AppManager

@Inject
lateinit var apiService: ApiService

override fun onCreate() {
super.onCreate()

Expand All @@ -43,42 +23,5 @@ class App : Application() {
apiKey = BuildConfig.REVENUECAT_API_KEY,
).build()
)
// Get FCM token
getFCMToken()
}

private fun getFCMToken() {
FirebaseMessaging.getInstance().token.addOnCompleteListener { task ->
if (!task.isSuccessful) {
Timber.w("Fetching FCM registration token failed", task.exception)
return@addOnCompleteListener
}

// Get new FCM registration token
val token = task.result
Timber.d("FCM Token: $token")
Purchases.sharedInstance.setPushToken(token)

// Send token to your server
sendTokenToServer(token)
}
}

private fun sendTokenToServer(token: String) {
CoroutineScope(Dispatchers.IO).launch {
val isLogged = appManager.isLoggedIn.firstOrNull() ?: false
if (!isLogged) {
return@launch
} else {
val accessToken = tokenManager.accessToken.firstOrNull() ?: ""
val userId = appManager.userId.firstOrNull() ?: ""
try {
apiService.sendDeviceToken(accessToken, DeviceTokenRequestDto(userId, token))
Timber.d("Token sent to server successfully.")
} catch (e: Exception) {
Timber.e(e, "Error sending token to server")
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.pwhs.quickmem.core.di
import com.pwhs.quickmem.data.local.repository.SearchQueryRepositoryImpl
import com.pwhs.quickmem.data.remote.repository.AuthRepositoryImpl
import com.pwhs.quickmem.data.remote.repository.ClassRepositoryImpl
import com.pwhs.quickmem.data.remote.repository.FirebaseRepositoryImpl
import com.pwhs.quickmem.data.remote.repository.FlashCardRepositoryImpl
import com.pwhs.quickmem.data.remote.repository.FolderRepositoryImpl
import com.pwhs.quickmem.data.remote.repository.NotificationRepositoryImpl
Expand All @@ -13,6 +14,7 @@ import com.pwhs.quickmem.data.remote.repository.StudyTimeRepositoryImpl
import com.pwhs.quickmem.data.remote.repository.UploadImageRepositoryImpl
import com.pwhs.quickmem.domain.repository.AuthRepository
import com.pwhs.quickmem.domain.repository.ClassRepository
import com.pwhs.quickmem.domain.repository.FirebaseRepository
import com.pwhs.quickmem.domain.repository.FlashCardRepository
import com.pwhs.quickmem.domain.repository.FolderRepository
import com.pwhs.quickmem.domain.repository.NotificationRepository
Expand Down Expand Up @@ -84,4 +86,9 @@ abstract class RepositoryModule {
abstract fun bindReportRepository(
reportRepositoryImpl: ReportRepositoryImpl
): ReportRepository

@Binds
abstract fun bindFirebaseRepository(
firebaseRepositoryImpl: FirebaseRepositoryImpl
): FirebaseRepository
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ data class UpdateFolderResponseDto(
val isPublic: Boolean,
@SerializedName("studySetCount")
val studySetCount: Int,
@SerializedName("owner")
@SerializedName("studySets")
val studySets: List<GetStudySetResponseDto>,
@SerializedName("linkShareCode")
val linkShareCode: String? = null,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.pwhs.quickmem.data.mapper.notification

import com.pwhs.quickmem.data.dto.notification.DeviceTokenRequestDto
import com.pwhs.quickmem.domain.model.notification.DeviceTokenRequestModel

fun DeviceTokenRequestModel.toDto() = DeviceTokenRequestDto(
userId = userId,
deviceToken = deviceToken
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.pwhs.quickmem.data.remote.repository

import com.pwhs.quickmem.core.utils.Resources
import com.pwhs.quickmem.data.mapper.notification.toDto
import com.pwhs.quickmem.data.remote.ApiService
import com.pwhs.quickmem.domain.model.notification.DeviceTokenRequestModel
import com.pwhs.quickmem.domain.repository.FirebaseRepository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import timber.log.Timber
import javax.inject.Inject

class FirebaseRepositoryImpl @Inject constructor(
private val apiService: ApiService
) : FirebaseRepository {
override suspend fun sendDeviceToken(
accessToken: String,
deviceTokenRequest: DeviceTokenRequestModel
): Flow<Resources<Unit>> {
return flow {
emit(Resources.Loading())
try {
apiService.sendDeviceToken(accessToken, deviceTokenRequest.toDto())
emit(Resources.Success(Unit))
} catch (e: Exception) {
Timber.e(e)
emit(Resources.Error(e.toString()))
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.pwhs.quickmem.domain.model.notification

data class DeviceTokenRequestModel(
val userId: String,
val deviceToken: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.pwhs.quickmem.domain.repository

import com.pwhs.quickmem.core.utils.Resources
import com.pwhs.quickmem.domain.model.notification.DeviceTokenRequestModel
import kotlinx.coroutines.flow.Flow


interface FirebaseRepository {
suspend fun sendDeviceToken(accessToken: String, deviceTokenRequest: DeviceTokenRequestModel): Flow<Resources<Unit>>
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import androidx.navigation.compose.currentBackStackEntryAsState
import com.pwhs.quickmem.R
import com.pwhs.quickmem.presentation.component.BottomSheetItem
import com.ramcosta.composedestinations.generated.NavGraphs
import com.ramcosta.composedestinations.generated.destinations.CreateClassScreenDestination
import com.ramcosta.composedestinations.generated.destinations.CreateFolderScreenDestination
import com.ramcosta.composedestinations.generated.destinations.CreateStudySetScreenDestination
Expand Down Expand Up @@ -135,6 +135,7 @@ fun StandardScaffold(
} else {
stringResource(item.title)
},
maxLines = 1,
style = typography.bodySmall.copy(
color = color,
fontWeight = if (currentDestination?.route?.contains(
Expand All @@ -144,7 +145,8 @@ fun StandardScaffold(
FontWeight.Bold
} else {
FontWeight.Normal
}
},
fontSize = 10.sp
),
)
},
Expand All @@ -159,9 +161,6 @@ fun StandardScaffold(
return@NavigationBarItem
}
navigator.navigate(item.direction) {
popUpTo(NavGraphs.root) {
saveState = true
}
launchSingleTop = true
restoreState = true
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ class EditClassViewModel @Inject constructor(
val classId: String = savedStateHandle["classId"] ?: ""
val classTitle = savedStateHandle["classTitle"] ?: ""
val classDescription = savedStateHandle["classDescription"] ?: ""
val allowSet: Boolean = savedStateHandle["allowSet"] ?: false
val allowMember: Boolean = savedStateHandle["allowMember"] ?: false
val allowSet: Boolean = savedStateHandle["isSetAllowed"] ?: false
val allowMember: Boolean = savedStateHandle["isMemberAllowed"] ?: false

_uiState.update {
it.copy(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ package com.pwhs.quickmem.presentation.app.home

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.google.firebase.messaging.FirebaseMessaging
import com.pwhs.quickmem.core.datastore.AppManager
import com.pwhs.quickmem.core.datastore.TokenManager
import com.pwhs.quickmem.core.utils.Resources
import com.pwhs.quickmem.domain.model.notification.DeviceTokenRequestModel
import com.pwhs.quickmem.domain.model.streak.StreakModel
import com.pwhs.quickmem.domain.model.subject.GetTop5SubjectResponseModel
import com.pwhs.quickmem.domain.model.subject.SubjectModel
import com.pwhs.quickmem.domain.repository.ClassRepository
import com.pwhs.quickmem.domain.repository.FirebaseRepository
import com.pwhs.quickmem.domain.repository.FolderRepository
import com.pwhs.quickmem.domain.repository.NotificationRepository
import com.pwhs.quickmem.domain.repository.StreakRepository
Expand All @@ -22,7 +25,6 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.update
Expand All @@ -39,6 +41,7 @@ class HomeViewModel @Inject constructor(
private val folderRepository: FolderRepository,
private val classRepository: ClassRepository,
private val notificationRepository: NotificationRepository,
private val firebaseRepository: FirebaseRepository,
private val tokenManager: TokenManager,
private val appManager: AppManager
) : ViewModel() {
Expand All @@ -55,25 +58,26 @@ class HomeViewModel @Inject constructor(
val userId = appManager.userId.firstOrNull() ?: ""
_uiState.value = HomeUiState(userId = userId)
initData()
getFCMToken()
}
}

private fun initData() {
job?.cancel()
job = viewModelScope.launch {
combine(tokenManager.accessToken, appManager.userId) { token, userId ->
token to userId
}.collect { (token, userId) ->
if (token?.isNotEmpty() == true && userId.isNotEmpty()) {
getRecentAccessStudySets(token = token, userId = userId)
getRecentAccessFolders(token = token, userId = userId)
getRecentAccessClasses(token = token, userId = userId)
getTop5Subjects(token = token)
getStreaksByUserId(token = token, userId = userId)
getCustomerInfo()
loadNotifications(token = token, userId = userId)
updateStreak(token = token, userId = userId)
}

val token = tokenManager.accessToken.firstOrNull() ?: ""
val userId = appManager.userId.firstOrNull() ?: ""

if (token.isNotEmpty() && userId.isNotEmpty()) {
getRecentAccessStudySets(token = token, userId = userId)
getRecentAccessFolders(token = token, userId = userId)
getRecentAccessClasses(token = token, userId = userId)
getTop5Subjects(token = token)
getStreaksByUserId(token = token, userId = userId)
getCustomerInfo()
loadNotifications(token = token, userId = userId)
updateStreak(token = token, userId = userId)
}
}
}
Expand Down Expand Up @@ -356,4 +360,50 @@ class HomeViewModel @Inject constructor(
}
}
}

private fun getFCMToken() {
FirebaseMessaging.getInstance().token.addOnCompleteListener { task ->
if (!task.isSuccessful) {
Timber.w("Fetching FCM registration token failed", task.exception)
return@addOnCompleteListener
}

// Get new FCM registration token
val token = task.result
Purchases.sharedInstance.setPushToken(token)

// Send token to your server
sendTokenToServer(token)
}
}

private fun sendTokenToServer(token: String) {
viewModelScope.launch {
val userId = appManager.userId.firstOrNull() ?: ""
val deviceTokenRequest = DeviceTokenRequestModel(
userId = userId,
deviceToken = token
)

val accessToken = tokenManager.accessToken.firstOrNull() ?: ""
firebaseRepository.sendDeviceToken(
accessToken = accessToken,
deviceTokenRequest = deviceTokenRequest
).collect { resource ->
when (resource) {
is Resources.Loading -> {
// do nothing
}

is Resources.Success -> {
// do nothing
}

is Resources.Error -> {
// do nothing
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ fun ClassHomeItem(
)
Text(
text = classItem?.owner?.username ?: "",
maxLines = 1,
overflow = TextOverflow.Ellipsis,
style = typography.bodyMedium.copy(
fontWeight = FontWeight.Bold
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,12 @@ fun FolderHomeItem(
)
Text(
text = userResponseModel.username,
style = typography.bodyMedium.copy(fontWeight = FontWeight.Bold),
color = colorScheme.onSurface
style = typography.bodyMedium.copy(
fontWeight = FontWeight.Bold,
color = colorScheme.onSurface,
),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
}
}
Expand Down
Loading

0 comments on commit adc1544

Please sign in to comment.