Skip to content

Commit

Permalink
Merge branch 'develop' of https://github.com/Rd4dev/oppia-android int…
Browse files Browse the repository at this point in the history
…o code_coverage_many_to_one_targets
  • Loading branch information
Rd4dev committed Jul 24, 2024
2 parents f170487 + d2db9df commit 8955775
Show file tree
Hide file tree
Showing 115 changed files with 2,831 additions and 528 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/static_checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ jobs:
run: |
bash /home/runner/work/oppia-android/oppia-android/scripts/ktlint_lint_check.sh $HOME
- name: Feature flag checks
run: |
bash /home/runner/work/oppia-android/oppia-android/scripts/feature_flags_check.sh $HOME
- name: Protobuf lint check
run: |
bash /home/runner/work/oppia-android/oppia-android/scripts/buf_lint_check.sh $HOME
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,23 @@ interface ActivityIntentFactories {
* This must be injected within an activity context.
*/
interface TopicActivityIntentFactory {
/** Returns a new [Intent] to start the topic activity for the specified profile and topic. */
fun createIntent(profileId: ProfileId, topicId: String): Intent
/**
* Returns a new [Intent] to start the topic activity for the specified profile, classroom
* and topic.
*/
fun createIntent(profileId: ProfileId, classroomId: String, topicId: String): Intent

/**
* Returns a new [Intent] to start the topic activity for the specified profile, topic, and
* story (where the activity will automatically navigate to & expand the specified story in the
* topic).
* Returns a new [Intent] to start the topic activity for the specified profile, classroom,
* topic, and story (where the activity will automatically navigate to & expand the specified
* story in the topic).
*/
fun createIntent(profileId: ProfileId, topicId: String, storyId: String): Intent
fun createIntent(
profileId: ProfileId,
classroomId: String,
topicId: String,
storyId: String
): Intent
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ import org.oppia.android.app.model.ProfileId
import org.oppia.android.app.model.RecentlyPlayedActivityParams
import org.oppia.android.app.model.RecentlyPlayedActivityTitle
import org.oppia.android.app.model.ScreenName.CLASSROOM_LIST_ACTIVITY
import org.oppia.android.app.topic.TopicActivity
import org.oppia.android.app.topic.TopicActivity.Companion.createTopicActivityIntent
import org.oppia.android.app.topic.TopicActivity.Companion.createTopicPlayStoryActivityIntent
import org.oppia.android.app.translation.AppLanguageResourceHandler
import org.oppia.android.util.logging.CurrentAppScreenNameIntentDecorator.decorateWithScreenName
import org.oppia.android.util.profile.CurrentUserProfileIdIntentDecorator.decorateWithUserProfileId
Expand Down Expand Up @@ -98,15 +99,23 @@ class ClassroomListActivity :
)
}

