Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Add dropdown menu on NotificationsInboxFragment #80

Open
wants to merge 3 commits into
base: 2U/develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/src/main/java/org/openedx/app/AppRouter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import org.openedx.discussion.presentation.responses.DiscussionResponsesFragment
import org.openedx.discussion.presentation.search.DiscussionSearchThreadFragment
import org.openedx.discussion.presentation.threads.DiscussionAddThreadFragment
import org.openedx.discussion.presentation.threads.DiscussionThreadsFragment
import org.openedx.notifications.presentation.NotificationsRouter
import org.openedx.notifications.presentation.inbox.NotificationsInboxFragment
import org.openedx.notifications.presentation.settings.NotificationsSettingsFragment
import org.openedx.profile.domain.model.Account
Expand All @@ -58,7 +59,7 @@ import org.openedx.whatsnew.WhatsNewRouter
import org.openedx.whatsnew.presentation.whatsnew.WhatsNewFragment

class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, DiscussionRouter,
ProfileRouter, AppUpgradeRouter, WhatsNewRouter {
ProfileRouter, AppUpgradeRouter, WhatsNewRouter, NotificationsRouter {

//region AuthRouter
override fun navigateToMain(
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/org/openedx/app/di/AppModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ import org.openedx.discussion.system.notifier.DiscussionNotifier
import org.openedx.notifications.PushManager
import org.openedx.notifications.data.storage.NotificationsPreferences
import org.openedx.notifications.presentation.NotificationsAnalytics
import org.openedx.notifications.presentation.NotificationsRouter
import org.openedx.profile.data.storage.ProfilePreferences
import org.openedx.profile.presentation.ProfileAnalytics
import org.openedx.profile.presentation.ProfileRouter
Expand Down Expand Up @@ -132,6 +133,7 @@ val appModule = module {
single<WhatsNewRouter> { get<AppRouter>() }
single<AppUpgradeRouter> { get<AppRouter>() }
single { DeepLinkRouter(get(), get(), get(), get(), get(), get()) }
single<NotificationsRouter> { get<AppRouter>() }
HamzaIsrar12 marked this conversation as resolved.
Show resolved Hide resolved

single { NetworkConnection(get()) }

Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/org/openedx/app/di/ScreenModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ val screenModule = module {
single { NotificationsRepository(get()) }
factory { NotificationsInteractor(get()) }

viewModel { NotificationsInboxViewModel(get(), get()) }
viewModel { NotificationsInboxViewModel(get(), get(), get()) }
viewModel { NotificationsSettingsViewModel(get(), get(), get()) }

single { IAPRepository(get()) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package org.openedx.notifications.data.model
import com.google.gson.annotations.SerializedName

data class MarkNotificationReadBody(
@SerializedName("app_name")
val appName: String,
@SerializedName("notification_id")
val notificationId: Int,
val notificationId: Int?,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.openedx.notifications.data.model
HamzaIsrar12 marked this conversation as resolved.
Show resolved Hide resolved

import androidx.annotation.StringRes
import org.openedx.notifications.R

enum class NotificationsMenuType(@StringRes val title: Int) {
MARK_ALL_READ(R.string.notifications_menu_mark_all_read),
NOTIFICATION_SETTINGS(R.string.notifications_menu_settings),
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ class NotificationsRepository(
).message.isNotNull()
}

suspend fun markNotificationAsRead(notificationId: Int): Boolean {
suspend fun markNotificationAsRead(notificationId: Int?): Boolean {
return api.markNotificationAsRead(
MarkNotificationReadBody(
appName = APIConstants.APP_NAME_DISCUSSION,
notificationId = notificationId,
)
).message.isNotNull()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,8 @@ class NotificationsInteractor(
isDiscussionPushEnabled = isDiscussionPushEnabled,
)
}

suspend fun markAllNotificationsAsRead(): Boolean {
return repository.markNotificationAsRead(notificationId = null)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.openedx.notifications.presentation

import androidx.fragment.app.FragmentManager

interface NotificationsRouter {
fun navigateToPushNotificationsSettings(fm: FragmentManager)
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
HamzaIsrar12 marked this conversation as resolved.
Show resolved Hide resolved
import androidx.compose.material.CircularProgressIndicator
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.Scaffold
import androidx.compose.material.Surface
Expand All @@ -39,6 +41,7 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
Expand All @@ -63,15 +66,19 @@ import org.openedx.core.ui.HandleUIMessage
import org.openedx.core.ui.OpenEdXPrimaryButton
import org.openedx.core.ui.WindowSize
import org.openedx.core.ui.WindowType
import org.openedx.core.ui.crop
import org.openedx.core.ui.displayCutoutForLandscape
import org.openedx.core.ui.rememberWindowSize
import org.openedx.core.ui.shouldLoadMore
import org.openedx.core.ui.statusBarsInset
import org.openedx.core.ui.theme.AppShapes
import org.openedx.core.ui.theme.OpenEdXTheme
import org.openedx.core.ui.theme.appColors
import org.openedx.core.ui.theme.appShapes
import org.openedx.core.ui.theme.appTypography
import org.openedx.core.ui.windowSizeValue
import org.openedx.notifications.R
import org.openedx.notifications.data.model.NotificationsMenuType
import org.openedx.notifications.domain.model.InboxSection
import org.openedx.notifications.domain.model.NotificationContent
import org.openedx.notifications.domain.model.NotificationItem
Expand Down Expand Up @@ -104,8 +111,16 @@ class NotificationsInboxFragment : Fragment() {
onBackClick = {
requireActivity().supportFragmentManager.popBackStack()
},
onSettingsClick = {
onSettingsClick = { menuType ->
when (menuType) {
NotificationsMenuType.MARK_ALL_READ -> {
viewModel.markAllNotificationsAsRead()
}

NotificationsMenuType.NOTIFICATION_SETTINGS -> {
viewModel.navigateToPushNotificationsSettings(requireActivity().supportFragmentManager)
}
}
},
onReloadNotifications = {
viewModel.onReloadNotifications()
Expand All @@ -132,7 +147,7 @@ private fun InboxView(
uiMessage: UIMessage?,
canLoadMore: Boolean,
onBackClick: () -> Unit,
onSettingsClick: () -> Unit,
onSettingsClick: (NotificationsMenuType) -> Unit,
onReloadNotifications: () -> Unit,
paginationCallBack: () -> Unit,
markNotificationAsRead: (notificationItem: NotificationItem, inboxSection: InboxSection) -> Unit,
Expand Down Expand Up @@ -267,7 +282,7 @@ private fun InboxView(
private fun Header(
modifier: Modifier = Modifier,
onBackClick: () -> Unit,
onSettingsClick: () -> Unit,
onSettingsClick: (NotificationsMenuType) -> Unit,
) {
Box(
modifier = modifier
Expand All @@ -291,17 +306,14 @@ private fun Header(
overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.Center,
)
NotificationsDropdownMenu(
modifier = Modifier
.align(Alignment.CenterEnd)
.padding(end = 16.dp),
onItemClick = onSettingsClick
)


IconButton(
modifier = Modifier.align(Alignment.CenterEnd),
onClick = { onSettingsClick() }
) {
Icon(
imageVector = Icons.Default.MoreVert,
tint = MaterialTheme.appColors.primary,
contentDescription = stringResource(id = R.string.notifications_accessibility_settings)
)
}
}
}

Expand All @@ -324,6 +336,63 @@ private fun SectionHeader(
}
}

@Composable
private fun NotificationsDropdownMenu(
modifier: Modifier = Modifier,
onItemClick: (NotificationsMenuType) -> Unit,
) {
var expanded by remember { mutableStateOf(false) }

Column(
modifier = modifier.padding(vertical = 8.dp)
) {
Row(
modifier = Modifier
.clickable {
expanded = true
},
verticalAlignment = Alignment.CenterVertically
) {
Icon(
imageVector = Icons.Default.MoreVert,
tint = MaterialTheme.appColors.primary,
contentDescription = stringResource(id = R.string.notifications_accessibility_settings)
)
}

MaterialTheme(
colors = MaterialTheme.colors.copy(surface = MaterialTheme.appColors.background),
shapes = MaterialTheme.shapes.copy(MaterialTheme.appShapes.material.medium)
) {
DropdownMenu(
modifier = Modifier
.crop(vertical = 8.dp)
.widthIn(min = 182.dp)
.background(MaterialTheme.appColors.surface),
expanded = expanded,
onDismissRequest = { expanded = false }
) {
for (menuItem in NotificationsMenuType.entries) {
DropdownMenuItem(
modifier = Modifier
.background(MaterialTheme.appColors.surface),
onClick = {
onItemClick(menuItem)
expanded = false
}
) {
Text(
text = stringResource(id = menuItem.title),
style = MaterialTheme.appTypography.titleSmall,
color = MaterialTheme.appColors.textPrimary
)
}
}
}
}
}
}

@Composable
private fun NotificationItemView(
modifier: Modifier = Modifier,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.openedx.notifications.presentation.inbox

import androidx.fragment.app.FragmentManager
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
Expand All @@ -13,11 +14,13 @@ import org.openedx.core.system.ResourceManager
import org.openedx.notifications.domain.interactor.NotificationsInteractor
import org.openedx.notifications.domain.model.InboxSection
import org.openedx.notifications.domain.model.NotificationItem
import org.openedx.notifications.presentation.NotificationsRouter
import java.util.Date
import org.openedx.core.R as coreR

class NotificationsInboxViewModel(
private val interactor: NotificationsInteractor,
private val notificationsRouter: NotificationsRouter,
private val resourceManager: ResourceManager,
) : BaseViewModel() {

Expand Down Expand Up @@ -114,7 +117,7 @@ class NotificationsInboxViewModel(
) {
viewModelScope.launch {
try {
if (notification.isUnread() && interactor.markNotificationAsRead(notification.id)) {
if (interactor.markNotificationAsRead(notification.id)) {
HamzaIsrar12 marked this conversation as resolved.
Show resolved Hide resolved
val currentSection = notifications[inboxSection] ?: return@launch

val index = currentSection.indexOfFirst { it.id == notification.id }
Expand Down Expand Up @@ -150,4 +153,26 @@ class NotificationsInboxViewModel(
)
}
}

fun navigateToPushNotificationsSettings(fm: FragmentManager) {
notificationsRouter.navigateToPushNotificationsSettings(fm)
}

fun markAllNotificationsAsRead() {
HamzaIsrar12 marked this conversation as resolved.
Show resolved Hide resolved
viewModelScope.launch {
try {
interactor.markAllNotificationsAsRead()

notifications.forEach { (section, notificationItems) ->
notifications[section] =
notificationItems.map { it.copy(lastRead = Date()) }.toMutableList()
}
HamzaIsrar12 marked this conversation as resolved.
Show resolved Hide resolved

_uiState.value = InboxUIState.Data(notifications = notifications.toMap())
HamzaIsrar12 marked this conversation as resolved.
Show resolved Hide resolved
} catch (e: Exception) {
e.printStackTrace()
emitErrorMessage(e)
}
}
}
}
3 changes: 3 additions & 0 deletions notifications/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
<string name="notification_now">Now</string>
<string name="notifications_no_notifications_yet">No notifications yet</string>
<string name="notifications_no_notifications_yet_description">When you receive notifications they’ll show up here</string>

<string name="notifications_menu_settings">Notification Settings</string>
HamzaIsrar12 marked this conversation as resolved.
Show resolved Hide resolved
<string name="notifications_menu_mark_all_read">Mark all as read</string>
<plurals name="notifications_date_format_seconds">
<item quantity="one">%1$s second</item>
<item quantity="other">%1$s seconds</item>
Expand Down
Loading