Skip to content

Commit

Permalink
Merge pull request #349 from PeriodPals/feat/misc/connectivity-banner
Browse files Browse the repository at this point in the history
Add connectivity banner to the bottom navigation menu
  • Loading branch information
lazarinibruno authored Dec 20, 2024
2 parents 0f3a1ef + 8564ce7 commit 2ddb7e5
Show file tree
Hide file tree
Showing 17 changed files with 240 additions and 66 deletions.
23 changes: 20 additions & 3 deletions app/src/main/java/com/android/periodpals/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import com.android.periodpals.model.user.UserAuthenticationState
import com.android.periodpals.model.user.UserRepositorySupabase
import com.android.periodpals.model.user.UserViewModel
import com.android.periodpals.services.GPSServiceImpl
import com.android.periodpals.services.NetworkChangeListener
import com.android.periodpals.services.PushNotificationsService
import com.android.periodpals.services.PushNotificationsServiceImpl
import com.android.periodpals.ui.alert.AlertListsScreen
Expand Down Expand Up @@ -72,6 +73,7 @@ class MainActivity : ComponentActivity() {
private lateinit var pushNotificationsService: PushNotificationsServiceImpl
private lateinit var chatViewModel: ChatViewModel
private lateinit var timerManager: TimerManager
private lateinit var networkChangeListener: NetworkChangeListener

private val supabaseClient =
createSupabaseClient(
Expand Down Expand Up @@ -107,6 +109,8 @@ class MainActivity : ComponentActivity() {
PushNotificationsServiceImpl(this, authenticationViewModel, userViewModel)
timerManager = TimerManager(this)
timerViewModel = TimerViewModel(timerModel, timerManager)
networkChangeListener = NetworkChangeListener(this)
networkChangeListener.startListening()

// Initialize osmdroid configuration getSharedPreferences(this)
Configuration.getInstance().load(this, getSharedPreferences("osmdroid", Context.MODE_PRIVATE))
Expand Down Expand Up @@ -141,7 +145,7 @@ class MainActivity : ComponentActivity() {
timerViewModel,
chatClient,
chatViewModel,
)
networkChangeListener)
}
}
}
Expand All @@ -150,16 +154,19 @@ class MainActivity : ComponentActivity() {
override fun onStop() {
super.onStop()
gpsService.switchFromPreciseToApproximate()
networkChangeListener.stopListening()
}

override fun onRestart() {
super.onRestart()
gpsService.switchFromApproximateToPrecise()
networkChangeListener.startListening()
}

override fun onDestroy() {
super.onDestroy()
gpsService.cleanup()
networkChangeListener.stopListening()
}
}

