Skip to content

Commit

Permalink
feat: Notifications indicator on the learn tab (#75)
Browse files Browse the repository at this point in the history
- Notification badge on the learn tab
- Check notification count on pull to refresh

Fixes: LEARNER-10347
  • Loading branch information
farhan-arshad-dev authored Dec 24, 2024
1 parent 4ce0e6e commit 00280ec
Show file tree
Hide file tree
Showing 31 changed files with 292 additions and 34 deletions.
5 changes: 4 additions & 1 deletion app/src/main/java/org/openedx/app/di/AppModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import com.google.android.play.core.review.ReviewManagerFactory
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import kotlinx.coroutines.Dispatchers
import org.openedx.notifications.PushManager
import org.koin.android.ext.koin.androidApplication
import org.koin.core.qualifier.named
import org.koin.dsl.module
Expand Down Expand Up @@ -48,6 +47,7 @@ import org.openedx.core.presentation.global.app_upgrade.AppUpgradeRouter
import org.openedx.core.system.AppCookieManager
import org.openedx.core.system.CalendarManager
import org.openedx.core.system.PushGlobalManager
import org.openedx.core.system.notifier.PushNotifier
import org.openedx.core.system.ResourceManager
import org.openedx.core.system.connection.NetworkConnection
import org.openedx.core.system.notifier.CourseNotifier
Expand All @@ -67,6 +67,7 @@ import org.openedx.discovery.presentation.DiscoveryRouter
import org.openedx.discussion.presentation.DiscussionAnalytics
import org.openedx.discussion.presentation.DiscussionRouter
import org.openedx.discussion.system.notifier.DiscussionNotifier
import org.openedx.notifications.PushManager
import org.openedx.profile.data.storage.ProfilePreferences
import org.openedx.profile.presentation.ProfileAnalytics
import org.openedx.profile.presentation.ProfileRouter
Expand Down Expand Up @@ -115,6 +116,7 @@ val appModule = module {
single { DownloadNotifier() }
single { VideoNotifier() }
single { DiscoveryNotifier() }
single { PushNotifier() }
single { IAPNotifier() }

single { AppRouter() }
Expand Down Expand Up @@ -206,6 +208,7 @@ val appModule = module {
single<WhatsNewAnalytics> { get<AnalyticsManager>() }
single<IAPAnalytics> { get<AnalyticsManager>() }

single { PushManager(get()) }
single<PushGlobalManager> { get<PushManager>() }

factory { AgreementProvider(get(), get()) }
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/org/openedx/app/di/NetworkingModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import org.koin.core.qualifier.named
import org.koin.dsl.module
import org.openedx.app.data.api.NotificationsApi
import org.openedx.app.data.networking.AppUpgradeInterceptor
import org.openedx.app.data.networking.HandleErrorInterceptor
import org.openedx.app.data.networking.HeadersInterceptor
Expand All @@ -17,6 +16,7 @@ import org.openedx.core.data.api.CourseApi
import org.openedx.core.data.api.iap.InAppPurchasesApi
import org.openedx.discovery.data.api.DiscoveryApi
import org.openedx.discussion.data.api.DiscussionApi
import org.openedx.notifications.data.api.NotificationsApi
import org.openedx.profile.data.api.ProfileApi
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
Expand Down
9 changes: 8 additions & 1 deletion app/src/main/java/org/openedx/app/di/ScreenModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ import org.openedx.discussion.presentation.threads.DiscussionAddThreadViewModel
import org.openedx.discussion.presentation.threads.DiscussionThreadsViewModel
import org.openedx.discussion.presentation.topics.DiscussionTopicsViewModel
import org.openedx.learn.presentation.LearnViewModel
import org.openedx.notifications.data.repository.NotificationsRepository
import org.openedx.notifications.domain.interactor.NotificationsInteractor
import org.openedx.profile.data.repository.ProfileRepository
import org.openedx.profile.domain.interactor.ProfileInteractor
import org.openedx.profile.domain.model.Account
Expand Down Expand Up @@ -152,6 +154,7 @@ val screenModule = module {
get(),
get(),
get(),
get(),
)
}

Expand All @@ -169,11 +172,12 @@ val screenModule = module {
get(),
get(),
windowSize,
get(),
)
}
viewModel { AllEnrolledCoursesViewModel(get(), get(), get(), get(), get(), get(), get()) }
viewModel { (openTab: String) ->
LearnViewModel(openTab, get(), get(), get())
LearnViewModel(openTab, get(), get(), get(), get(), get())
}

factory { DiscoveryRepository(get(), get(), get()) }
Expand Down Expand Up @@ -478,6 +482,9 @@ val screenModule = module {
)
}

