Skip to content

Commit 0a3dcca

Browse files
authored
Merge branch 'master' into feature-optimize-adapter-courses-diffutil
2 parents a4cddd5 + fec5226 commit 0a3dcca

32 files changed

+554
-324
lines changed

.github/workflows/android-build.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ on:
55
branches:
66
- '*'
77
- '!master'
8-
- 'dependabot/**'
8+
- 'claude/**'
99
- 'codex/**'
10+
- 'dependabot/**'
11+
- 'jules/**'
1012
- '*-codex/**'
1113

1214
jobs:

app/src/main/java/org/ole/planet/myplanet/base/BaseResourceFragment.kt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -489,9 +489,6 @@ abstract class BaseResourceFragment : Fragment() {
489489
}
490490

491491
override fun onDestroy() {
492-
if (::profileDbHandler.isInitialized) {
493-
profileDbHandler.onDestroy()
494-
}
495492
cleanupRealm()
496493
super.onDestroy()
497494
}

app/src/main/java/org/ole/planet/myplanet/datamanager/ApiClient.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import retrofit2.Retrofit
1111
object ApiClient {
1212
lateinit var client: Retrofit
1313

14+
@Deprecated("This function blocks the calling thread. Use a coroutine with executeWithRetryAndWrap instead.")
1415
fun <T> executeWithRetry(operation: () -> Response<T>?): Response<T>? = runBlocking {
1516
RetryUtils.retry(
1617
maxAttempts = 3,
@@ -20,6 +21,15 @@ object ApiClient {
2021
)
2122
}
2223

24+
suspend fun <T> executeWithRetryAndWrap(operation: suspend () -> Response<T>?): Response<T>? {
25+
return RetryUtils.retry(
26+
maxAttempts = 3,
27+
delayMs = 2000L,
28+
shouldRetry = { resp -> resp == null || !resp.isSuccessful },
29+
block = { operation() },
30+
)
31+
}
32+
2333
suspend fun <T> executeWithResult(operation: suspend () -> Response<T>?): NetworkResult<T> {
2434
var retryCount = 0
2535
var lastException: Exception? = null

app/src/main/java/org/ole/planet/myplanet/repository/NewsRepositoryImpl.kt

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import io.realm.Sort
77
import java.util.HashMap
88
import javax.inject.Inject
99
import org.ole.planet.myplanet.datamanager.DatabaseService
10+
import org.ole.planet.myplanet.datamanager.findCopyByField
1011
import org.ole.planet.myplanet.model.RealmNews
1112
import org.ole.planet.myplanet.model.RealmNews.Companion.createNews
1213
import org.ole.planet.myplanet.model.RealmUserModel
@@ -17,12 +18,15 @@ class NewsRepositoryImpl @Inject constructor(
1718
) : RealmRepository(databaseService), NewsRepository {
1819

1920
override suspend fun getNewsWithReplies(newsId: String): Pair<RealmNews?, List<RealmNews>> {
20-
val news = findByField(RealmNews::class.java, "id", newsId)
21-
val replies = queryList(RealmNews::class.java) {
22-
equalTo("replyTo", newsId, Case.INSENSITIVE)
23-
sort("time", Sort.DESCENDING)
21+
return withRealm(ensureLatest = true) { realm ->
22+
val news = realm.findCopyByField(RealmNews::class.java, "id", newsId)
23+
val replies = realm.where(RealmNews::class.java)
24+
.equalTo("replyTo", newsId, Case.INSENSITIVE)
25+
.sort("time", Sort.DESCENDING)
26+
.findAll()
27+
.let { realm.copyFromRealm(it) }
28+
news to replies
2429
}
25-
return news to replies
2630
}
2731

2832
override suspend fun getCommunityVisibleNews(userIdentifier: String): List<RealmNews> {

app/src/main/java/org/ole/planet/myplanet/repository/RealmRepository.kt

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,28 @@ open class RealmRepository(private val databaseService: DatabaseService) {
1818
protected suspend fun <T : RealmObject> queryList(
1919
clazz: Class<T>,
2020
builder: RealmQuery<T>.() -> Unit = {},
21+
): List<T> = queryList(clazz, false, builder)
22+
23+
protected suspend fun <T : RealmObject> queryList(
24+
clazz: Class<T>,
25+
ensureLatest: Boolean,
26+
builder: RealmQuery<T>.() -> Unit = {},
2127
): List<T> =
22-
databaseService.withRealmAsync { realm ->
28+
withRealm(ensureLatest) { realm ->
2329
realm.queryList(clazz, builder)
2430
}
2531

2632
protected suspend fun <T : RealmObject> count(
2733
clazz: Class<T>,
2834
builder: RealmQuery<T>.() -> Unit = {},
35+
): Long = count(clazz, false, builder)
36+
37+
protected suspend fun <T : RealmObject> count(
38+
clazz: Class<T>,
39+
ensureLatest: Boolean,
40+
builder: RealmQuery<T>.() -> Unit = {},
2941
): Long =
30-
databaseService.withRealmAsync { realm ->
42+
withRealm(ensureLatest) { realm ->
3143
realm.where(clazz).apply(builder).count()
3244
}
3345

@@ -54,8 +66,15 @@ open class RealmRepository(private val databaseService: DatabaseService) {
5466
clazz: Class<T>,
5567
fieldName: String,
5668
value: V,
69+
): T? = findByField(clazz, fieldName, value, false)
70+
71+
protected suspend fun <T : RealmObject, V : Any> findByField(
72+
clazz: Class<T>,
73+
fieldName: String,
74+
value: V,
75+
ensureLatest: Boolean,
5776
): T? =
58-
databaseService.withRealmAsync { realm ->
77+
withRealm(ensureLatest) { realm ->
5978
realm.findCopyByField(clazz, fieldName, value)
6079
}
6180

@@ -90,8 +109,20 @@ open class RealmRepository(private val databaseService: DatabaseService) {
90109
}
91110
}
92111

112+
protected suspend fun <T> withRealm(
113+
ensureLatest: Boolean = false,
114+
operation: (Realm) -> T,
115+
): T {
116+
return databaseService.withRealmAsync { realm ->
117+
if (ensureLatest) {
118+
realm.refresh()
119+
}
120+
operation(realm)
121+
}
122+
}
123+
93124
protected suspend fun <T> withRealmAsync(operation: (Realm) -> T): T {
94-
return databaseService.withRealmAsync(operation)
125+
return withRealm(false, operation)
95126
}
96127

97128
protected fun <T> withRealmFlow(
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
package org.ole.planet.myplanet.repository
22

33
import org.ole.planet.myplanet.model.RealmStepExam
4+
import org.ole.planet.myplanet.ui.survey.SurveyInfo
45

56
interface SurveyRepository {
67
suspend fun getTeamOwnedSurveys(teamId: String?): List<RealmStepExam>
78
suspend fun getAdoptableTeamSurveys(teamId: String?): List<RealmStepExam>
89
suspend fun getIndividualSurveys(): List<RealmStepExam>
10+
suspend fun getSurveyInfos(
11+
isTeam: Boolean,
12+
teamId: String?,
13+
userId: String?,
14+
surveys: List<RealmStepExam>
15+
): Map<String, SurveyInfo>
916
}

app/src/main/java/org/ole/planet/myplanet/repository/SurveyRepositoryImpl.kt

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
11
package org.ole.planet.myplanet.repository
22

3+
import android.content.Context
4+
import dagger.hilt.android.qualifiers.ApplicationContext
5+
import io.realm.Sort
36
import javax.inject.Inject
47
import org.json.JSONException
58
import org.json.JSONObject
9+
import org.ole.planet.myplanet.R
610
import org.ole.planet.myplanet.datamanager.DatabaseService
711
import org.ole.planet.myplanet.model.RealmStepExam
812
import org.ole.planet.myplanet.model.RealmSubmission
13+
import org.ole.planet.myplanet.ui.survey.SurveyInfo
14+
import org.ole.planet.myplanet.utilities.TimeUtils.formatDate
15+
import org.ole.planet.myplanet.utilities.TimeUtils.getFormattedDateWithTime
916

1017
class SurveyRepositoryImpl @Inject constructor(
18+
@ApplicationContext private val context: Context,
1119
databaseService: DatabaseService
1220
) : RealmRepository(databaseService), SurveyRepository {
1321

@@ -77,4 +85,44 @@ class SurveyRepositoryImpl @Inject constructor(
7785
null
7886
}
7987
}
88+
89+
override suspend fun getSurveyInfos(
90+
isTeam: Boolean,
91+
teamId: String?,
92+
userId: String?,
93+
surveys: List<RealmStepExam>
94+
): Map<String, SurveyInfo> {
95+
val surveyIds = surveys.map { it.id }
96+
val submissions = queryList(RealmSubmission::class.java) {
97+
`in`("parentId", surveyIds.toTypedArray())
98+
}
99+
val surveyInfos = mutableMapOf<String, SurveyInfo>()
100+
for (survey in surveys) {
101+
val surveyId = survey.id ?: continue
102+
val submissionCount = if (isTeam) {
103+
submissions.count { it.parentId == surveyId && it.membershipDoc?.teamId == teamId }.toString()
104+
} else {
105+
submissions.count { it.parentId == surveyId && it.userId == userId }.toString()
106+
}
107+
val lastSubmissionDate = if (isTeam) {
108+
submissions.filter { it.parentId == surveyId && it.membershipDoc?.teamId == teamId }
109+
.maxByOrNull { it.startTime }?.startTime?.let { getFormattedDateWithTime(it) } ?: ""
110+
} else {
111+
submissions.filter { it.parentId == surveyId && it.userId == userId }
112+
.maxByOrNull { it.startTime }?.startTime?.let { getFormattedDateWithTime(it) } ?: ""
113+
}
114+
val creationDate = survey.createdDate.let { formatDate(it, "MMM dd, yyyy") } ?: ""
115+
surveyInfos[surveyId] = SurveyInfo(
116+
surveyId = surveyId,
117+
submissionCount = context.resources.getQuantityString(
118+
R.plurals.survey_taken_count,
119+
submissionCount.toInt(),
120+
submissionCount.toInt()
121+
),
122+
lastSubmissionDate = lastSubmissionDate,
123+
creationDate = creationDate
124+
)
125+
}
126+
return surveyInfos
127+
}
80128
}

app/src/main/java/org/ole/planet/myplanet/repository/TeamRepository.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ import org.ole.planet.myplanet.model.RealmMyTeam
77
import org.ole.planet.myplanet.model.RealmTeamTask
88
import org.ole.planet.myplanet.model.RealmUserModel
99

10+
data class TeamMemberStatus(
11+
val isMember: Boolean,
12+
val isLeader: Boolean,
13+
val hasPendingRequest: Boolean
14+
)
15+
1016
interface TeamRepository {
1117
suspend fun getShareableTeams(): List<RealmMyTeam>
1218
suspend fun getShareableEnterprises(): List<RealmMyTeam>
@@ -17,6 +23,7 @@ interface TeamRepository {
1723
suspend fun isMember(userId: String?, teamId: String): Boolean
1824
suspend fun isTeamLeader(teamId: String, userId: String?): Boolean
1925
suspend fun hasPendingRequest(teamId: String, userId: String?): Boolean
26+
suspend fun getTeamMemberStatuses(userId: String?, teamIds: Collection<String>): Map<String, TeamMemberStatus>
2027
suspend fun getRecentVisitCounts(teamIds: Collection<String>): Map<String, Long>
2128
suspend fun requestToJoin(teamId: String, userId: String?, userPlanetCode: String?, teamType: String?)
2229
suspend fun leaveTeam(teamId: String, userId: String?)

app/src/main/java/org/ole/planet/myplanet/repository/TeamRepositoryImpl.kt

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,46 @@ class TeamRepositoryImpl @Inject constructor(
199199
} > 0
200200
}
201201

202+
override suspend fun getTeamMemberStatuses(userId: String?, teamIds: Collection<String>): Map<String, TeamMemberStatus> {
203+
if (userId.isNullOrBlank() || teamIds.isEmpty()) return emptyMap()
204+
205+
val validIds = teamIds.filter { it.isNotBlank() }.distinct()
206+
if (validIds.isEmpty()) return emptyMap()
207+
208+
val memberships = queryList(RealmMyTeam::class.java) {
209+
equalTo("userId", userId)
210+
equalTo("docType", "membership")
211+
`in`("teamId", validIds.toTypedArray())
212+
}
213+
214+
val pendingRequests = queryList(RealmMyTeam::class.java) {
215+
equalTo("userId", userId)
216+
equalTo("docType", "request")
217+
`in`("teamId", validIds.toTypedArray())
218+
}
219+
220+
val membershipMap = memberships
221+
.mapNotNull { it.teamId }
222+
.toSet()
223+
224+
val leaderMap = memberships
225+
.filter { it.isLeader }
226+
.mapNotNull { it.teamId }
227+
.toSet()
228+
229+
val pendingRequestMap = pendingRequests
230+
.mapNotNull { it.teamId }
231+
.toSet()
232+
233+
return validIds.associateWith { teamId ->
234+
TeamMemberStatus(
235+
isMember = teamId in membershipMap,
236+
isLeader = teamId in leaderMap,
237+
hasPendingRequest = teamId in pendingRequestMap
238+
)
239+
}
240+
}
241+
202242
override suspend fun getRecentVisitCounts(teamIds: Collection<String>): Map<String, Long> {
203243
if (teamIds.isEmpty()) return emptyMap()
204244

0 commit comments

Comments
 (0)