Expand Down Expand Up @@ -192,6 +199,7 @@ fun PeriodPalsApp(
timerViewModel: TimerViewModel,
chatClient: ChatClient,
chatViewModel: ChatViewModel,
networkChangeListener: NetworkChangeListener
) {
val navController = rememberNavController()
val navigationActions = NavigationActions(navController)
Expand All @@ -217,6 +225,7 @@ fun PeriodPalsApp(
alertViewModel,
authenticationViewModel,
userViewModel,
networkChangeListener,
navigationActions,
)
}
Expand All @@ -232,6 +241,7 @@ fun PeriodPalsApp(
locationViewModel,
gpsService,
chatViewModel,
networkChangeListener,
navigationActions,
)
}
Expand Down Expand Up @@ -277,14 +287,20 @@ fun PeriodPalsApp(
// Map
navigation(startDestination = Screen.MAP, route = Route.MAP) {
composable(Screen.MAP) {
MapScreen(gpsService, authenticationViewModel, alertViewModel, navigationActions)
MapScreen(
gpsService,
authenticationViewModel,
alertViewModel,
networkChangeListener,
navigationActions)
}
}

// Timer
navigation(startDestination = Screen.TIMER, route = Route.TIMER) {
composable(Screen.TIMER) {
TimerScreen(authenticationViewModel, timerViewModel, navigationActions)
TimerScreen(
authenticationViewModel, timerViewModel, networkChangeListener, navigationActions)
}
}

Expand All @@ -296,6 +312,7 @@ fun PeriodPalsApp(
authenticationViewModel,
pushNotificationsService,
chatViewModel,
networkChangeListener,
navigationActions,
)
}
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/com/android/periodpals/resources/C.kt
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ object C {
object BottomNavigationMenu {
const val BOTTOM_NAVIGATION_MENU = "bottomNavigationMenu"
const val BOTTOM_NAVIGATION_MENU_ITEM = "bottomNavigationMenu"
const val CONNECTIVITY_BANNER = "connectivityBanner"
const val CONNECTIVITY_BANNER_TEXT = "connectivityBannerText"
}

/** Constants for tagging UI components in the TopAppBar. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ private const val TAG = "NetworkChangeListener"
* @param context Activity context
*/
class NetworkChangeListener(context: Context) {
private var _isNetworkAvailable = MutableStateFlow(false)
private var _isNetworkAvailable = MutableStateFlow(true)
val isNetworkAvailable = _isNetworkAvailable.asStateFlow()

private val connectivityManager =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ import com.android.periodpals.resources.ComponentColor.getFilledPrimaryButtonCol
import com.android.periodpals.resources.ComponentColor.getPrimaryCardColors
import com.android.periodpals.resources.ComponentColor.getTertiaryCardColors
import com.android.periodpals.services.GPSServiceImpl
import com.android.periodpals.services.NetworkChangeListener
import com.android.periodpals.ui.components.FilterDialog
import com.android.periodpals.ui.components.FilterFab
import com.android.periodpals.ui.navigation.BottomNavigationMenu
Expand Down Expand Up @@ -117,6 +118,7 @@ fun AlertListsScreen(
locationViewModel: LocationViewModel,
gpsService: GPSServiceImpl,
chatViewModel: ChatViewModel,
networkChangeListener: NetworkChangeListener,
navigationActions: NavigationActions,
) {
var selectedTab by remember { mutableStateOf(SELECTED_TAB_DEFAULT) }
Expand Down Expand Up @@ -199,7 +201,7 @@ fun AlertListsScreen(
onTabSelect = { route -> navigationActions.navigateTo(route) },
tabList = LIST_TOP_LEVEL_DESTINATION,
selectedItem = navigationActions.currentRoute(),
)
networkChangeListener = networkChangeListener)
},
floatingActionButton = {
if (selectedTab == AlertListsTab.PALS_ALERTS) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import com.android.periodpals.resources.C
import com.android.periodpals.resources.C.Tag.AlertInputs
import com.android.periodpals.resources.ComponentColor.getFilledPrimaryContainerButtonColors
import com.android.periodpals.services.GPSServiceImpl
import com.android.periodpals.services.NetworkChangeListener
import com.android.periodpals.ui.components.ActionButton
import com.android.periodpals.ui.components.LocationField
import com.android.periodpals.ui.components.MessageField
Expand Down Expand Up @@ -78,6 +79,7 @@ fun CreateAlertScreen(
alertViewModel: AlertViewModel,
authenticationViewModel: AuthenticationViewModel,
userViewModel: UserViewModel,
networkChangeListener: NetworkChangeListener,
navigationActions: NavigationActions,
) {
val context = LocalContext.current
Expand Down Expand Up @@ -124,7 +126,7 @@ fun CreateAlertScreen(
onTabSelect = { route -> navigationActions.navigateTo(route) },
tabList = LIST_TOP_LEVEL_DESTINATION,
selectedItem = navigationActions.currentRoute(),
)
networkChangeListener = networkChangeListener)
},
containerColor = MaterialTheme.colorScheme.surface,
contentColor = MaterialTheme.colorScheme.onSurface,
Expand Down
5 changes: 4 additions & 1 deletion app/src/main/java/com/android/periodpals/ui/map/Map.kt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import com.android.periodpals.model.authentication.AuthenticationViewModel
import com.android.periodpals.model.location.Location
import com.android.periodpals.resources.C
import com.android.periodpals.services.GPSServiceImpl
import com.android.periodpals.services.NetworkChangeListener
import com.android.periodpals.ui.navigation.BottomNavigationMenu
import com.android.periodpals.ui.navigation.LIST_TOP_LEVEL_DESTINATION
import com.android.periodpals.ui.navigation.NavigationActions
Expand Down Expand Up @@ -67,6 +68,7 @@ fun MapScreen(
gpsService: GPSServiceImpl,
authenticationViewModel: AuthenticationViewModel,
alertViewModel: AlertViewModel,
networkChangeListener: NetworkChangeListener,
navigationActions: NavigationActions
) {

Expand Down Expand Up @@ -103,7 +105,8 @@ fun MapScreen(
BottomNavigationMenu(
onTabSelect = { route -> navigationActions.navigateTo(route) },
tabList = LIST_TOP_LEVEL_DESTINATION,
selectedItem = navigationActions.currentRoute())
selectedItem = navigationActions.currentRoute(),
networkChangeListener = networkChangeListener)
},
topBar = { TopAppBar(title = context.getString(R.string.map_screen_title)) },
floatingActionButton = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package com.android.periodpals.ui.navigation

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.layout.wrapContentSize
Expand All @@ -12,53 +16,88 @@ import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.NavigationBarItemDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.text.style.TextAlign
import com.android.periodpals.R
import com.android.periodpals.resources.C.Tag.BottomNavigationMenu
import com.android.periodpals.resources.C.Tag.BottomNavigationMenu.CONNECTIVITY_BANNER
import com.android.periodpals.resources.C.Tag.BottomNavigationMenu.CONNECTIVITY_BANNER_TEXT
import com.android.periodpals.services.NetworkChangeListener
import com.android.periodpals.ui.theme.dimens

@Composable
fun BottomNavigationMenu(
onTabSelect: (TopLevelDestination) -> Unit,
tabList: List<TopLevelDestination>,
selectedItem: String,
networkChangeListener: NetworkChangeListener
) {
NavigationBar(
modifier =
Modifier.fillMaxWidth()
.wrapContentHeight()
.testTag(BottomNavigationMenu.BOTTOM_NAVIGATION_MENU),
containerColor = MaterialTheme.colorScheme.surfaceContainerHighest,
contentColor = MaterialTheme.colorScheme.onSurface,
content = {
tabList.forEach { tab ->
NavigationBarItem(
selected = tab.route == selectedItem,
onClick = { onTabSelect(tab) },
icon = {
Icon(
imageVector = tab.icon,
contentDescription = null,
modifier = Modifier.size(MaterialTheme.dimens.iconSize))
},
modifier =
Modifier.wrapContentSize()
.clip(RoundedCornerShape(percent = MaterialTheme.dimens.roundedPercent))
.align(Alignment.CenterVertically)
.testTag(BottomNavigationMenu.BOTTOM_NAVIGATION_MENU_ITEM + tab.textId),
label = { Text(text = tab.textId, style = MaterialTheme.typography.labelSmall) },
colors =
NavigationBarItemDefaults.colors(
selectedIconColor = MaterialTheme.colorScheme.onSecondaryContainer,
selectedTextColor = MaterialTheme.colorScheme.onSecondaryContainer,
indicatorColor = MaterialTheme.colorScheme.secondaryContainer,
unselectedIconColor = MaterialTheme.colorScheme.onSurface,
unselectedTextColor = MaterialTheme.colorScheme.onSurface,
),
)
}
},
)

val isOnline by networkChangeListener.isNetworkAvailable.collectAsState()
val context = LocalContext.current

Column(modifier = Modifier.fillMaxWidth()) {
NavigationBar(
modifier =
Modifier.fillMaxWidth()
.wrapContentHeight()
.testTag(BottomNavigationMenu.BOTTOM_NAVIGATION_MENU),
containerColor = MaterialTheme.colorScheme.surfaceContainerHighest,
contentColor = MaterialTheme.colorScheme.onSurface,
content = {
tabList.forEach { tab ->
NavigationBarItem(
selected = tab.route == selectedItem,
onClick = { onTabSelect(tab) },
icon = {
Icon(
imageVector = tab.icon,
contentDescription = null,
modifier = Modifier.size(MaterialTheme.dimens.iconSize),
)
},
modifier =
Modifier.wrapContentSize()
.clip(RoundedCornerShape(percent = MaterialTheme.dimens.roundedPercent))
.align(Alignment.CenterVertically)
.testTag(BottomNavigationMenu.BOTTOM_NAVIGATION_MENU_ITEM + tab.textId),
label = { Text(text = tab.textId, style = MaterialTheme.typography.labelSmall) },
colors =
NavigationBarItemDefaults.colors(
selectedIconColor = MaterialTheme.colorScheme.onSecondaryContainer,
selectedTextColor = MaterialTheme.colorScheme.onSecondaryContainer,
indicatorColor = MaterialTheme.colorScheme.secondaryContainer,
unselectedIconColor = MaterialTheme.colorScheme.onSurface,
unselectedTextColor = MaterialTheme.colorScheme.onSurface,
),
)
}
},
)

// Offline bar
if (!isOnline) {
Box(
modifier =
Modifier.fillMaxWidth()
.height(MaterialTheme.dimens.small3)
.background(color = MaterialTheme.colorScheme.error)
.testTag(CONNECTIVITY_BANNER),
contentAlignment = Alignment.TopCenter,
) {
Text(
text = context.getString(R.string.bottom_bar_banner_text),
color = MaterialTheme.colorScheme.onError,
style = MaterialTheme.typography.bodySmall,
textAlign = TextAlign.Center,
modifier = Modifier.testTag(CONNECTIVITY_BANNER_TEXT))
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import com.android.periodpals.model.user.User
import com.android.periodpals.model.user.UserViewModel
import com.android.periodpals.resources.C.Tag.ProfileScreens.ProfileScreen
import com.android.periodpals.resources.ComponentColor.getTertiaryCardColors
import com.android.periodpals.services.NetworkChangeListener
import com.android.periodpals.services.PushNotificationsService
import com.android.periodpals.ui.components.ProfilePicture
import com.android.periodpals.ui.components.ProfileSection
Expand Down Expand Up @@ -74,6 +75,7 @@ fun ProfileScreen(
authenticationViewModel: AuthenticationViewModel,
notificationService: PushNotificationsService,
chatViewModel: ChatViewModel,
networkChangeListener: NetworkChangeListener,
navigationActions: NavigationActions
) {
val context = LocalContext.current
Expand Down Expand Up @@ -117,7 +119,7 @@ fun ProfileScreen(
onTabSelect = { route -> navigationActions.navigateTo(route) },
tabList = LIST_TOP_LEVEL_DESTINATION,
selectedItem = navigationActions.currentRoute(),
)
networkChangeListener = networkChangeListener)
},
containerColor = MaterialTheme.colorScheme.surface,
contentColor = MaterialTheme.colorScheme.onSurface,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import com.android.periodpals.resources.C.Tag.TimerScreen
import com.android.periodpals.resources.ComponentColor.getErrorButtonColors
import com.android.periodpals.resources.ComponentColor.getFilledPrimaryButtonColors
import com.android.periodpals.resources.ComponentColor.getInverseSurfaceButtonColors
import com.android.periodpals.services.NetworkChangeListener
import com.android.periodpals.ui.navigation.BottomNavigationMenu
import com.android.periodpals.ui.navigation.LIST_TOP_LEVEL_DESTINATION
import com.android.periodpals.ui.navigation.NavigationActions
Expand All @@ -75,6 +76,7 @@ private const val TAG = "TimerScreen"
fun TimerScreen(
authenticationViewModel: AuthenticationViewModel,
timerViewModel: TimerViewModel,
networkChangeListener: NetworkChangeListener,
navigationActions: NavigationActions,
) {
val authUserData by remember { mutableStateOf(authenticationViewModel.authUserData) }
Expand All @@ -98,7 +100,8 @@ fun TimerScreen(
BottomNavigationMenu(
onTabSelect = { route -> navigationActions.navigateTo(route) },
tabList = LIST_TOP_LEVEL_DESTINATION,
selectedItem = navigationActions.currentRoute())
selectedItem = navigationActions.currentRoute(),
networkChangeListener = networkChangeListener)
},
containerColor = MaterialTheme.colorScheme.surface,
contentColor = MaterialTheme.colorScheme.onSurface,
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,7 @@
<string name="title_activity_channel">ChannelActivity</string>
<string name="channel_screen_title">My Chats</string>

<!-- Timer Screen -->
<string name="bottom_bar_banner_text">No connection</string>

</resources>
Loading

0 comments on commit 2ddb7e5

Please sign in to comment.