Skip to content

Commit

Permalink
draft pr for gsoc what section
Browse files Browse the repository at this point in the history
  • Loading branch information
ShubhadeepKarmakar committed Mar 22, 2024
1 parent 9938779 commit 18da85a
Show file tree
Hide file tree
Showing 2 changed files with 286 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
package org.oppia.android.domain.classroom

import org.json.JSONObject
import org.oppia.android.app.model.ClassroomSummary
import org.oppia.android.app.model.EphemeralTopicSummary
import org.oppia.android.app.model.ProfileId
import org.oppia.android.app.model.StoryRecord
import org.oppia.android.app.model.SubtitledHtml
import org.oppia.android.app.model.TopicIdList
import org.oppia.android.app.model.TopicList
import org.oppia.android.app.model.TopicPlayAvailability
import org.oppia.android.app.model.TopicRecord
import org.oppia.android.app.model.TopicSummary
import org.oppia.android.domain.topic.createTopicThumbnailFromJson
import org.oppia.android.domain.translation.TranslationController
import org.oppia.android.domain.util.JsonAssetRetriever
import org.oppia.android.domain.util.getStringFromObject
import org.oppia.android.util.caching.AssetRepository
import org.oppia.android.util.caching.LoadLessonProtosFromAssets
import org.oppia.android.util.data.DataProvider
import org.oppia.android.util.data.DataProviders.Companion.transform
import org.oppia.android.util.locale.OppiaLocale
import javax.inject.Inject
import javax.inject.Singleton

private const val GET_CLASSROOM_SUMMARY_LIST_PROVIDER_ID = "get_classroom_summary_list_provider_id"

