diff --git a/app/src/main/kotlin/ca/rmen/android/poetassistant/about/LicenseActivity.kt b/app/src/main/kotlin/ca/rmen/android/poetassistant/about/LicenseActivity.kt
index 9a2f42dc..3de8659a 100644
--- a/app/src/main/kotlin/ca/rmen/android/poetassistant/about/LicenseActivity.kt
+++ b/app/src/main/kotlin/ca/rmen/android/poetassistant/about/LicenseActivity.kt
@@ -22,17 +22,13 @@ package ca.rmen.android.poetassistant.about
import android.content.Context
import android.content.Intent
import android.os.Bundle
-import android.util.Log
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
-import androidx.annotation.WorkerThread
+import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
+import androidx.compose.runtime.collectAsState
import ca.rmen.android.poetassistant.Constants
-import ca.rmen.android.poetassistant.dagger.DaggerHelper
import ca.rmen.android.poetassistant.theme.AppTheme
-import java.io.BufferedReader
-import java.io.IOException
-import java.io.InputStreamReader
class LicenseActivity : AppCompatActivity() {
companion object {
@@ -52,38 +48,20 @@ class LicenseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
+ val licenseViewModel: LicenseViewModel by viewModels()
val title = intent.getStringExtra(EXTRA_TITLE)!!
val licenseFile = intent.getStringExtra(EXTRA_LICENSE_TEXT_ASSET_FILE)!!
- val threading = DaggerHelper.getMainScreenComponent(this).getThreading()
- threading.execute(
- { readFile(licenseFile) },
- {
- setContent {
- AppTheme {
- LicenseScreen(
- title = title,
- licenseText = it,
- onBack = onBackPressedDispatcher::onBackPressed
- )
- }
- }
- })
- }
-
- @WorkerThread
- private fun readFile(fileName: String): String {
-
- try {
- BufferedReader(InputStreamReader(assets.open(fileName))).use {
- val builder = StringBuilder()
- it.forEachLine { line ->
- builder.append(line).append('\n')
- }
- return builder.toString()
+ licenseViewModel.readLicenseText(licenseFile)
+ setContent {
+ val licenseText = licenseViewModel.licenseText.collectAsState()
+ AppTheme {
+ LicenseScreen(
+ title = title,
+ licenseText = licenseText.value,
+ onBack = onBackPressedDispatcher::onBackPressed
+ )
}
- } catch (e: IOException) {
- Log.e(TAG, "Couldn't read license file $fileName: ${e.message}", e)
- return ""
}
}
+
}
diff --git a/app/src/main/kotlin/ca/rmen/android/poetassistant/about/LicenseViewModel.kt b/app/src/main/kotlin/ca/rmen/android/poetassistant/about/LicenseViewModel.kt
new file mode 100644
index 00000000..de71f339
--- /dev/null
+++ b/app/src/main/kotlin/ca/rmen/android/poetassistant/about/LicenseViewModel.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2025 - present Carmen Alvarez
+ *
+ * This file is part of Poet Assistant.
+ *
+ * Poet Assistant is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Poet Assistant is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Poet Assistant. If not, see .
+ */
+package ca.rmen.android.poetassistant.about
+
+import android.app.Application
+import android.util.Log
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.viewModelScope
+import ca.rmen.android.poetassistant.Constants
+import ca.rmen.android.poetassistant.dagger.DaggerHelper
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.launch
+import java.io.IOException
+import javax.inject.Inject
+
+class LicenseViewModel(private val application: Application) :
+ AndroidViewModel(application) {
+
+ companion object {
+ private val TAG = Constants.TAG + LicenseViewModel::class.java.simpleName
+ }
+
+ init {
+ DaggerHelper.getMainScreenComponent(application).inject(this)
+ }
+
+ @Inject
+ lateinit var ioDispatcher: CoroutineDispatcher
+
+ private val _licenseText = MutableStateFlow("")
+ val licenseText = _licenseText.asStateFlow()
+
+ fun readLicenseText(fileName: String) {
+ viewModelScope.launch(ioDispatcher) {
+ val contents = readFile(fileName)
+ _licenseText.value = contents
+ }
+ }
+
+ private fun readFile(fileName: String): String {
+ try {
+ return application.assets.open(fileName).bufferedReader().use { it.readText() }
+ } catch (e: IOException) {
+ Log.e(TAG, "Couldn't read license file $fileName: ${e.message}", e)
+ return ""
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/ca/rmen/android/poetassistant/dagger/AppComponent.kt b/app/src/main/kotlin/ca/rmen/android/poetassistant/dagger/AppComponent.kt
index cf22b1a2..e7cbcd14 100644
--- a/app/src/main/kotlin/ca/rmen/android/poetassistant/dagger/AppComponent.kt
+++ b/app/src/main/kotlin/ca/rmen/android/poetassistant/dagger/AppComponent.kt
@@ -22,6 +22,7 @@ package ca.rmen.android.poetassistant.dagger
import ca.rmen.android.poetassistant.Favorites
import ca.rmen.android.poetassistant.PoemAudioExport
import ca.rmen.android.poetassistant.Threading
+import ca.rmen.android.poetassistant.about.LicenseViewModel
import ca.rmen.android.poetassistant.main.MainActivity
import ca.rmen.android.poetassistant.main.dictionaries.ResultListAdapterFactory
import ca.rmen.android.poetassistant.main.dictionaries.ResultListHeaderViewModel
@@ -48,6 +49,7 @@ import ca.rmen.android.poetassistant.wotd.WotdEntryViewModel
import ca.rmen.android.poetassistant.wotd.WotdLiveData
import dagger.Component
import dagger.Subcomponent
+import kotlinx.coroutines.CoroutineDispatcher
import javax.inject.Singleton
@Singleton
@@ -64,6 +66,7 @@ interface AppComponent {
fun getFavorites(): Favorites
fun getSettingsPrefs(): SettingsPrefs
fun getThreading(): Threading
+ fun getIODispatcher(): CoroutineDispatcher
fun getResultListAdapterFactory() : ResultListAdapterFactory
}
@@ -75,6 +78,7 @@ interface AppComponent {
fun injectDict(resultListViewModel: ResultListViewModel)
fun inject(rtEntry: RTEntryViewModel)
fun inject(resultListHeaderViewModel: ResultListHeaderViewModel)
+ fun inject(licenseViewModel: LicenseViewModel)
fun inject(readerViewModel: ReaderViewModel)
fun inject(poemAudioExport: PoemAudioExport)
fun inject(rhymerLiveData: RhymerLiveData)
diff --git a/app/src/main/kotlin/ca/rmen/android/poetassistant/dagger/ThreadingModule.kt b/app/src/main/kotlin/ca/rmen/android/poetassistant/dagger/ThreadingModule.kt
index e87dc44c..e0c4808e 100644
--- a/app/src/main/kotlin/ca/rmen/android/poetassistant/dagger/ThreadingModule.kt
+++ b/app/src/main/kotlin/ca/rmen/android/poetassistant/dagger/ThreadingModule.kt
@@ -23,6 +23,7 @@ import ca.rmen.android.poetassistant.CoroutineThreading
import ca.rmen.android.poetassistant.Threading
import dagger.Module
import dagger.Provides
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import javax.inject.Singleton
@@ -31,4 +32,9 @@ class ThreadingModule {
@Provides
@Singleton
fun providesThreading() : Threading = CoroutineThreading(Dispatchers.Default, Dispatchers.Main)
+
+
+ @Provides
+ @Singleton
+ fun providesIODispatcher(): CoroutineDispatcher = Dispatchers.IO
}
\ No newline at end of file
diff --git a/app/src/sharedTest/kotlin/ca/rmen/android/poetassistant/dagger/TestThreadingModule.kt b/app/src/sharedTest/kotlin/ca/rmen/android/poetassistant/dagger/TestThreadingModule.kt
index 191ca9fa..f850fafd 100644
--- a/app/src/sharedTest/kotlin/ca/rmen/android/poetassistant/dagger/TestThreadingModule.kt
+++ b/app/src/sharedTest/kotlin/ca/rmen/android/poetassistant/dagger/TestThreadingModule.kt
@@ -23,6 +23,9 @@ import ca.rmen.android.poetassistant.InstrumentationThreading
import ca.rmen.android.poetassistant.Threading
import dagger.Module
import dagger.Provides
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
import javax.inject.Singleton
@Module
@@ -31,4 +34,9 @@ class TestThreadingModule {
@Provides
@Singleton
fun providesThreading(): Threading = InstrumentationThreading()
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @Provides
+ @Singleton
+ fun providesIODispatcher(): CoroutineDispatcher = UnconfinedTestDispatcher()
}
diff --git a/app/src/test/kotlin/ca/rmen/android/poetassistant/dagger/JunitThreadingModule.kt b/app/src/test/kotlin/ca/rmen/android/poetassistant/dagger/JunitThreadingModule.kt
index 5f87eb6e..1ae67abf 100644
--- a/app/src/test/kotlin/ca/rmen/android/poetassistant/dagger/JunitThreadingModule.kt
+++ b/app/src/test/kotlin/ca/rmen/android/poetassistant/dagger/JunitThreadingModule.kt
@@ -23,6 +23,9 @@ import ca.rmen.android.poetassistant.JunitThreading
import ca.rmen.android.poetassistant.Threading
import dagger.Module
import dagger.Provides
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
import javax.inject.Singleton
@Module
@@ -30,4 +33,9 @@ class JunitThreadingModule {
@Provides
@Singleton
fun providesThreading() : Threading = JunitThreading()
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @Provides
+ @Singleton
+ fun providesIODispatcher(): CoroutineDispatcher = UnconfinedTestDispatcher()
}