Skip to content

Commit

Permalink
Fix #1152: LessonThumbnailImageView (#1554)
Browse files Browse the repository at this point in the history
* LessonThumbnail Image View

* Draft approach for Lesson thumbnail

* Possible fix for Glide not liking custom models bound into views.

* Working implementation

* Added thumbnail support to Recently played screen, subtopics

* StoryTestHelper

* Profile Progress items

* Updated json files

* Reset progress test file

* Nit changes

* Nit changes

* Added thumbnail to new files

* Added todo

Co-authored-by: Rajat Talesra <talesra@google.com>
Co-authored-by: Ben Henning <bhenning@google.com>
  • Loading branch information
3 people committed Aug 7, 2020
1 parent 912cc26 commit c735bb3
Show file tree
Hide file tree
Showing 58 changed files with 589 additions and 330 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,7 @@ import androidx.lifecycle.ViewModel
import org.oppia.app.model.CompletedStory

/** Completed story view model for the recycler view in [CompletedStoryListFragment]. */
class CompletedStoryItemViewModel(val completedStory: CompletedStory) : ViewModel()
class CompletedStoryItemViewModel(
val completedStory: CompletedStory,
val entityType: String
) : ViewModel()
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ import org.oppia.app.model.ProfileId
import org.oppia.domain.topic.TopicController
import org.oppia.util.data.AsyncResult
import org.oppia.util.logging.ConsoleLogger
import org.oppia.util.parser.StoryHtmlParserEntityType
import javax.inject.Inject

