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

Feature: educational videos #54

Merged
merged 84 commits into from
Jul 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
7f200a1
added OnboardingScreenPreview
Basler182 Jun 22, 2024
e41e638
added app screen navigation event
Basler182 Jun 28, 2024
f6d3058
added Route to App Screen and Video Detail
Basler182 Jun 28, 2024
07c946b
updated onConsented Target
Basler182 Jun 28, 2024
dd45165
changed to elevated card
Basler182 Jun 28, 2024
39eeb0e
added gitignore
Basler182 Jun 28, 2024
c7e89a0
added education module
Basler182 Jun 28, 2024
3d3d232
added NavigationItem
Basler182 Jun 28, 2024
07185c3
Merge branch 'main' into feature/educational-videos
Basler182 Jun 28, 2024
63747f3
added engage education repo and mapper
Basler182 Jun 28, 2024
a5e2f21
added app screen
Basler182 Jun 28, 2024
edfbdb4
updated main activity
Basler182 Jun 28, 2024
d8489fb
added education to build.gradle.kts
Basler182 Jun 28, 2024
07a3a0a
added home drawable
Basler182 Jun 28, 2024
1a4dca7
app ui state
Basler182 Jun 28, 2024
87982aa
updated app screen
Basler182 Jun 28, 2024
bff7499
updated MainActivityViewModel
Basler182 Jun 28, 2024
19fa7b5
tested MainActivityViewModel
Basler182 Jun 28, 2024
e4c7b78
added top app bar
Basler182 Jun 28, 2024
79335a5
added video screen
Basler182 Jun 29, 2024
705c0ff
added education screen
Basler182 Jun 29, 2024
8614fcc
added dependencies
Basler182 Jun 29, 2024
3b852fb
changed background color
Basler182 Jun 29, 2024
41bd71e
tested video
Basler182 Jun 29, 2024
5dac3f6
tested education view model
Basler182 Jun 29, 2024
51901e1
added test identifiers to education screen
Basler182 Jun 29, 2024
2729ba9
added modifier to ExpandableSection
Basler182 Jun 29, 2024
d2852b8
added EducationScreenSimulator
Basler182 Jun 29, 2024
b15275e
removed suppression
Basler182 Jun 30, 2024
49097ac
Merge branch 'main' into feature/educational-videos
Basler182 Jun 30, 2024
02fd3d1
updated AppScreen Navigation Test
Basler182 Jun 30, 2024
3bd22df
updated AppScreen Navigation Test
Basler182 Jun 30, 2024
ad0f9c4
optimized play icon
Basler182 Jun 30, 2024
d122916
fix detekt
Basler182 Jul 1, 2024
02ba156
fix detekt
Basler182 Jul 1, 2024
15eb63e
fix detekt
Basler182 Jul 1, 2024
64ee18f
fix detekt
Basler182 Jul 1, 2024
98495aa
fix detekt
Basler182 Jul 1, 2024
9b01d8a
fix detekt
Basler182 Jul 1, 2024
17b46dd
Merge branch 'main' into feature/educational-videos
Basler182 Jul 2, 2024
2b04295
added Ratios
Basler182 Jul 5, 2024
bf7316d
Merge branch 'feature/educational-videos' of https://github.com/Stanf…
Basler182 Jul 5, 2024
a9a6b8f
pass whole video to video detail screen
Basler182 Jul 5, 2024
07532ff
pass whole video to video detail screen
Basler182 Jul 5, 2024
37f73c2
added serialisation for navigation
Basler182 Jul 5, 2024
c41d902
pass entire video
Basler182 Jul 5, 2024
a6ba022
added Borders
Basler182 Jul 5, 2024
706dca4
changed ratio of video preview to 16:9
Basler182 Jul 5, 2024
a8acd6f
updated EducationUiState
Basler182 Jul 5, 2024
12782fb
extracted EducationRoutes
Basler182 Jul 5, 2024
8269738
removed VideoDetails Route from App
Basler182 Jul 5, 2024
a1f8c38
added saveStateHandle in ViewModel
Basler182 Jul 5, 2024
39094d4
updated VideoViewModelTest and EducationViewModelTest
Basler182 Jul 5, 2024
0897c7d
fix detekt format
Basler182 Jul 5, 2024
4e142d6
update video screen test to video
Basler182 Jul 5, 2024
947d9a9
tested video screen
Basler182 Jul 6, 2024
8823a5b
tested EducationScreen
Basler182 Jul 6, 2024
4900df8
moved pop back stack into navigator module
Basler182 Jul 6, 2024
73ee180
updated BottomBarItem to enum
Basler182 Jul 6, 2024
486ca21
removed not used Elevations
Basler182 Jul 6, 2024
090caee
removed not needed dependencies
Basler182 Jul 6, 2024
16df4dc
reused AppTopAppBar
Basler182 Jul 6, 2024
252e590
extracted image height to const
Basler182 Jul 6, 2024
26a2184
added missing params
Basler182 Jul 6, 2024
4392476
changed to lazy.items from indexed
Basler182 Jul 6, 2024
7573a43
extracted ExpandIcon
Basler182 Jul 6, 2024
31a83b1
moved popbackstack into setup
Basler182 Jul 6, 2024
79269cb
moved language into mapper
Basler182 Jul 6, 2024
4075f9d
removed entities with invalid nulls
Basler182 Jul 6, 2024
b2333a4
removed entities with invalid nulls
Basler182 Jul 6, 2024
c93efe4
tested app screen
Basler182 Jul 6, 2024
26d7233
adjusted borders, elevations, ratios, shapes and sizes
Basler182 Jul 6, 2024
7f6189a
adjusted borders, elevations, ratios, shapes and sizes
Basler182 Jul 6, 2024
45ef95e
adjusted education screen test
Basler182 Jul 6, 2024
3efcc64
removed unused update block
Basler182 Jul 6, 2024
7b57be1
trigger expand in view model
Basler182 Jul 6, 2024
9772073
renamed expandable video section
Basler182 Jul 6, 2024
51cc9a1
introduced uistate generic interface
Basler182 Jul 6, 2024
7435a96
handle video listener in view model
Basler182 Jul 6, 2024
519ebcf
tested top app bar
Basler182 Jul 6, 2024
c6e24e7
adjust app screen add additional test modifiers
Basler182 Jul 6, 2024
b6072a1
added and tested thumbnail url in video model
Basler182 Jul 6, 2024
3a3cc12
fix detekt
Basler182 Jul 6, 2024
27f6e14
fix detekt issues
eldcn Jul 7, 2024
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
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ dependencies {
implementation(project(":core:coroutines"))
implementation(project(":core:navigation"))
implementation(project(":modules:account"))
implementation(project(":modules:education"))
implementation(project(":modules:onboarding"))

implementation(libs.androidx.core.ktx)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,10 @@ class AppNavigationTest {
}

@Test
fun `test navigation to bluetooth screen`() {
fun `test navigation to app screen`() {
mainActivity {
navigateToBluetoothScreen()
assertBluetoothScreenIsDisplayed()
navigateToAppScreen()
assertAppScreenIsDisplayed()
}
}

Expand Down
62 changes: 62 additions & 0 deletions app/src/androidTest/kotlin/edu/stanford/bdh/engagehf/AppTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package edu.stanford.bdh.engagehf

import androidx.compose.ui.test.junit4.createAndroidComposeRule
import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
import edu.stanford.bdh.engagehf.navigation.screens.AppScreen
import edu.stanford.bdh.engagehf.simulator.AppSimulator
import edu.stanford.spezi.core.design.component.ComposeContentActivity
import org.junit.Before
import org.junit.Rule
import org.junit.Test

@HiltAndroidTest
class AppTest {

@get:Rule
val hiltRule = HiltAndroidRule(this)

@get:Rule
val composeTestRule = createAndroidComposeRule<ComposeContentActivity>()

@Before
fun init() {
composeTestRule.activity.setScreen {
AppScreen()
}
}

@Test
fun `test app screen root is displayed`() {
appScreen {
assertIsDisplayed()
}
}

@Test
fun `test app screen navigation bar items are displayed`() {
BottomBarItem.entries.forEach { item ->
appScreen {
assertNavigationBarItemIsDisplayed(composeTestRule.activity.getString(item.label))
}
}
}

@Test
fun `test app screen top app bar is displayed`() {
appScreen {
assertTopAppBarIsDisplayed()
}
}

@Test
fun `test app screen top app bar title is displayed`() {
appScreen {
assertTopAppBarTitleIsDisplayed(composeTestRule.activity.getString(BottomBarItem.entries.first().label))
}
}

private fun appScreen(block: AppSimulator.() -> Unit) {
AppSimulator(composeTestRule).apply(block)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package edu.stanford.bdh.engagehf.simulator

import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertTextEquals
import androidx.compose.ui.test.junit4.ComposeTestRule
import edu.stanford.bdh.engagehf.navigation.screens.AppScreenTestIdentifier
import edu.stanford.spezi.core.testing.onNodeWithIdentifier

class AppSimulator(
private val composeTestRule: ComposeTestRule,
) {
private val root = composeTestRule.onNodeWithIdentifier(AppScreenTestIdentifier.ROOT)

private val topAppBar =
composeTestRule.onNodeWithIdentifier(AppScreenTestIdentifier.TOP_APP_BAR)

private val topAppBarTitle =
composeTestRule.onNodeWithIdentifier(AppScreenTestIdentifier.TOP_APP_BAR_TITLE)

fun assertIsDisplayed() {
root.assertIsDisplayed()
}

fun assertTopAppBarIsDisplayed() {
topAppBar.assertIsDisplayed()
}

fun assertTopAppBarTitleIsDisplayed(text: String) {
topAppBarTitle.assertIsDisplayed()
.assertTextEquals(text)
}

fun assertNavigationBarItemIsDisplayed(text: String) {
composeTestRule
.onNodeWithIdentifier(AppScreenTestIdentifier.NAVIGATION_BAR_ITEM, text)
.assertIsDisplayed()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package edu.stanford.bdh.engagehf.simulator

import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.ComposeTestRule
import edu.stanford.bdh.engagehf.bluetooth.screen.BluetoothScreenTestIdentifier
import edu.stanford.bdh.engagehf.navigation.AppNavigationEvent
import edu.stanford.bdh.engagehf.navigation.screens.AppScreenTestIdentifier
import edu.stanford.spezi.core.navigation.Navigator
import edu.stanford.spezi.core.testing.onAllNodes
import edu.stanford.spezi.core.testing.onNodeWithIdentifier
Expand All @@ -29,17 +29,17 @@ class NavigatorSimulator(
composeTestRule.onNodeWithIdentifier(InvitationCodeScreenTestIdentifier.ROOT)
private val sequential =
composeTestRule.onNodeWithIdentifier(SequentialOnboardingScreenTestIdentifier.ROOT)
private val bluetooth = composeTestRule.onNodeWithIdentifier(BluetoothScreenTestIdentifier.ROOT)
private val appScreen = composeTestRule.onNodeWithIdentifier(AppScreenTestIdentifier.ROOT)
private val consent = composeTestRule.onNodeWithIdentifier(ConsentScreenTestIdentifier.ROOT)

fun assertOnboardingIsDisplayed() {
waitNode(OnboardingScreenTestIdentifier.ROOT)
onboarding.assertIsDisplayed()
}

fun assertBluetoothScreenIsDisplayed() {
waitNode(BluetoothScreenTestIdentifier.ROOT)
bluetooth.assertIsDisplayed()
fun assertAppScreenIsDisplayed() {
waitNode(AppScreenTestIdentifier.ROOT)
appScreen.assertIsDisplayed()
}

fun assertLoginScreenIsDisplayed() {
Expand Down Expand Up @@ -67,8 +67,8 @@ class NavigatorSimulator(
consent.assertIsDisplayed()
}

fun navigateToBluetoothScreen() {
navigator.navigateTo(AppNavigationEvent.BluetoothScreen)
fun navigateToAppScreen() {
navigator.navigateTo(AppNavigationEvent.AppScreen)
}

fun navigateToOnboardingScreen() {
Expand Down
30 changes: 26 additions & 4 deletions app/src/main/kotlin/edu/stanford/bdh/engagehf/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@
import androidx.navigation.compose.rememberNavController
import androidx.navigation.toRoute
import dagger.hilt.android.AndroidEntryPoint
import edu.stanford.bdh.engagehf.bluetooth.screen.BluetoothScreen
import edu.stanford.bdh.engagehf.navigation.AppNavigationEvent
import edu.stanford.bdh.engagehf.navigation.RegisterParams
import edu.stanford.bdh.engagehf.navigation.Routes
import edu.stanford.bdh.engagehf.navigation.screens.AppScreen
import edu.stanford.bdh.engagehf.navigation.serializableType
import edu.stanford.spezi.core.coroutines.di.Dispatching
import edu.stanford.spezi.core.design.theme.SpeziTheme
import edu.stanford.spezi.core.navigation.NavigationEvent
import edu.stanford.spezi.module.account.AccountNavigationEvent
import edu.stanford.spezi.module.account.login.LoginScreen
import edu.stanford.spezi.module.account.register.RegisterScreen
Expand All @@ -28,6 +29,10 @@
import edu.stanford.spezi.module.onboarding.invitation.InvitationCodeScreen
import edu.stanford.spezi.module.onboarding.onboarding.OnboardingScreen
import edu.stanford.spezi.module.onboarding.sequential.SequentialOnboardingScreen
import edu.stanford.spezi.modules.education.EducationNavigationEvent
import edu.stanford.spezi.modules.education.EducationRoutes
import edu.stanford.spezi.modules.education.video.VideoScreen
import edu.stanford.spezi.modules.education.videos.Video
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.launch
import javax.inject.Inject
Expand Down Expand Up @@ -82,8 +87,16 @@
LoginScreen(isAlreadyRegistered = args.isAlreadyRegistered)
}

composable<Routes.BluetoothScreen> {
BluetoothScreen()
composable<EducationRoutes.VideoDetail>(
typeMap = mapOf(
typeOf<Video>() to serializableType<Video>()
)
) {
VideoScreen()

Check warning on line 95 in app/src/main/kotlin/edu/stanford/bdh/engagehf/MainActivity.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/kotlin/edu/stanford/bdh/engagehf/MainActivity.kt#L95

Added line #L95 was not covered by tests
Basler182 marked this conversation as resolved.
Show resolved Hide resolved
}

composable<Routes.AppScreen> {
AppScreen()
}

composable<Routes.InvitationCodeScreen> {
Expand Down Expand Up @@ -125,7 +138,6 @@
)
)

is AppNavigationEvent.BluetoothScreen -> navHostController.navigate(Routes.BluetoothScreen)
is OnboardingNavigationEvent.InvitationCodeScreen -> navHostController.navigate(
Routes.InvitationCodeScreen
)
Expand All @@ -141,6 +153,16 @@
is OnboardingNavigationEvent.ConsentScreen -> navHostController.navigate(
Routes.ConsentScreen
)

is AppNavigationEvent.AppScreen -> navHostController.navigate(Routes.AppScreen)
is NavigationEvent.PopBackStack -> navHostController.popBackStack()
is NavigationEvent.NavigateUp -> navHostController.navigateUp()

is EducationNavigationEvent.VideoSectionClicked -> navHostController.navigate(
EducationRoutes.VideoDetail(
video = event.video

Check warning on line 163 in app/src/main/kotlin/edu/stanford/bdh/engagehf/MainActivity.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/kotlin/edu/stanford/bdh/engagehf/MainActivity.kt#L162-L163

Added lines #L162 - L163 were not covered by tests
)
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
package edu.stanford.bdh.engagehf

import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import edu.stanford.bdh.engagehf.navigation.AppNavigationEvent
import edu.stanford.bdh.engagehf.navigation.data.models.AppUiState
import edu.stanford.spezi.core.logging.speziLogger
import edu.stanford.spezi.core.navigation.NavigationEvent
import edu.stanford.spezi.core.navigation.Navigator
import edu.stanford.spezi.module.account.AccountEvents
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import javax.inject.Inject
import edu.stanford.spezi.core.design.R as DesignR

@HiltViewModel
class MainActivityViewModel @Inject constructor(
Expand All @@ -19,13 +26,23 @@
) : ViewModel() {
private val logger by speziLogger()

private val _uiState = MutableStateFlow(
AppUiState(
items = BottomBarItem.entries,
selectedItem = BottomBarItem.HOME
)
)

val uiState = _uiState.asStateFlow()

init {
viewModelScope.launch {
accountEvents.events.collect { event ->
when (event) {
is AccountEvents.Event.SignUpSuccess, AccountEvents.Event.SignInSuccess -> {
navigator.navigateTo(AppNavigationEvent.BluetoothScreen)
navigator.navigateTo(AppNavigationEvent.AppScreen)

Check warning on line 43 in app/src/main/kotlin/edu/stanford/bdh/engagehf/MainActivityViewModel.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/kotlin/edu/stanford/bdh/engagehf/MainActivityViewModel.kt#L43

Added line #L43 was not covered by tests
}

else -> {
logger.i { "Ignoring registration event: $event" }
}
Expand All @@ -34,5 +51,46 @@
}
}

fun onAction(action: Action) {
when (action) {
is Action.UpdateSelectedBottomBarItem -> {
_uiState.update {
it.copy(selectedItem = action.selectedBottomBarItem)
}
}
}
}

fun getNavigationEvents(): Flow<NavigationEvent> = navigator.events
}

sealed interface Action {
data class UpdateSelectedBottomBarItem(val selectedBottomBarItem: BottomBarItem) : Action
}

enum class BottomBarItem(
@StringRes val label: Int,
@DrawableRes val icon: Int,
@DrawableRes val selectedIcon: Int,
) {
HOME(
label = R.string.home,
icon = DesignR.drawable.ic_home,
selectedIcon = DesignR.drawable.ic_home
),
HEART_HEALTH(
label = R.string.heart_health,
icon = DesignR.drawable.ic_vital_signs,
selectedIcon = DesignR.drawable.ic_vital_signs
),
MEDICATION(
label = R.string.medication,
icon = DesignR.drawable.ic_medication,
selectedIcon = DesignR.drawable.ic_medication
),
EDUCATION(
label = R.string.education,
icon = DesignR.drawable.ic_school,
selectedIcon = DesignR.drawable.ic_school
),
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package edu.stanford.bdh.engagehf.education

import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import edu.stanford.spezi.modules.education.videos.data.repository.EducationRepository

@Module

Check warning on line 9 in app/src/main/kotlin/edu/stanford/bdh/engagehf/education/EducationModule.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/kotlin/edu/stanford/bdh/engagehf/education/EducationModule.kt#L9

Added line #L9 was not covered by tests
@InstallIn(SingletonComponent::class)
abstract class EducationModule {
@Binds
abstract fun bindEducationRepository(
engageEducationRepository: EngageEducationRepository,
): EducationRepository
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package edu.stanford.bdh.engagehf.education

import com.google.firebase.firestore.FirebaseFirestore
import edu.stanford.spezi.module.onboarding.invitation.await
import edu.stanford.spezi.modules.education.videos.VideoSection
import edu.stanford.spezi.modules.education.videos.data.repository.EducationRepository
import javax.inject.Inject

class EngageEducationRepository @Inject constructor(
private val firebaseFirestore: FirebaseFirestore,
Basler182 marked this conversation as resolved.
Show resolved Hide resolved
private val mapper: VideoSectionDocumentToVideoSectionMapper,

Check warning on line 11 in app/src/main/kotlin/edu/stanford/bdh/engagehf/education/EngageEducationRepository.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/kotlin/edu/stanford/bdh/engagehf/education/EngageEducationRepository.kt#L9-L11

Added lines #L9 - L11 were not covered by tests
) : EducationRepository {
override suspend fun getVideoSections(): Result<List<VideoSection>> {
return runCatching {
firebaseFirestore.collection("videoSections").get().await().mapNotNull { document ->
mapper.map(document)
}.sortedBy { it.orderIndex }

Check warning on line 17 in app/src/main/kotlin/edu/stanford/bdh/engagehf/education/EngageEducationRepository.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/kotlin/edu/stanford/bdh/engagehf/education/EngageEducationRepository.kt#L14-L17

Added lines #L14 - L17 were not covered by tests
}
}
}
Basler182 marked this conversation as resolved.
Show resolved Hide resolved
Loading
Loading