single { NotificationsRepository(get()) }
factory { NotificationsInteractor(get()) }

single { IAPRepository(get()) }
factory { IAPInteractor(get(), get(), get(), get(), get()) }
viewModel { (purchaseFlowData: PurchaseFlowData) ->
Expand Down
5 changes: 5 additions & 0 deletions core/src/main/java/org/openedx/core/config/Config.kt
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ class Config(context: Context) {
return getObjectOrNewInstance(DASHBOARD, DashboardConfig::class.java)
}

fun isPushNotificationsEnabled(): Boolean {
return getBoolean(PUSH_NOTIFICATIONS_ENABLED, false)
}

fun getBranchConfig(): BranchConfig {
return getObjectOrNewInstance(BRANCH, BranchConfig::class.java)
}
Expand Down Expand Up @@ -176,6 +180,7 @@ class Config(context: Context) {
private const val DISCOVERY = "DISCOVERY"
private const val PROGRAM = "PROGRAM"
private const val DASHBOARD = "DASHBOARD"
private const val PUSH_NOTIFICATIONS_ENABLED = "PUSH_NOTIFICATIONS_ENABLED"
private const val BRANCH = "BRANCH"
private const val UI_COMPONENTS = "UI_COMPONENTS"
private const val PLATFORM_NAME = "PLATFORM_NAME"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
package org.openedx.core.system

interface PushGlobalManager
interface PushGlobalManager {
suspend fun getUnreadNotificationsCount(): Int
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.openedx.core.system.notifier

import org.openedx.core.system.notifier.app.AppEvent

sealed class PushEvent : AppEvent {
data object RefreshBadgeCount : PushEvent()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.openedx.core.system.notifier

import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow

class PushNotifier {
private val channel = MutableSharedFlow<PushEvent>(replay = 0, extraBufferCapacity = 0)

val notifier: Flow<PushEvent> = channel.asSharedFlow()

suspend fun send(event: PushEvent.RefreshBadgeCount) = channel.emit(event)
}
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ fun DashboardGalleryView(
when (action) {
DashboardGalleryScreenAction.SwipeRefresh -> {
viewModel.updateCourses()
viewModel.refreshPushBadgeCount()
}

DashboardGalleryScreenAction.ViewAll -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ import org.openedx.core.system.notifier.CourseDataUpdated
import org.openedx.core.system.notifier.DiscoveryNotifier
import org.openedx.core.system.notifier.IAPNotifier
import org.openedx.core.system.notifier.NavigationToDiscovery
import org.openedx.core.system.notifier.PushEvent
import org.openedx.core.system.notifier.PushNotifier
import org.openedx.core.system.notifier.UpdateCourseData
import org.openedx.core.ui.WindowSize
import org.openedx.core.utils.FileUtil
Expand All @@ -57,9 +59,10 @@ class DashboardGalleryViewModel(
private val fileUtil: FileUtil,
private val dashboardRouter: DashboardRouter,
private val iapNotifier: IAPNotifier,
private val pushNotifier: PushNotifier,
private val iapInteractor: IAPInteractor,
private val iapAnalytics: IAPAnalytics,
private val windowSize: WindowSize,
iapAnalytics: IAPAnalytics,
) : BaseViewModel() {

val apiHostUrl get() = config.getApiHostURL()
Expand Down Expand Up @@ -147,6 +150,10 @@ class DashboardGalleryViewModel(
getCourses(isIAPFlow = isIAPFlow)
}

fun refreshPushBadgeCount() {
viewModelScope.launch { pushNotifier.send(PushEvent.RefreshBadgeCount) }
}

fun navigateToDiscovery() {
viewModelScope.launch { discoveryNotifier.send(NavigationToDiscovery()) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ class DashboardListFragment : Fragment() {
},
onSwipeRefresh = {
viewModel.updateCourses()
viewModel.refreshPushBadgeCount()
},
paginationCallback = {
viewModel.fetchMore()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ import org.openedx.core.system.notifier.CourseDashboardUpdate
import org.openedx.core.system.notifier.CourseDataUpdated
import org.openedx.core.system.notifier.DiscoveryNotifier
import org.openedx.core.system.notifier.IAPNotifier
import org.openedx.core.system.notifier.PushEvent
import org.openedx.core.system.notifier.PushNotifier
import org.openedx.core.system.notifier.UpdateCourseData
import org.openedx.core.system.notifier.app.AppNotifier
import org.openedx.core.system.notifier.app.AppUpgradeEvent
Expand All @@ -54,11 +56,12 @@ class DashboardListViewModel(
private val resourceManager: ResourceManager,
private val discoveryNotifier: DiscoveryNotifier,
private val iapNotifier: IAPNotifier,
private val pushNotifier: PushNotifier,
private val analytics: DashboardAnalytics,
private val appNotifier: AppNotifier,
private val preferencesManager: CorePreferences,
private val iapAnalytics: IAPAnalytics,
private val iapInteractor: IAPInteractor,
iapAnalytics: IAPAnalytics,
) : BaseViewModel() {

private val coursesList = mutableListOf<EnrolledCourse>()
Expand Down Expand Up @@ -174,6 +177,10 @@ class DashboardListViewModel(
}
}

fun refreshPushBadgeCount() {
viewModelScope.launch { pushNotifier.send(PushEvent.RefreshBadgeCount) }
}

fun processIAPAction(
fragmentManager: FragmentManager,
action: IAPAction,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.DropdownMenu
import androidx.compose.material.DropdownMenuItem
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
Expand All @@ -29,6 +30,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
Expand Down Expand Up @@ -74,10 +76,13 @@ class LearnFragment : Fragment(R.layout.fragment_learn) {
}, false
)
Header(
selectedLearnType = uiState.learnType,
uiState = uiState,
onUpdateLearnType = { learnType ->
viewModel.updateLearnType(learnType)
},
onNotificationBadgeClick = {
viewModel.onNotificationBadgeClick()
}
)
}
}
Expand Down Expand Up @@ -111,8 +116,9 @@ class LearnFragment : Fragment(R.layout.fragment_learn) {

@Composable
private fun Header(
selectedLearnType: LearnType,
onUpdateLearnType: (LearnType) -> Unit
uiState: LearnUIState,
onUpdateLearnType: (LearnType) -> Unit,
onNotificationBadgeClick: () -> Unit,
) {
val viewModel: LearnViewModel = koinViewModel()
val windowSize = rememberWindowSize()
Expand All @@ -135,13 +141,16 @@ private fun Header(
) {
Title(
label = stringResource(id = R.string.dashboard_learn),
showNotificationIcon = uiState.showNotificationIcon,
hasUnreadNotifications = uiState.hasUnreadNotifications,
onNotificationBadgeClick = onNotificationBadgeClick
)
if (viewModel.isProgramTypeWebView) {
LearnDropdownMenu(
modifier = Modifier
.align(Alignment.Start)
.padding(horizontal = 16.dp),
selectedLearnType = selectedLearnType,
selectedLearnType = uiState.learnType,
onUpdateLearnType = onUpdateLearnType
)
}
Expand All @@ -152,6 +161,9 @@ private fun Header(
private fun Title(
modifier: Modifier = Modifier,
label: String,
showNotificationIcon: Boolean = false,
hasUnreadNotifications: Boolean = false,
onNotificationBadgeClick: () -> Unit,
) {
Box(
modifier = modifier.fillMaxWidth()
Expand All @@ -164,6 +176,27 @@ private fun Title(
color = MaterialTheme.appColors.textDark,
style = MaterialTheme.appTypography.headlineBold
)
if (showNotificationIcon) {
IconButton(
modifier = Modifier
.align(Alignment.CenterEnd)
.padding(end = 12.dp),
onClick = {
onNotificationBadgeClick()
}
) {
val notificationIcon = if (hasUnreadNotifications) {
R.drawable.dashboard_ic_notification_bubble_badge
} else {
R.drawable.dashboard_ic_notification_badge
}
Icon(
painter = painterResource(id = notificationIcon),
tint = Color.Unspecified,
contentDescription = stringResource(id = R.string.dashboard_notification_badge)
)
}
}
}
}

Expand Down Expand Up @@ -249,7 +282,9 @@ private fun LearnDropdownMenu(
@Composable
private fun HeaderPreview() {
OpenEdXTheme {
Title(label = stringResource(id = R.string.dashboard_learn))
Title(label = stringResource(id = R.string.dashboard_learn),
showNotificationIcon = true,
onNotificationBadgeClick = {})
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@ package org.openedx.learn.presentation

import org.openedx.learn.LearnType

data class LearnUIState(val learnType: LearnType)
data class LearnUIState(
val learnType: LearnType,
val showNotificationIcon: Boolean = false,
val hasUnreadNotifications: Boolean = false
)
Loading

0 comments on commit 00280ec

Please sign in to comment.