/** The ViewModel for [CompletedStoryListFragment]. */
@FragmentScope
class CompletedStoryListViewModel @Inject constructor(
private val topicController: TopicController,
private val logger: ConsoleLogger
private val logger: ConsoleLogger,
@StoryHtmlParserEntityType private val entityType: String
) : ViewModel() {
/** [internalProfileId] needs to be set before any of the live data members can be accessed. */
private var internalProfileId: Int = -1
Expand Down Expand Up @@ -57,7 +59,7 @@ class CompletedStoryListViewModel @Inject constructor(
val itemViewModelList: MutableList<CompletedStoryItemViewModel> = mutableListOf()
itemViewModelList.addAll(
completedStoryList.completedStoryList.map { completedStory ->
CompletedStoryItemViewModel(completedStory)
CompletedStoryItemViewModel(completedStory, entityType)
}
)
return itemViewModelList
Expand Down
150 changes: 150 additions & 0 deletions app/src/main/java/org/oppia/app/customview/LessonThumbnailImageView.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package org.oppia.app.customview

import android.content.Context
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatImageView
import androidx.fragment.app.FragmentManager
import org.oppia.app.R
import org.oppia.app.fragment.InjectableFragment
import org.oppia.app.model.LessonThumbnail
import org.oppia.app.model.LessonThumbnailGraphic
import org.oppia.util.gcsresource.DefaultResourceBucketName
import org.oppia.util.parser.DefaultGcsPrefix
import org.oppia.util.parser.ImageLoader
import org.oppia.util.parser.ImageViewTarget
import org.oppia.util.parser.ThumbnailDownloadUrlTemplate
import javax.inject.Inject

/** A custom [AppCompatImageView] used to show lesson thumbnails. */
class LessonThumbnailImageView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : AppCompatImageView(context, attrs, defStyleAttr) {

private val imageView = this
private lateinit var lessonThumbnail: LessonThumbnail
private lateinit var entityId: String
private lateinit var entityType: String

@Inject
lateinit var imageLoader: ImageLoader

@Inject
@field:DefaultResourceBucketName
lateinit var resourceBucketName: String

// TODO(#1571): Investigate this issue to fix the initialization error.
@Inject
@field:ThumbnailDownloadUrlTemplate
lateinit var thumbnailDownloadUrlTemplate: String

@Inject
@field:DefaultGcsPrefix
lateinit var gcsPrefix: String

fun setEntityId(entityId: String) {
this.entityId = entityId
checkIfLoadingIsPossible()
}

fun setEntityType(entityType: String) {
this.entityType = entityType
checkIfLoadingIsPossible()
}

fun setLessonThumbnail(lessonThumbnail: LessonThumbnail) {
this.lessonThumbnail = lessonThumbnail
checkIfLoadingIsPossible()
}

private fun checkIfLoadingIsPossible() {
if (::entityId.isInitialized &&
::entityType.isInitialized &&
::lessonThumbnail.isInitialized &&
::thumbnailDownloadUrlTemplate.isInitialized &&
::resourceBucketName.isInitialized &&
::gcsPrefix.isInitialized &&
::imageLoader.isInitialized
) {
loadLessonThumbnail()
}
}

private fun loadLessonThumbnail() {
if (lessonThumbnail.thumbnailFilename.isNotEmpty()) {
loadImage(lessonThumbnail.thumbnailFilename)
} else {
imageView.setImageResource(getLessonDrawableResource(lessonThumbnail))
}
imageView.setBackgroundColor(lessonThumbnail.backgroundColorRgb)
}

/** Loads an image using Glide from [filename]. */
private fun loadImage(filename: String) {
val imageName = String.format(
thumbnailDownloadUrlTemplate,
entityType,
entityId,
filename
)
val imageUrl = "$gcsPrefix/$resourceBucketName/$imageName"
if (imageUrl.endsWith("svg", ignoreCase = true)) {
imageLoader.loadSvg(imageUrl, ImageViewTarget(this))
} else {
imageLoader.loadBitmap(imageUrl, ImageViewTarget(this))
}
}

override fun onAttachedToWindow() {
super.onAttachedToWindow()
FragmentManager.findFragment<InjectableFragment>(this)
.createViewComponent(this)
.inject(this)
}

private fun getLessonDrawableResource(lessonThumbnail: LessonThumbnail): Int {
return when (lessonThumbnail.thumbnailGraphic) {
LessonThumbnailGraphic.BAKER ->
R.drawable.lesson_thumbnail_graphic_baker
LessonThumbnailGraphic.CHILD_WITH_BOOK ->
R.drawable.lesson_thumbnail_graphic_child_with_book
LessonThumbnailGraphic.CHILD_WITH_CUPCAKES ->
R.drawable.lesson_thumbnail_graphic_child_with_cupcakes
LessonThumbnailGraphic.CHILD_WITH_FRACTIONS_HOMEWORK ->
R.drawable.lesson_thumbnail_graphic_child_with_fractions_homework
LessonThumbnailGraphic.DUCK_AND_CHICKEN ->
R.drawable.lesson_thumbnail_graphic_duck_and_chicken
LessonThumbnailGraphic.PERSON_WITH_PIE_CHART ->
R.drawable.lesson_thumbnail_graphic_person_with_pie_chart
LessonThumbnailGraphic.IDENTIFYING_THE_PARTS_OF_A_FRACTION ->
R.drawable.topic_fractions_01
LessonThumbnailGraphic.WRITING_FRACTIONS ->
R.drawable.topic_fractions_02
LessonThumbnailGraphic.EQUIVALENT_FRACTIONS ->
R.drawable.topic_fractions_03
LessonThumbnailGraphic.MIXED_NUMBERS_AND_IMPROPER_FRACTIONS ->
R.drawable.topic_fractions_04
LessonThumbnailGraphic.COMPARING_FRACTIONS ->
R.drawable.topic_fractions_05
LessonThumbnailGraphic.ADDING_AND_SUBTRACTING_FRACTIONS ->
R.drawable.topic_fractions_06
LessonThumbnailGraphic.MULTIPLYING_FRACTIONS ->
R.drawable.topic_fractions_07
LessonThumbnailGraphic.DIVIDING_FRACTIONS ->
R.drawable.topic_fractions_08
LessonThumbnailGraphic.DERIVE_A_RATIO ->
R.drawable.topic_ratios_01
LessonThumbnailGraphic.WHAT_IS_A_FRACTION ->
R.drawable.topic_fractions_01
LessonThumbnailGraphic.FRACTION_OF_A_GROUP ->
R.drawable.topic_fractions_02
LessonThumbnailGraphic.ADDING_FRACTIONS ->
R.drawable.topic_fractions_03
LessonThumbnailGraphic.MIXED_NUMBERS ->
R.drawable.topic_fractions_04
else ->
R.drawable.topic_fractions_01
}
}
}
16 changes: 12 additions & 4 deletions app/src/main/java/org/oppia/app/home/HomeFragmentPresenter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import org.oppia.domain.topic.TopicListController
import org.oppia.util.data.AsyncResult
import org.oppia.util.datetime.DateTimeUtil
import org.oppia.util.logging.ConsoleLogger
import org.oppia.util.parser.StoryHtmlParserEntityType
import org.oppia.util.parser.TopicHtmlParserEntityType
import org.oppia.util.system.OppiaClock
import javax.inject.Inject

Expand All @@ -43,7 +45,9 @@ class HomeFragmentPresenter @Inject constructor(
private val topicListController: TopicListController,
private val oppiaClock: OppiaClock,
private val logger: ConsoleLogger,
private val oppiaLogger: OppiaLogger
private val oppiaLogger: OppiaLogger,
@TopicHtmlParserEntityType private val topicEntityType: String,
@StoryHtmlParserEntityType private val storyEntityType: String
) {
private val routeToTopicListener = activity as RouteToTopicListener
private val itemList: MutableList<HomeItemViewModel> = ArrayList()
Expand Down Expand Up @@ -142,7 +146,11 @@ class HomeFragmentPresenter @Inject constructor(
Observer<TopicList> { result ->
for (topicSummary in result.topicSummaryList) {
val topicSummaryViewModel =
TopicSummaryViewModel(topicSummary, fragment as TopicSummaryClickListener)
TopicSummaryViewModel(
topicSummary,
topicEntityType,
fragment as TopicSummaryClickListener
)
itemList.add(topicSummaryViewModel)
}
topicListAdapter.notifyDataSetChanged()
Expand Down Expand Up @@ -183,14 +191,14 @@ class HomeFragmentPresenter @Inject constructor(
promotedStoryList.clear()
if (it.recentStoryCount != 0) {
it.recentStoryList.take(limit).forEach { promotedStory ->
val recentStory = PromotedStoryViewModel(activity, internalProfileId)
val recentStory = PromotedStoryViewModel(activity, internalProfileId, storyEntityType)
recentStory.setPromotedStory(promotedStory)
promotedStoryList.add(recentStory)
}
} else {
// TODO(#936): Optimise this as part of recommended stories.
it.olderStoryList.take(limit).forEach { promotedStory ->
val oldStory = PromotedStoryViewModel(activity, internalProfileId)
val oldStory = PromotedStoryViewModel(activity, internalProfileId, storyEntityType)
oldStory.setPromotedStory(promotedStory)
promotedStoryList.add(oldStory)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import org.oppia.app.model.PromotedStory
/** [ViewModel] for displaying a promoted story. */
class OngoingStoryViewModel(
val ongoingStory: PromotedStory,
val entityType: String,
private val ongoingStoryClickListener: OngoingStoryClickListener
) : RecentlyPlayedItemViewModel() {
fun clickOnOngoingStoryTile(@Suppress("UNUSED_PARAMETER") v: View) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import org.oppia.domain.exploration.ExplorationDataController
import org.oppia.domain.topic.TopicListController
import org.oppia.util.data.AsyncResult
import org.oppia.util.logging.ConsoleLogger
import org.oppia.util.parser.StoryHtmlParserEntityType
import javax.inject.Inject

/** The presenter for [RecentlyPlayedFragment]. */
Expand All @@ -31,7 +32,8 @@ class RecentlyPlayedFragmentPresenter @Inject constructor(
private val fragment: Fragment,
private val logger: ConsoleLogger,
private val explorationDataController: ExplorationDataController,
private val topicListController: TopicListController
private val topicListController: TopicListController,
@StoryHtmlParserEntityType private val entityType: String
) {

private val routeToExplorationListener = activity as RouteToExplorationListener
Expand Down Expand Up @@ -81,7 +83,11 @@ class RecentlyPlayedFragmentPresenter @Inject constructor(
itemList.add(recentSectionTitleViewModel)
for (promotedStory in it.recentStoryList) {
val ongoingStoryViewModel =
OngoingStoryViewModel(promotedStory, fragment as OngoingStoryClickListener)
OngoingStoryViewModel(
promotedStory,
entityType,
fragment as OngoingStoryClickListener
)
itemList.add(ongoingStoryViewModel)
}
}
Expand All @@ -96,7 +102,11 @@ class RecentlyPlayedFragmentPresenter @Inject constructor(
itemList.add(olderSectionTitleViewModel)
for (promotedStory in it.olderStoryList) {
val ongoingStoryViewModel =
OngoingStoryViewModel(promotedStory, fragment as OngoingStoryClickListener)
OngoingStoryViewModel(
promotedStory,
entityType,
fragment as OngoingStoryClickListener
)
itemList.add(ongoingStoryViewModel)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import org.oppia.app.viewmodel.ObservableViewModel
/** [ViewModel] for displaying a promoted story. */
class PromotedStoryViewModel(
private val activity: AppCompatActivity,
private val internalProfileId: Int
private val internalProfileId: Int,
val entityType: String
) :
ObservableViewModel(),
RouteToTopicPlayStoryListener {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const val DARKEN_SATURATION_MULTIPLIER: Float = 1.2f
/** The view model corresponding to topic summaries in the topic summary RecyclerView. */
class TopicSummaryViewModel(
val topicSummary: TopicSummary,
val entityType: String,
private val topicSummaryClickListener: TopicSummaryClickListener
) : HomeItemViewModel() {
val name: String = topicSummary.name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ import androidx.lifecycle.ViewModel
import org.oppia.app.model.Topic

/** [ViewModel] for displaying topic item in [OngoingTopicListActivity]. */
class OngoingTopicItemViewModel(val topic: Topic) : ViewModel()
class OngoingTopicItemViewModel(val topic: Topic, val entityType: String) : ViewModel()
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ import org.oppia.app.model.ProfileId
import org.oppia.domain.topic.TopicController
import org.oppia.util.data.AsyncResult
import org.oppia.util.logging.ConsoleLogger
import org.oppia.util.parser.TopicHtmlParserEntityType
import javax.inject.Inject

/** The ViewModel for [OngoingTopicListFragment]. */
@FragmentScope
class OngoingTopicListViewModel @Inject constructor(
private val topicController: TopicController,
private val logger: ConsoleLogger
private val logger: ConsoleLogger,
@TopicHtmlParserEntityType private val entityType: String
) : ViewModel() {
/** [internalProfileId] needs to be set before any of the live data members can be accessed. */
private var internalProfileId: Int = -1
Expand Down Expand Up @@ -57,7 +59,7 @@ class OngoingTopicListViewModel @Inject constructor(
val itemViewModelList: MutableList<OngoingTopicItemViewModel> = mutableListOf()
itemViewModelList.addAll(
ongoingTopicList.topicList.map { topic ->
OngoingTopicItemViewModel(topic)
OngoingTopicItemViewModel(topic, entityType)
}
)
return itemViewModelList
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import org.oppia.domain.topic.TopicController
import org.oppia.domain.topic.TopicListController
import org.oppia.util.data.AsyncResult
import org.oppia.util.logging.ConsoleLogger
import org.oppia.util.parser.StoryHtmlParserEntityType
import javax.inject.Inject

/** The [ViewModel] for [ProfileProgressFragment]. */
Expand All @@ -27,7 +28,8 @@ class ProfileProgressViewModel @Inject constructor(
private val profileManagementController: ProfileManagementController,
private val topicController: TopicController,
private val topicListController: TopicListController,
private val logger: ConsoleLogger
private val logger: ConsoleLogger,
@StoryHtmlParserEntityType private val entityType: String
) : ViewModel() {
/** [internalProfileId] needs to be set before any of the live data members can be accessed. */
private var internalProfileId: Int = -1
Expand Down Expand Up @@ -109,7 +111,7 @@ class ProfileProgressViewModel @Inject constructor(
}
itemViewModelList.addAll(
itemList.map { story ->
RecentlyPlayedStorySummaryViewModel(story) as ProfileProgressItemViewModel
RecentlyPlayedStorySummaryViewModel(story, entityType)
}
)
return itemViewModelList
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@ package org.oppia.app.profileprogress
import org.oppia.app.model.PromotedStory

/** Recently played item [ViewModel] for the recycler view in [ProfileProgressFragment]. */
class RecentlyPlayedStorySummaryViewModel(val promotedStory: PromotedStory) :
ProfileProgressItemViewModel()
class RecentlyPlayedStorySummaryViewModel(
val promotedStory: PromotedStory,
val entityType: String
) : ProfileProgressItemViewModel()

0 comments on commit c735bb3

Please sign in to comment.