@Singleton
class ClassroomController @Inject constructor(
private val jsonAssetRetriever: JsonAssetRetriever,
private val assetRepository: AssetRepository,
private val translationController: TranslationController,
@LoadLessonProtosFromAssets private val loadLessonProtosFromAssets: Boolean
) {

fun getClassroomList(profileId: ProfileId): DataProvider<List<ClassroomSummary>> {
val translationLocaleProvider =
translationController.getWrittenTranslationContentLocale(profileId)
return translationLocaleProvider.transform(
GET_CLASSROOM_SUMMARY_LIST_PROVIDER_ID,
::createClassroomSummaryList
)
}

private fun createClassroomSummaryList(contentLocale: OppiaLocale.ContentLocale): List<ClassroomSummary> {
val classroomSummaryList = mutableListOf<ClassroomSummary>()
if (false
// loadLessonProtosFromAssets
) {
// val classroomIdList =
// assetRepository.loadProtoFromLocalAssets(
// assetName = "classroom",
// baseMessage = ClassroomIdList.getDefaultInstance()
// )
} else {
val classroomIdJsonArray = jsonAssetRetriever
.loadJsonFromAsset("classrooms.json")!!
.getJSONArray("classroom_id_list")

for (i in 0 until classroomIdJsonArray.length()) {
val classroomSummary =
createClassroomSummary(contentLocale, classroomIdJsonArray.optString(i)!!)
classroomSummaryList.add(classroomSummary)
}
}
return classroomSummaryList
}

private fun createClassroomSummary(
contentLocale: OppiaLocale.ContentLocale,
classroomId: String
): ClassroomSummary {
return if (
false
// loadLessonProtosFromAssets
) {
TODO()
} else {
createClassroomSummaryFromJson(
contentLocale,
classroomId
)
}
}

private fun createClassroomSummaryFromJson(
contentLocale: OppiaLocale.ContentLocale,
classroomId: String
): ClassroomSummary {
val topicList = createTopicList(contentLocale, classroomId)
var totalLessonCount = 0
val topicSummaryCount = topicList.topicSummaryCount
for (i in 0 until topicSummaryCount) {
totalLessonCount += topicList.getTopicSummary(i).topicSummary.totalChapterCount
}
val classroomIdAndNameJsonArray =
jsonAssetRetriever.loadJsonFromAsset("classroomIdAndNameMap.json")
val classroomTitle = SubtitledHtml.newBuilder().apply {
contentId = "title"
html = classroomIdAndNameJsonArray?.getStringFromObject(classroomId)
}.build()
return ClassroomSummary.newBuilder()
.setClassroomId(classroomId)
.setClassroomTitle(classroomTitle)
.setClassroomTitle(SubtitledHtml.getDefaultInstance())
.setTopicList(topicList)
.setTotalLessonCount(5)
.build()
}

private fun createTopicList(
contentLocale: OppiaLocale.ContentLocale,
classroomId: String
): TopicList {
return if (loadLessonProtosFromAssets) {
val topicIdList =
assetRepository.loadProtoFromLocalAssets(
assetName = "topics",
baseMessage = TopicIdList.getDefaultInstance()
)
return TopicList.newBuilder().apply {
// Only include topics currently playable in the topic list.
addAllTopicSummary(
topicIdList.topicIdsList.map {
createEphemeralTopicSummary(it, contentLocale)
}.filter {
it.topicSummary.topicPlayAvailability.availabilityCase == TopicPlayAvailability.AvailabilityCase.AVAILABLE_TO_PLAY_NOW
}.filter {
it.topicSummary.classroomId == classroomId
}
)
}.build()
} else loadTopicListFromJson(contentLocale, classroomId)
}

private fun loadTopicListFromJson(
contentLocale: OppiaLocale.ContentLocale,
classroomId: String
): TopicList {
val topicIdJsonArray = jsonAssetRetriever
.loadJsonFromAsset("topics.json")!!
.getJSONArray("topic_id_list")
val topicListBuilder = TopicList.newBuilder()
for (i in 0 until topicIdJsonArray.length()) {
val ephemeralSummary =
createEphemeralTopicSummary(topicIdJsonArray.optString(i)!!, contentLocale)
val topicPlayAvailability = ephemeralSummary.topicSummary.topicPlayAvailability
val topicClassroomId = ephemeralSummary.topicSummary.classroomId
// Only include topics currently playable in the topic list and part of the classroomId
if (topicPlayAvailability.availabilityCase == TopicPlayAvailability.AvailabilityCase.AVAILABLE_TO_PLAY_NOW &&
topicClassroomId == classroomId
) {
topicListBuilder.addTopicSummary(ephemeralSummary)
}
}
return topicListBuilder.build()
}

private fun createEphemeralTopicSummary(
topicId: String,
contentLocale: OppiaLocale.ContentLocale
): EphemeralTopicSummary {
val topicSummary = createTopicSummary(topicId)
return EphemeralTopicSummary.newBuilder().apply {
this.topicSummary = topicSummary
writtenTranslationContext =
translationController.computeWrittenTranslationContext(
topicSummary.writtenTranslationsMap,
contentLocale
)
}.build()
}

private fun createTopicSummary(topicId: String): TopicSummary {
return if (loadLessonProtosFromAssets) {
val topicRecord =
assetRepository.loadProtoFromLocalAssets(
assetName = topicId,
baseMessage = TopicRecord.getDefaultInstance()
)
val storyRecords = topicRecord.canonicalStoryIdsList.map {
assetRepository.loadProtoFromLocalAssets(
assetName = it,
baseMessage = StoryRecord.getDefaultInstance()
)
}
TopicSummary.newBuilder().apply {
this.topicId = topicId
putAllWrittenTranslations(topicRecord.writtenTranslationsMap)
title = topicRecord.translatableTitle
classroomId = topicRecord.classroomId
classroomTitle = topicRecord.classroomTitle
totalChapterCount = storyRecords.sumOf { it.chaptersList.size }
topicThumbnail = topicRecord.topicThumbnail
topicPlayAvailability = if (topicRecord.isPublished) {
TopicPlayAvailability.newBuilder().setAvailableToPlayNow(true).build()
} else {
TopicPlayAvailability.newBuilder().setAvailableToPlayInFuture(true).build()
}
storyRecords.firstOrNull()?.storyId?.let { this.firstStoryId = it }
}.build()
} else {
createTopicSummaryFromJson(topicId, jsonAssetRetriever.loadJsonFromAsset("$topicId.json")!!)
}
}

private fun createTopicSummaryFromJson(topicId: String, jsonObject: JSONObject): TopicSummary {
var totalChapterCount = 0
val storyData = jsonObject.getJSONArray("canonical_story_dicts")
for (i in 0 until storyData.length()) {
totalChapterCount += storyData
.getJSONObject(i)
.getJSONArray("node_titles")
.length()
}
val firstStoryId =
if (storyData.length() == 0) "" else storyData.getJSONObject(0).getStringFromObject("id")

val topicPlayAvailability = if (jsonObject.getBoolean("published")) {
TopicPlayAvailability.newBuilder().setAvailableToPlayNow(true).build()
} else {
TopicPlayAvailability.newBuilder().setAvailableToPlayInFuture(true).build()
}
val topicTitle = SubtitledHtml.newBuilder().apply {
contentId = "title"
html = jsonObject.getStringFromObject("topic_name")
}.build()
val classroomTitle = SubtitledHtml.newBuilder().apply {
contentId = "title"
html = jsonObject.getStringFromObject("classroom_title")
}
// No written translations are included since none are retrieved from JSON.
return TopicSummary.newBuilder()
.setTopicId(topicId)
.setTitle(topicTitle)
.setClassroomId(jsonObject.getStringFromObject("classroom_id"))
.setClassroomTitle(classroomTitle)
.setVersion(jsonObject.optInt("version"))
.setTotalChapterCount(totalChapterCount)
.setTopicThumbnail(createTopicThumbnailFromJson(jsonObject))
.setTopicPlayAvailability(topicPlayAvailability)
.setFirstStoryId(firstStoryId)
.build()
}
}
41 changes: 41 additions & 0 deletions model/src/main/proto/topic.proto
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ message Topic {
// The topic's title.
SubtitledHtml title = 10;

// The ID of the classroom which contains this Topic.
string classroom_id = 12;

// The title of the classroom this Topic is part of.
SubtitledHtml classroom_title = 13;

// A brief description of the topic.
SubtitledHtml description = 11;

Expand Down Expand Up @@ -204,6 +210,20 @@ message Classroom {
int64 last_update_time_ms = 2;
}

message ClassroomSummary {
// The Id of the ClassroomSummary.
string classroom_id = 1;

// The title of the ClassroomSummary.
SubtitledHtml classroom_title = 2;

// All topics that are part of this ClassroomSummary.
TopicList topic_list = 3;

// The total number of lessons (by adding all the lessons from each topic) in this ClassroomSummary.
int32 total_lesson_count = 4;
}

// Corresponds to the list of topics that are currently being played and are not fully finished.
message OngoingTopicList {
// All topics that are currently being played and have not finished.
Expand Down Expand Up @@ -289,6 +309,12 @@ message PromotedStory {
// The title of the next chapter (exploration title) to complete.
SubtitledHtml next_chapter_title = 17;

// The ID of the classroom this story is part of.
string classroom_id = 18;

// The title of the classroom this story is part of.
SubtitledHtml classroom_title = 19;

// The exploration id next chapter to complete.
string exploration_id = 6;

Expand Down Expand Up @@ -331,9 +357,18 @@ message TopicSummary {
// The title of the topic.
SubtitledHtml title = 8;

// The ID of the classroom which contains this TopicSummary.
string classroom_id = 10;

// The title of the classroom this TopicSummary is part of.
SubtitledHtml classroom_title = 11;

// The structural version of the topic.
int32 version = 3;

// The number of lessons the player has completed in this topic.
int32 completed_chapter_count = 12;

// The total number of lessons associated with this topic.
int32 total_chapter_count = 4;

Expand Down Expand Up @@ -575,6 +610,12 @@ message TopicRecord {
// The topic's description.
SubtitledHtml translatable_description = 10;

// The ID of the classroom which contains this TopicSummary.
string classroom_id = 11;

// The title of the classroom this TopicSummary is part of.
SubtitledHtml classroom_title = 12;

// The list of canonical story IDs that can be used to load stories from the local filesystem.
repeated string canonical_story_ids = 4;

Expand Down

0 comments on commit 18da85a

Please sign in to comment.