Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
85 changes: 85 additions & 0 deletions app/src/main/assets/list/blind_75.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
[
"Two Sum",
"Longest Substring Without Repeating Characters",
"Longest Palindromic Substring",
"Container With Most Water",
"3Sum",
"Remove Nth Node From End of List",
"Valid Parentheses",
"Merge Two Sorted Lists",
"Merge k Sorted Lists",
"Search in Rotated Sorted Array",
"Combination Sum",
"Group Anagrams",
"Maximum Subarray",
"Jump Game",
"Merge Intervals",
"Insert Interval",
"Unique Paths",
"Climbing Stairs",
"Set Matrix Zeroes",
"Search a 2D Matrix",
"Minimum Window Substring",
"Subsets",
"Word Search",
"Decode Ways",
"Validate Binary Search Tree",
"Same Tree",
"Binary Tree Level Order Traversal",
"Maximum Depth of Binary Tree",
"Construct Binary Tree from Preorder and Inorder Traversal",
"Best Time to Buy and Sell Stock",
"Binary Tree Maximum Path Sum",
"Valid Palindrome",
"Word Break",
"Linked List Cycle",
"Reorder List",
"Maximum Product Subarray",
"Find Minimum in Rotated Sorted Array",
"Reverse Bits",
"Number of 1 Bits",
"House Robber",
"Number of Islands",
"Reverse Linked List",
"Course Schedule",
"Implement Trie (Prefix Tree)",
"Design Add and Search Words Data Structure",
"Word Search II",
"House Robber II",
"Contains Duplicate",
"Invert Binary Tree",
"Kth Smallest Element in a BST",
"Lowest Common Ancestor of a Binary Search Tree",
"Lowest Common Ancestor of a Binary Tree",
"Product of Array Except Self",
"Valid Anagram",
"Meeting Rooms",
"Meeting Rooms II",
"Graph Valid Tree",
"Missing Number",
"Alien Dictionary",
"Encode and Decode Strings",
"Find Median from Data Stream",
"Longest Increasing Subsequence",
"Coin Change",
"Sum of Two Integers",
"Counting Bits",
"Longest Common Subsequence",
"Word Break Problem",
"Clone Graph",
"Pacific Atlantic Water Flow",
"Longest Consecutive Sequence",
"Number of Connected Components in an Undirected Graph",
"Non-overlapping Intervals",
"Reverse a Linked List",
"Detect Cycle in a Linked List",
"Spiral Matrix",
"Rotate Image",
"Longest Repeating Character Replacement",
"Palindromic Substrings",
"Invert/Flip Binary Tree",
"Serialize and Deserialize Binary Tree",
"Subtree of Another Tree",
"Lowest Common Ancestor of BST",
"Top K Frequent Elements"
]
7 changes: 7 additions & 0 deletions app/src/main/assets/predefined_problem_set_manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[
{
"id": "blind_75",
"name": "Blind 75",
"file": "blind_75.json"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.byteutility.dev.leetcode.plus.data.repository.di

import android.content.Context
import android.content.res.AssetManager
import com.byteutility.dev.leetcode.plus.data.sets.AssetProblemSetFactory
import com.byteutility.dev.leetcode.plus.data.sets.ProblemSetFactory
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object FactoryModule {

@Provides
@Singleton
fun provideGson(): Gson {
return GsonBuilder()
.create()
}

@Provides
@Singleton
fun provideAssetManager(@ApplicationContext context: Context): AssetManager {
return context.assets
}

@Provides
@Singleton
fun provideProblemSetFactory(
assetManager: AssetManager,
gson: Gson
): ProblemSetFactory {
return AssetProblemSetFactory(assetManager, gson)
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package com.byteutility.dev.leetcode.plus.data.repository.problems

import com.byteutility.dev.leetcode.plus.data.model.LeetCodeProblem
import com.byteutility.dev.leetcode.plus.domain.model.ProblemSetType
import com.byteutility.dev.leetcode.plus.network.responseVo.LeetCodeQuestionResponse

interface ProblemsRepository {
suspend fun getProblems(limit: Long): List<LeetCodeProblem>
suspend fun getProblems(type: ProblemSetType? = null): List<LeetCodeProblem>
suspend fun getSelectedRawQuestion(titleSlug: String): LeetCodeQuestionResponse
}
Original file line number Diff line number Diff line change
@@ -1,54 +1,35 @@
package com.byteutility.dev.leetcode.plus.data.repository.problems

import android.content.Context
import com.byteutility.dev.leetcode.plus.data.model.LeetCodeProblem
import com.byteutility.dev.leetcode.plus.data.sets.ProblemSet
import com.byteutility.dev.leetcode.plus.data.sets.ProblemSetFactory
import com.byteutility.dev.leetcode.plus.domain.model.ProblemSetType
import com.byteutility.dev.leetcode.plus.network.RestApiService
import com.byteutility.dev.leetcode.plus.network.responseVo.LeetCodeQuestionResponse
import com.byteutility.dev.leetcode.plus.network.responseVo.ProblemSetResponseVo
import com.google.gson.Gson
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import javax.inject.Inject

class ProblemsRepositoryImpl @Inject constructor(
@ApplicationContext private val context: Context,
private val factory: ProblemSetFactory,
private val restApiService: RestApiService
) : ProblemsRepository {

private val masterList: List<LeetCodeProblem> by lazy {
factory.loadMasterList()
}
private val setCache = mutableMapOf<ProblemSetType, ProblemSet>()

override suspend fun getProblems(
limit: Long
type: ProblemSetType?
): List<LeetCodeProblem> {
var leetCodeProblems: List<LeetCodeProblem> = mutableListOf()
withContext(Dispatchers.IO) {
val response: ProblemSetResponseVo = parseProblemsJson(context)
response.problemSetQuestionList.map {
LeetCodeProblem(
title = it.title,
difficulty = it.difficulty,
tag = it.topicTags.firstOrNull()?.name ?: "NO_TAG",
titleSlug = it.titleSlug,
)
}.run {
leetCodeProblems = this
return withContext(Dispatchers.IO) {
if (type == null) return@withContext masterList
val problemSet = setCache.getOrPut(type) {
factory.createSet(type)
}
masterList.filter { problemSet.isIncluded(it) }
}
return leetCodeProblems
}

private fun parseProblemsJson(
context: Context
): ProblemSetResponseVo {
val jsonString = loadJsonFromAssets(context, "problems.json")
val gson = Gson()
return gson.fromJson(jsonString, ProblemSetResponseVo::class.java)
}

private fun loadJsonFromAssets(
context: Context,
fileName: String
): String {
return context.assets.open(fileName).bufferedReader().use { it.readText() }
}

@Throws
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.byteutility.dev.leetcode.plus.data.repository.problems.predefined

import android.content.res.AssetManager
import android.util.Log
import com.byteutility.dev.leetcode.plus.domain.model.SetMetadata
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import java.io.IOException
import javax.inject.Inject

class PredefinedProblemSetMetadataProvider @Inject constructor(
private val assetManager: AssetManager,
private val gson: Gson
) {

fun getAvailableStaticSets(): List<SetMetadata> {
return try {
assetManager.open("predefined_problem_set_manifest.json").bufferedReader()
.use { reader ->
val type = object : TypeToken<List<SetMetadata>>() {}.type
gson.fromJson(reader, type)
}
} catch (e: IOException) {
Log.e(this.javaClass.name, "getAvailableStaticSets: exception ${e.message}")
emptyList()
} finally {
emptyList<SetMetadata>()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.byteutility.dev.leetcode.plus.data.sets

import android.content.res.AssetManager
import com.byteutility.dev.leetcode.plus.data.model.LeetCodeProblem
import com.byteutility.dev.leetcode.plus.domain.model.ProblemSetType
import com.byteutility.dev.leetcode.plus.domain.model.ProblemSetType.PredefinedProblemSet
import com.byteutility.dev.leetcode.plus.domain.model.ProblemSetType.UserDefinedProblemSet
import com.byteutility.dev.leetcode.plus.network.responseVo.ProblemSetResponseVo
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import javax.inject.Inject

class AssetProblemSetFactory @Inject constructor(
private val assetManager: AssetManager,
private val gson: Gson
) : ProblemSetFactory {
override fun createSet(type: ProblemSetType): ProblemSet {
return when (type) {
is PredefinedProblemSet -> {
val titles = loadTitlesFromAssets(type.metadata.file)
PredefinedProblemSet(displayName = type.displayName, titles = titles)
}

is UserDefinedProblemSet -> {
UserDefinedProblemSet(
displayName = type.displayName,
titles = emptyList()
)
}
}
}

override fun loadMasterList(): List<LeetCodeProblem> {
return loadAllProblemFromAssets("problems.json").toList()
}

private fun loadTitlesFromAssets(fileName: String): List<String> {
val json = assetManager.open("list/$fileName").bufferedReader().use { it.readText() }
val listType = object : TypeToken<List<String>>() {}.type
return gson.fromJson<List<String>>(json, listType)
}

private fun loadAllProblemFromAssets(fileName: String): List<LeetCodeProblem> {
val json = assetManager.open(fileName).bufferedReader().use { it.readText() }
val response = gson.fromJson(json, ProblemSetResponseVo::class.java)
val allProblems = response.problemSetQuestionList.map {
LeetCodeProblem(
title = it.title,
difficulty = it.difficulty,
tag = it.topicTags.firstOrNull()?.name ?: "NO_TAG",
titleSlug = it.titleSlug,
)
}
return allProblems
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.byteutility.dev.leetcode.plus.data.sets

import com.byteutility.dev.leetcode.plus.data.model.LeetCodeProblem

interface ProblemSet {
val displayName: String

/**
* Returns true if the given problem belongs to this specific set.
*/
fun isIncluded(problem: LeetCodeProblem): Boolean
}

class PredefinedProblemSet(
override val displayName: String,
private val titles: List<String>
) : ProblemSet {

override fun isIncluded(problem: LeetCodeProblem): Boolean {
return titles.contains(problem.title.trim())
}
}

class UserDefinedProblemSet(
override val displayName: String,
private val titles: List<String>
) : ProblemSet {
override fun isIncluded(problem: LeetCodeProblem): Boolean {
return titles.contains(problem.title)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.byteutility.dev.leetcode.plus.data.sets

import com.byteutility.dev.leetcode.plus.data.model.LeetCodeProblem
import com.byteutility.dev.leetcode.plus.domain.model.ProblemSetType

interface ProblemSetFactory {
fun createSet(type: ProblemSetType): ProblemSet
fun loadMasterList(): List<LeetCodeProblem>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.byteutility.dev.leetcode.plus.domain.model

sealed interface ProblemSetType {
val displayName: String

data class PredefinedProblemSet(val metadata: SetMetadata) : ProblemSetType {
override val displayName: String = metadata.name
}

data class UserDefinedProblemSet(
override val displayName: String,
val fileName: String,
) : ProblemSetType
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.byteutility.dev.leetcode.plus.domain.model

data class SetMetadata(val id: String, val name: String, val file: String)
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ import androidx.navigation.compose.rememberNavController
import androidx.navigation.toRoute
import com.byteutility.dev.leetcode.plus.troubleshoot.TroubleShootScreen
import com.byteutility.dev.leetcode.plus.ui.screens.MainScreen
import com.byteutility.dev.leetcode.plus.ui.screens.contest.details.ContestDetailScreen
import com.byteutility.dev.leetcode.plus.ui.screens.leetcodelogin.LeetCodeLoginWebView
import com.byteutility.dev.leetcode.plus.ui.screens.login.UserLoginScreen
import com.byteutility.dev.leetcode.plus.ui.screens.problem.details.ProblemDetailsScreen
import com.byteutility.dev.leetcode.plus.ui.screens.solutions.VideoSolutionsScreen
import com.byteutility.dev.leetcode.plus.ui.screens.targetset.SetWeeklyTargetScreen
import com.byteutility.dev.leetcode.plus.ui.screens.targetstatus.GoalProgressScreen
import com.byteutility.dev.leetcode.plus.ui.screens.contest.details.ContestDetailScreen
import com.byteutility.dev.leetcode.plus.ui.screens.webview.CommonWebViewScreen

@Composable
Expand Down
Loading