Skip to content

Commit fb8408d

Browse files
authored
Merge branch 'master' into refactor-team-resource-dto-8518796163138516645
2 parents fd16cd0 + 2b91b72 commit fb8408d

139 files changed

Lines changed: 2691 additions & 1945 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CLAUDE.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -237,15 +237,15 @@ Activities, Chat, Configurations, Courses, Events, Feedback, Life, Notifications
237237
- `SharedPreferencesModule.kt` - Provides SharedPreferences
238238

239239
**Entry Points for Workers (11 entry point files):**
240-
- `AutoSyncEntryPoint`, `ApiClientEntryPoint`, `ApiInterfaceEntryPoint`
240+
- `NetworkDependenciesEntryPoint`, `NetworkDependenciesEntryPoint`, `NetworkDependenciesEntryPoint`
241241
- `ApplicationScopeEntryPoint`, `BroadcastServiceEntryPoint`, `DatabaseServiceEntryPoint`
242242
- `RepositoryEntryPoint`, `RetryQueueEntryPoint`, `ServiceEntryPoint`
243-
- `TeamsRepositoryEntryPoint`, `WorkerDependenciesEntryPoint`
243+
- `RepositoryDependenciesEntryPoint`, `CoreDependenciesEntryPoint`
244244

245245
```kotlin
246246
@EntryPoint
247247
@InstallIn(SingletonComponent::class)
248-
interface AutoSyncEntryPoint {
248+
interface NetworkDependenciesEntryPoint {
249249
fun apiInterface(): ApiInterface
250250
fun sharedPreferences(): SharedPreferences
251251
}
@@ -543,7 +543,7 @@ class AutoSyncWorker(
543543
override suspend fun doWork(): Result {
544544
val entryPoint = EntryPointAccessors.fromApplication(
545545
applicationContext,
546-
AutoSyncEntryPoint::class.java
546+
NetworkDependenciesEntryPoint::class.java
547547
)
548548
val apiInterface = entryPoint.apiInterface()
549549
// ... use injected dependencies

app/src/androidTest/java/org/ole/planet/myplanet/model/RealmUserTest.kt

Lines changed: 63 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,35 @@
11
package org.ole.planet.myplanet.model
22

3+
import android.content.SharedPreferences
34
import androidx.test.core.app.ApplicationProvider
45
import androidx.test.ext.junit.runners.AndroidJUnit4
56
import androidx.test.platform.app.InstrumentationRegistry
7+
import dagger.Lazy
8+
import io.mockk.mockk
69
import io.realm.Realm
710
import io.realm.RealmConfiguration
8-
import java.util.concurrent.CountDownLatch
9-
import java.util.concurrent.TimeUnit
11+
import kotlinx.coroutines.CoroutineScope
12+
import kotlinx.coroutines.Dispatchers
13+
import kotlinx.coroutines.runBlocking
1014
import org.junit.After
1115
import org.junit.Assert.assertEquals
1216
import org.junit.Before
1317
import org.junit.Test
1418
import org.junit.runner.RunWith
19+
import org.ole.planet.myplanet.data.DatabaseService
20+
import org.ole.planet.myplanet.data.api.ApiInterface
21+
import org.ole.planet.myplanet.repository.ConfigurationsRepository
22+
import org.ole.planet.myplanet.repository.UserRepositoryImpl
23+
import org.ole.planet.myplanet.services.SharedPrefManager
24+
import org.ole.planet.myplanet.services.UploadToShelfService
25+
import org.ole.planet.myplanet.utils.DispatcherProvider
1526

1627
@RunWith(AndroidJUnit4::class)
1728
class RealmUserTest {
1829

1930
private lateinit var realmConfiguration: RealmConfiguration
31+
private lateinit var userRepository: UserRepositoryImpl
32+
private lateinit var databaseService: DatabaseService
2033

2134
@Before
2235
fun setUp() {
@@ -31,6 +44,45 @@ class RealmUserTest {
3144
.build()
3245
Realm.setDefaultConfiguration(realmConfiguration)
3346
}
47+
48+
databaseService = object : DatabaseService {
49+
override val realm: Realm
50+
get() = Realm.getInstance(realmConfiguration)
51+
52+
override fun executeTransaction(transaction: Realm.Transaction) {
53+
realm.executeTransaction(transaction)
54+
}
55+
56+
override fun executeTransactionAsync(
57+
transaction: Realm.Transaction,
58+
onSuccess: Realm.Transaction.OnSuccess,
59+
onError: Realm.Transaction.OnError
60+
) {
61+
realm.executeTransactionAsync(transaction, onSuccess, onError)
62+
}
63+
}
64+
65+
val mockSettings = mockk<SharedPreferences>(relaxed = true)
66+
val mockSharedPrefManager = mockk<SharedPrefManager>(relaxed = true)
67+
val mockApiInterface = mockk<ApiInterface>(relaxed = true)
68+
val mockUploadToShelfService = mockk<Lazy<UploadToShelfService>>(relaxed = true)
69+
val mockContext = ApplicationProvider.getApplicationContext<android.content.Context>()
70+
val mockConfigurationsRepository = mockk<ConfigurationsRepository>(relaxed = true)
71+
val mockAppScope = CoroutineScope(Dispatchers.Unconfined)
72+
val mockDispatcherProvider = mockk<DispatcherProvider>(relaxed = true)
73+
74+
userRepository = UserRepositoryImpl(
75+
databaseService,
76+
Dispatchers.Unconfined,
77+
mockSettings,
78+
mockSharedPrefManager,
79+
mockApiInterface,
80+
mockUploadToShelfService,
81+
mockContext,
82+
mockConfigurationsRepository,
83+
mockAppScope,
84+
mockDispatcherProvider
85+
)
3486
}
3587

3688
@After
@@ -43,8 +95,7 @@ class RealmUserTest {
4395
}
4496

4597
@Test
46-
fun cleanupDuplicateUsers_removesGuestWhenCouchDbUserExists() {
47-
val latch = CountDownLatch(1)
98+
fun cleanupDuplicateUsers_removesGuestWhenCouchDbUserExists() = runBlocking {
4899
InstrumentationRegistry.getInstrumentation().runOnMainSync {
49100
val realm = Realm.getInstance(realmConfiguration)
50101
realm.executeTransaction { r ->
@@ -57,14 +108,10 @@ class RealmUserTest {
57108
name = "testuser"
58109
}
59110
}
60-
61-
RealmUser.cleanupDuplicateUsers(realm) {
62-
latch.countDown()
63-
realm.close() // Close the realm after async transaction finishes
64-
}
111+
realm.close()
65112
}
66113

67-
latch.await(5, TimeUnit.SECONDS)
114+
userRepository.cleanupDuplicateUsers()
68115

69116
InstrumentationRegistry.getInstrumentation().runOnMainSync {
70117
val verifyRealm = Realm.getInstance(realmConfiguration)
@@ -76,8 +123,7 @@ class RealmUserTest {
76123
}
77124

78125
@Test
79-
fun cleanupDuplicateUsers_keepsCouchDbUserWhenGuestExists() {
80-
val latch = CountDownLatch(1)
126+
fun cleanupDuplicateUsers_keepsCouchDbUserWhenGuestExists() = runBlocking {
81127
InstrumentationRegistry.getInstrumentation().runOnMainSync {
82128
val realm = Realm.getInstance(realmConfiguration)
83129
realm.executeTransaction { r ->
@@ -90,14 +136,10 @@ class RealmUserTest {
90136
name = "testuser"
91137
}
92138
}
93-
94-
RealmUser.cleanupDuplicateUsers(realm) {
95-
latch.countDown()
96-
realm.close()
97-
}
139+
realm.close()
98140
}
99141

100-
latch.await(5, TimeUnit.SECONDS)
142+
userRepository.cleanupDuplicateUsers()
101143

102144
InstrumentationRegistry.getInstrumentation().runOnMainSync {
103145
val verifyRealm = Realm.getInstance(realmConfiguration)
@@ -109,8 +151,7 @@ class RealmUserTest {
109151
}
110152

111153
@Test
112-
fun cleanupDuplicateUsers_keepsAllUsersWhenNoDuplicates() {
113-
val latch = CountDownLatch(1)
154+
fun cleanupDuplicateUsers_keepsAllUsersWhenNoDuplicates() = runBlocking {
114155
InstrumentationRegistry.getInstrumentation().runOnMainSync {
115156
val realm = Realm.getInstance(realmConfiguration)
116157
realm.executeTransaction { r ->
@@ -123,14 +164,10 @@ class RealmUserTest {
123164
name = "testuser2"
124165
}
125166
}
126-
127-
RealmUser.cleanupDuplicateUsers(realm) {
128-
latch.countDown()
129-
realm.close()
130-
}
167+
realm.close()
131168
}
132169

133-
latch.await(5, TimeUnit.SECONDS)
170+
userRepository.cleanupDuplicateUsers()
134171

135172
InstrumentationRegistry.getInstrumentation().runOnMainSync {
136173
val verifyRealm = Realm.getInstance(realmConfiguration)

app/src/main/java/org/ole/planet/myplanet/MainApplication.kt

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,9 @@ import kotlinx.coroutines.launch
3535
import kotlinx.coroutines.withContext
3636
import org.ole.planet.myplanet.callback.OnTeamPageListener
3737
import org.ole.planet.myplanet.data.DatabaseService
38-
import org.ole.planet.myplanet.di.ApiClientEntryPoint
39-
import org.ole.planet.myplanet.di.ApplicationScopeEntryPoint
40-
import org.ole.planet.myplanet.di.AutoSyncEntryPoint
38+
import org.ole.planet.myplanet.di.CoreDependenciesEntryPoint
4139
import org.ole.planet.myplanet.di.DefaultPreferences
42-
import org.ole.planet.myplanet.di.RetryQueueEntryPoint
43-
import org.ole.planet.myplanet.di.ServerUrlMapperEntryPoint
44-
import org.ole.planet.myplanet.di.WorkerDependenciesEntryPoint
40+
import org.ole.planet.myplanet.di.NetworkDependenciesEntryPoint
4541
import org.ole.planet.myplanet.model.RealmApkLog
4642
import org.ole.planet.myplanet.repository.ResourcesRepository
4743
import org.ole.planet.myplanet.services.AutoSyncWorker
@@ -54,7 +50,9 @@ import org.ole.planet.myplanet.services.retry.RetryQueueWorker
5450
import org.ole.planet.myplanet.utils.ANRWatchdog
5551
import org.ole.planet.myplanet.utils.DispatcherProvider
5652
import org.ole.planet.myplanet.utils.DownloadUtils.downloadAllFiles
53+
import org.ole.planet.myplanet.utils.FileUtils
5754
import org.ole.planet.myplanet.utils.LocaleUtils
55+
import org.ole.planet.myplanet.utils.MarkdownUtils
5856
import org.ole.planet.myplanet.utils.NetworkUtils.isNetworkConnectedFlow
5957
import org.ole.planet.myplanet.utils.NetworkUtils.startListenNetworkState
6058
import org.ole.planet.myplanet.utils.NetworkUtils.stopListenNetworkState
@@ -117,10 +115,10 @@ class MainApplication : Application(), Application.ActivityLifecycleCallbacks, W
117115
applicationScope.launch {
118116
val entryPoint = EntryPointAccessors.fromApplication(
119117
context,
120-
WorkerDependenciesEntryPoint::class.java
118+
CoreDependenciesEntryPoint::class.java
121119
)
122120
val userSessionManager = entryPoint.userSessionManager()
123-
val spm = EntryPointAccessors.fromApplication(context, AutoSyncEntryPoint::class.java).sharedPrefManager()
121+
val spm = EntryPointAccessors.fromApplication(context, CoreDependenciesEntryPoint::class.java).sharedPrefManager()
124122
try {
125123
val databaseService = (context.applicationContext as MainApplication).databaseService
126124
val model = userSessionManager.getUserModel()
@@ -155,7 +153,7 @@ class MainApplication : Application(), Application.ActivityLifecycleCallbacks, W
155153
urlString: String,
156154
ioDispatcher: kotlinx.coroutines.CoroutineDispatcher = kotlinx.coroutines.Dispatchers.IO
157155
): Boolean {
158-
val entryPoint = EntryPointAccessors.fromApplication(context, ServerUrlMapperEntryPoint::class.java)
156+
val entryPoint = EntryPointAccessors.fromApplication(context, CoreDependenciesEntryPoint::class.java)
159157
val serverUrlMapper = entryPoint.serverUrlMapper()
160158
val mapping = serverUrlMapper.processUrl(urlString)
161159
val urlsToTry = mutableListOf(urlString)
@@ -224,7 +222,9 @@ class MainApplication : Application(), Application.ActivityLifecycleCallbacks, W
224222

225223
private fun performDeferredInitialization() {
226224
applicationScope.launch(Dispatchers.IO) {
225+
FileUtils.warmUp(this@MainApplication)
227226
SecurePrefs.warmUp(this@MainApplication)
227+
MarkdownUtils.warmUp(this@MainApplication)
228228
}
229229
applicationScope.launch {
230230
initApp()
@@ -245,7 +245,7 @@ class MainApplication : Application(), Application.ActivityLifecycleCallbacks, W
245245
private fun setupCriticalProperties() {
246246
applicationScope = EntryPointAccessors.fromApplication(
247247
this,
248-
ApplicationScopeEntryPoint::class.java
248+
CoreDependenciesEntryPoint::class.java
249249
).applicationScope()
250250
}
251251

@@ -261,7 +261,7 @@ class MainApplication : Application(), Application.ActivityLifecycleCallbacks, W
261261
withContext(dispatcherProvider.io) {
262262
EntryPointAccessors.fromApplication(
263263
this@MainApplication,
264-
ApiClientEntryPoint::class.java
264+
NetworkDependenciesEntryPoint::class.java
265265
).apiClient()
266266
apiClientInitialized.complete(Unit)
267267
}
@@ -320,7 +320,7 @@ class MainApplication : Application(), Application.ActivityLifecycleCallbacks, W
320320
try {
321321
val entryPoint = EntryPointAccessors.fromApplication(
322322
this@MainApplication,
323-
RetryQueueEntryPoint::class.java
323+
NetworkDependenciesEntryPoint::class.java
324324
)
325325
entryPoint.retryQueue().recoverStuckOperations()
326326
} catch (e: Exception) {

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,9 +297,10 @@ abstract class BaseResourceFragment : Fragment() {
297297
fun createListView(dbMyLibrary: List<RealmMyLibrary?>, alertDialog: AlertDialog) {
298298
lv = convertView?.findViewById(R.id.alertDialog_listView)
299299
val names = dbMyLibrary.map { it?.title ?: "" }
300-
val adapter = CheckboxAdapter(names) {
300+
val adapter = CheckboxAdapter {
301301
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = ((lv?.adapter as? CheckboxAdapter)?.selectedItemsList?.size ?: 0) > 0
302302
}
303+
adapter.submitList(names)
303304
lv?.layoutManager = LinearLayoutManager(requireActivity().baseContext)
304305
lv?.adapter = adapter
305306
}

app/src/main/java/org/ole/planet/myplanet/di/ApiClientEntryPoint.kt

Lines changed: 0 additions & 12 deletions
This file was deleted.

app/src/main/java/org/ole/planet/myplanet/di/ApiInterfaceEntryPoint.kt

Lines changed: 0 additions & 12 deletions
This file was deleted.

app/src/main/java/org/ole/planet/myplanet/di/ApplicationScopeEntryPoint.kt

Lines changed: 0 additions & 13 deletions
This file was deleted.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package org.ole.planet.myplanet.di
2+
3+
import dagger.hilt.EntryPoint
4+
import dagger.hilt.InstallIn
5+
import dagger.hilt.components.SingletonComponent
6+
import kotlinx.coroutines.CoroutineScope
7+
import org.ole.planet.myplanet.data.DatabaseService
8+
import org.ole.planet.myplanet.services.SharedPrefManager
9+
import org.ole.planet.myplanet.services.UserSessionManager
10+
import org.ole.planet.myplanet.services.sync.ServerUrlMapper
11+
12+
@EntryPoint
13+
@InstallIn(SingletonComponent::class)
14+
interface CoreDependenciesEntryPoint {
15+
@ApplicationScope fun applicationScope(): CoroutineScope
16+
fun sharedPrefManager(): SharedPrefManager
17+
fun databaseService(): DatabaseService
18+
fun userSessionManager(): UserSessionManager
19+
fun serverUrlMapper(): ServerUrlMapper
20+
}

app/src/main/java/org/ole/planet/myplanet/di/DatabaseModule.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ object DatabaseModule {
2929
@Singleton
3030
@RealmDispatcher
3131
fun provideRealmDispatcher(): CoroutineDispatcher {
32-
val handlerThread = HandlerThread("RealmQueryThread")
33-
handlerThread.start()
32+
// Realm async queries and change listeners require a thread with a Looper.
33+
val handlerThread = HandlerThread("RealmQueryThread").also { it.start() }
3434
return Handler(handlerThread.looper).asCoroutineDispatcher()
3535
}
3636

app/src/main/java/org/ole/planet/myplanet/di/DatabaseServiceEntryPoint.kt

Lines changed: 0 additions & 12 deletions
This file was deleted.

0 commit comments

Comments
 (0)