override fun routeToTopic(internalProfileId: Int, topicId: String) {
startActivity(TopicActivity.createTopicActivityIntent(this, internalProfileId, topicId))
override fun routeToTopic(internalProfileId: Int, classroomId: String, topicId: String) {
startActivity(
createTopicActivityIntent(this, internalProfileId, classroomId, topicId)
)
}

override fun routeToTopicPlayStory(internalProfileId: Int, topicId: String, storyId: String) {
override fun routeToTopicPlayStory(
internalProfileId: Int,
classroomId: String,
topicId: String,
storyId: String
) {
startActivity(
TopicActivity.createTopicPlayStoryActivityIntent(
createTopicPlayStoryActivityIntent(
this,
internalProfileId,
classroomId,
topicId,
storyId
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ import androidx.compose.ui.res.integerResource
import androidx.compose.ui.unit.dp
import androidx.databinding.ObservableList
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import org.oppia.android.R
import org.oppia.android.app.classroom.classroomlist.ClassroomList
import org.oppia.android.app.classroom.promotedlist.ComingSoonTopicList
import org.oppia.android.app.classroom.promotedlist.PromotedStoryList
import org.oppia.android.app.classroom.topiclist.AllTopicsHeaderText
import org.oppia.android.app.classroom.topiclist.TopicCard
Expand All @@ -37,9 +39,11 @@ import org.oppia.android.app.home.HomeItemViewModel
import org.oppia.android.app.home.RouteToTopicPlayStoryListener
import org.oppia.android.app.home.WelcomeViewModel
import org.oppia.android.app.home.classroomlist.ClassroomSummaryViewModel
import org.oppia.android.app.home.promotedlist.ComingSoonTopicListViewModel
import org.oppia.android.app.home.promotedlist.PromotedStoryListViewModel
import org.oppia.android.app.home.topiclist.AllTopicsViewModel
import org.oppia.android.app.home.topiclist.TopicSummaryViewModel
import org.oppia.android.app.model.AppStartupState
import org.oppia.android.app.model.ClassroomSummary
import org.oppia.android.app.model.LessonThumbnail
import org.oppia.android.app.model.LessonThumbnailGraphic
Expand All @@ -48,10 +52,14 @@ import org.oppia.android.app.translation.AppLanguageResourceHandler
import org.oppia.android.app.utility.datetime.DateTimeUtil
import org.oppia.android.databinding.ClassroomListFragmentBinding
import org.oppia.android.domain.classroom.ClassroomController
import org.oppia.android.domain.onboarding.AppStartupStateController
import org.oppia.android.domain.oppialogger.OppiaLogger
import org.oppia.android.domain.oppialogger.analytics.AnalyticsController
import org.oppia.android.domain.profile.ProfileManagementController
import org.oppia.android.domain.topic.TopicListController
import org.oppia.android.domain.translation.TranslationController
import org.oppia.android.util.data.AsyncResult
import org.oppia.android.util.data.DataProviders.Companion.toLiveData
import org.oppia.android.util.locale.OppiaLocale
import org.oppia.android.util.parser.html.StoryHtmlParserEntityType
import org.oppia.android.util.parser.html.TopicHtmlParserEntityType
Expand All @@ -75,6 +83,8 @@ class ClassroomListFragmentPresenter @Inject constructor(
private val dateTimeUtil: DateTimeUtil,
private val translationController: TranslationController,
private val machineLocale: OppiaLocale.MachineLocale,
private val appStartupStateController: AppStartupStateController,
private val analyticsController: AnalyticsController,
) {
private val routeToTopicPlayStoryListener = activity as RouteToTopicPlayStoryListener
private lateinit var binding: ClassroomListFragmentBinding
Expand All @@ -92,6 +102,8 @@ class ClassroomListFragmentPresenter @Inject constructor(

internalProfileId = profileId.internalId

logHomeActivityEvent()

classroomListViewModel = ClassroomListViewModel(
activity,
fragment,
Expand Down Expand Up @@ -144,13 +156,16 @@ class ClassroomListFragmentPresenter @Inject constructor(
}
)

logAppOnboardedEvent()

return binding.root
}

/** Routes to the play story view for the first story in the given topic summary. */
fun onTopicSummaryClicked(topicSummary: TopicSummary) {
routeToTopicPlayStoryListener.routeToTopicPlayStory(
internalProfileId,
topicSummary.classroomId,
topicSummary.topicId,
topicSummary.firstStoryId
)
Expand Down Expand Up @@ -200,6 +215,14 @@ class ClassroomListFragmentPresenter @Inject constructor(
)
}
}
ComingSoonTopicListViewModel::class -> items.forEach { item ->
item {
ComingSoonTopicList(
comingSoonTopicListViewModel = item as ComingSoonTopicListViewModel,
machineLocale = machineLocale,
)
}
}
ClassroomSummaryViewModel::class -> stickyHeader {
ClassroomList(
classroomSummaryList = items.map { it as ClassroomSummaryViewModel },
Expand All @@ -225,6 +248,45 @@ class ClassroomListFragmentPresenter @Inject constructor(
}
}
}

private fun logAppOnboardedEvent() {
val startupStateProvider = appStartupStateController.getAppStartupState()
val liveData = startupStateProvider.toLiveData()
liveData.observe(
activity,
object : Observer<AsyncResult<AppStartupState>> {
override fun onChanged(startUpStateResult: AsyncResult<AppStartupState>?) {
when (startUpStateResult) {
null, is AsyncResult.Pending -> {
// Do nothing.
}
is AsyncResult.Success -> {
liveData.removeObserver(this)

if (startUpStateResult.value.startupMode ==
AppStartupState.StartupMode.USER_NOT_YET_ONBOARDED
) {
analyticsController.logAppOnboardedEvent(profileId)
}
}
is AsyncResult.Failure -> {
oppiaLogger.e(
"ClassroomListFragment",
"Failed to retrieve app startup state"
)
}
}
}
}
)
}

private fun logHomeActivityEvent() {
analyticsController.logImportantEvent(
oppiaLogger.createOpenHomeContext(),
profileId
)
}
}

/** Adds a grid of items to a LazyListScope with specified arrangement and item content. */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
package org.oppia.android.app.classroom.promotedlist

import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Card
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import org.oppia.android.R
import org.oppia.android.app.classroom.getDrawableResource
import org.oppia.android.app.home.promotedlist.ComingSoonTopicListViewModel
import org.oppia.android.app.home.promotedlist.ComingSoonTopicsViewModel
import org.oppia.android.util.locale.OppiaLocale

/** Test tag for the header of the promoted story list. */
const val COMING_SOON_TOPIC_LIST_HEADER_TEST_TAG = "TEST_TAG.coming_soon_topic_list_header"

/** Test tag for the promoted story list. */
const val COMING_SOON_TOPIC_LIST_TEST_TAG = "TEST_TAG.coming_soon_topic_list"

/** Displays a list of topics to be published soon. */
@Composable
fun ComingSoonTopicList(
comingSoonTopicListViewModel: ComingSoonTopicListViewModel,
machineLocale: OppiaLocale.MachineLocale,
) {
Text(
text = stringResource(id = R.string.coming_soon),
color = colorResource(id = R.color.component_color_shared_primary_text_color),
fontFamily = FontFamily.SansSerif,
fontWeight = FontWeight.Medium,
fontSize = dimensionResource(id = R.dimen.coming_soon_topic_list_header_text_size).value.sp,
modifier = Modifier
.padding(
start = dimensionResource(id = R.dimen.coming_soon_topic_list_layout_margin_start),
top = dimensionResource(id = R.dimen.coming_soon_topic_list_layout_margin_top),
end = dimensionResource(id = R.dimen.coming_soon_topic_list_layout_margin_end),
)
.testTag(COMING_SOON_TOPIC_LIST_HEADER_TEST_TAG),
)
LazyRow(
modifier = Modifier
.padding(
top = dimensionResource(id = R.dimen.coming_soon_topic_list_padding)
)
.testTag(COMING_SOON_TOPIC_LIST_TEST_TAG),
contentPadding = PaddingValues(
start = dimensionResource(id = R.dimen.coming_soon_topic_list_layout_margin_start),
end = dimensionResource(id = R.dimen.home_padding_end),
),
) {
items(comingSoonTopicListViewModel.comingSoonTopicList) {
ComingSoonTopicCard(
comingSoonTopicsViewModel = it,
machineLocale = machineLocale,
)
}
}
}

/** Displays a card with the coming soon topic summary information. */
@Composable
fun ComingSoonTopicCard(
comingSoonTopicsViewModel: ComingSoonTopicsViewModel,
machineLocale: OppiaLocale.MachineLocale,
) {
Card(
modifier = Modifier
.width(dimensionResource(id = R.dimen.coming_soon_topic_card_width))
.padding(
start = dimensionResource(id = R.dimen.coming_soon_topic_card_layout_margin_start),
end = dimensionResource(id = R.dimen.coming_soon_topic_card_layout_margin_end),
bottom = dimensionResource(id = R.dimen.coming_soon_topic_card_layout_margin_bottom),
),
elevation = dimensionResource(id = R.dimen.topic_card_elevation),
) {
Box(
contentAlignment = Alignment.TopEnd
) {
Column(
verticalArrangement = Arrangement.Center,
) {
Image(
painter = painterResource(
id = comingSoonTopicsViewModel.topicSummary.lessonThumbnail.getDrawableResource()
),
contentDescription = "Picture of a " +
"${comingSoonTopicsViewModel.topicSummary.lessonThumbnail.thumbnailGraphic.name}.",
modifier = Modifier
.aspectRatio(4f / 3f)
.background(
Color(
(
0xff000000L or
comingSoonTopicsViewModel
.topicSummary.lessonThumbnail.backgroundColorRgb.toLong()
).toInt()
)
)
)
ComingSoonTopicCardTextSection(comingSoonTopicsViewModel)
}
Text(
text = machineLocale
.run { stringResource(id = R.string.coming_soon).toMachineUpperCase() },
modifier = Modifier
.background(
color = colorResource(
id = R.color.component_color_coming_soon_rect_background_start_color
),
shape = RoundedCornerShape(topEnd = 4.dp, bottomStart = 12.dp),
)
.padding(
horizontal = dimensionResource(id = R.dimen.coming_soon_text_padding_horizontal),
vertical = dimensionResource(id = R.dimen.coming_soon_text_padding_vertical),
),
fontSize = 12.sp,
color = colorResource(id = R.color.component_color_shared_secondary_4_text_color),
fontFamily = FontFamily.SansSerif,
textAlign = TextAlign.End,
)
}
}
}

/** Displays the topic title. */
@Composable
fun ComingSoonTopicCardTextSection(comingSoonTopicsViewModel: ComingSoonTopicsViewModel) {
Column(
modifier = Modifier
.fillMaxWidth()
.background(
color = colorResource(
id = R.color.component_color_shared_topic_card_item_background_color
)
),
verticalArrangement = Arrangement.SpaceBetween,
) {
Text(
text = comingSoonTopicsViewModel.topicTitle,
modifier = Modifier
.fillMaxWidth()
.padding(
start = dimensionResource(id = R.dimen.coming_soon_topic_card_text_padding),
top = dimensionResource(id = R.dimen.coming_soon_topic_card_text_padding),
end = dimensionResource(id = R.dimen.coming_soon_topic_card_text_padding),
bottom = dimensionResource(id = R.dimen.coming_soon_topic_card_text_padding_bottom),
),
color = colorResource(id = R.color.component_color_shared_secondary_4_text_color),
fontFamily = FontFamily.SansSerif,
fontSize = dimensionResource(id = R.dimen.topic_list_item_text_size).value.sp,
textAlign = TextAlign.Start,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
}
}
Loading

0 comments on commit 8955775

Please sign in to comment.