Use coroutines instead of SwingUtilities

This commit is contained in:
Syer10
2021-05-26 19:25:55 -04:00
parent 8d64c7e0dc
commit 29629cab9a
18 changed files with 124 additions and 77 deletions

View File

@@ -6,8 +6,7 @@
package ca.gosyer.common.io
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import ca.gosyer.util.lang.withIOContext
import okio.BufferedSink
import okio.Source
import okio.buffer
@@ -15,7 +14,7 @@ import okio.sink
import java.io.File
suspend fun Source.saveTo(file: File) {
withContext(Dispatchers.IO) {
withIOContext {
use { source ->
file.sink().buffer().use { it.writeAll(source) }
}
@@ -23,7 +22,7 @@ suspend fun Source.saveTo(file: File) {
}
suspend fun Source.copyTo(sink: BufferedSink) {
withContext(Dispatchers.IO) {
withIOContext {
use { source ->
sink.use { it.writeAll(source) }
}

View File

@@ -7,16 +7,15 @@
package ca.gosyer.data.server
import ca.gosyer.BuildConfig
import ca.gosyer.util.lang.withIOContext
import ca.gosyer.util.system.CKLogger
import ca.gosyer.util.system.userDataDir
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import mu.KotlinLogging
import java.io.BufferedReader
import java.io.File
@@ -75,7 +74,7 @@ class ServerService @Inject constructor(
copyJar(jarFile)
} else {
try {
val jarVersion = withContext(Dispatchers.IO) {
val jarVersion = withIOContext {
JarInputStream(jarFile.inputStream()).use { jar ->
jar.manifest?.mainAttributes?.getValue("Specification-Version")
}

View File

@@ -13,6 +13,7 @@ import ca.gosyer.data.server.requests.backupExportRequest
import ca.gosyer.data.server.requests.backupFileExportRequest
import ca.gosyer.data.server.requests.backupFileImportRequest
import ca.gosyer.data.server.requests.backupImportRequest
import ca.gosyer.util.lang.withIOContext
import io.ktor.client.request.forms.formData
import io.ktor.client.request.forms.submitFormWithBinaryData
import io.ktor.client.statement.HttpResponse
@@ -21,8 +22,6 @@ import io.ktor.http.Headers
import io.ktor.http.HttpHeaders
import io.ktor.http.content.MultiPartData
import io.ktor.http.contentType
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.File
import javax.inject.Inject
@@ -31,7 +30,7 @@ class BackupInteractionHandler @Inject constructor(
serverPreferences: ServerPreferences
) : BaseInteractionHandler(client, serverPreferences) {
suspend fun importBackupFile(file: File) = withContext(Dispatchers.IO) {
suspend fun importBackupFile(file: File) = withIOContext {
client.submitFormWithBinaryData<HttpResponse>(
serverUrl + backupFileImportRequest(),
formData = formData {
@@ -46,7 +45,7 @@ class BackupInteractionHandler @Inject constructor(
)
}
suspend fun importBackup(backup: Backup) = withContext(Dispatchers.IO) {
suspend fun importBackup(backup: Backup) = withIOContext {
client.postRepeat<HttpResponse>(
serverUrl + backupImportRequest()
) {
@@ -55,13 +54,13 @@ class BackupInteractionHandler @Inject constructor(
}
}
suspend fun exportBackupFile() = withContext(Dispatchers.IO) {
suspend fun exportBackupFile() = withIOContext {
client.getRepeat<MultiPartData>(
serverUrl + backupFileExportRequest()
)
}
suspend fun exportBackup() = withContext(Dispatchers.IO) {
suspend fun exportBackup() = withIOContext {
client.getRepeat<Backup>(
serverUrl + backupExportRequest()
)

View File

@@ -19,11 +19,10 @@ import ca.gosyer.data.server.requests.getCategoriesQuery
import ca.gosyer.data.server.requests.getMangaCategoriesQuery
import ca.gosyer.data.server.requests.getMangaInCategoryQuery
import ca.gosyer.data.server.requests.removeMangaFromCategoryRequest
import ca.gosyer.util.lang.withIOContext
import io.ktor.client.statement.HttpResponse
import io.ktor.http.HttpMethod
import io.ktor.http.Parameters
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import javax.inject.Inject
class CategoryInteractionHandler @Inject constructor(
@@ -31,7 +30,7 @@ class CategoryInteractionHandler @Inject constructor(
serverPreferences: ServerPreferences
) : BaseInteractionHandler(client, serverPreferences) {
suspend fun getMangaCategories(mangaId: Long) = withContext(Dispatchers.IO) {
suspend fun getMangaCategories(mangaId: Long) = withIOContext {
client.getRepeat<List<Category>>(
serverUrl + getMangaCategoriesQuery(mangaId)
)
@@ -39,7 +38,7 @@ class CategoryInteractionHandler @Inject constructor(
suspend fun getMangaCategories(manga: Manga) = getMangaCategories(manga.id)
suspend fun addMangaToCategory(mangaId: Long, categoryId: Long) = withContext(Dispatchers.IO) {
suspend fun addMangaToCategory(mangaId: Long, categoryId: Long) = withIOContext {
client.getRepeat<HttpResponse>(
serverUrl + addMangaToCategoryQuery(mangaId, categoryId)
)
@@ -48,7 +47,7 @@ class CategoryInteractionHandler @Inject constructor(
suspend fun addMangaToCategory(manga: Manga, categoryId: Long) = addMangaToCategory(manga.id, categoryId)
suspend fun addMangaToCategory(mangaId: Long, category: Category) = addMangaToCategory(mangaId, category.id)
suspend fun removeMangaFromCategory(mangaId: Long, categoryId: Long) = withContext(Dispatchers.IO) {
suspend fun removeMangaFromCategory(mangaId: Long, categoryId: Long) = withIOContext {
client.deleteRepeat<HttpResponse>(
serverUrl + removeMangaFromCategoryRequest(mangaId, categoryId)
)
@@ -57,13 +56,13 @@ class CategoryInteractionHandler @Inject constructor(
suspend fun removeMangaFromCategory(manga: Manga, categoryId: Long) = removeMangaFromCategory(manga.id, categoryId)
suspend fun removeMangaFromCategory(mangaId: Long, category: Category) = removeMangaFromCategory(mangaId, category.id)
suspend fun getCategories() = withContext(Dispatchers.IO) {
suspend fun getCategories() = withIOContext {
client.getRepeat<List<Category>>(
serverUrl + getCategoriesQuery()
)
}
suspend fun createCategory(name: String) = withContext(Dispatchers.IO) {
suspend fun createCategory(name: String) = withIOContext {
client.submitFormRepeat<HttpResponse>(
serverUrl + createCategoryRequest(),
formParameters = Parameters.build {
@@ -72,7 +71,7 @@ class CategoryInteractionHandler @Inject constructor(
)
}
suspend fun modifyCategory(categoryId: Long, name: String? = null, isLanding: Boolean? = null) = withContext(Dispatchers.IO) {
suspend fun modifyCategory(categoryId: Long, name: String? = null, isLanding: Boolean? = null) = withIOContext {
client.submitFormRepeat<HttpResponse>(
serverUrl + categoryModifyRequest(categoryId),
formParameters = Parameters.build {
@@ -89,7 +88,7 @@ class CategoryInteractionHandler @Inject constructor(
}
suspend fun modifyCategory(category: Category, name: String? = null, isLanding: Boolean? = null) = modifyCategory(category.id, name, isLanding)
suspend fun reorderCategory(categoryId: Long, to: Int, from: Int) = withContext(Dispatchers.IO) {
suspend fun reorderCategory(categoryId: Long, to: Int, from: Int) = withIOContext {
client.submitFormRepeat<HttpResponse>(
serverUrl + categoryReorderRequest(categoryId),
formParameters = Parameters.build {
@@ -102,14 +101,14 @@ class CategoryInteractionHandler @Inject constructor(
}
suspend fun reorderCategory(category: Category, to: Int, from: Int) = reorderCategory(category.id, to, from)
suspend fun deleteCategory(categoryId: Long) = withContext(Dispatchers.IO) {
suspend fun deleteCategory(categoryId: Long) = withIOContext {
client.deleteRepeat<HttpResponse>(
serverUrl + categoryDeleteRequest(categoryId)
)
}
suspend fun deleteCategory(category: Category) = deleteCategory(category.id)
suspend fun getMangaFromCategory(categoryId: Long) = withContext(Dispatchers.IO) {
suspend fun getMangaFromCategory(categoryId: Long) = withIOContext {
client.getRepeat<List<Manga>>(
serverUrl + getMangaInCategoryQuery(categoryId)
)

View File

@@ -14,12 +14,11 @@ import ca.gosyer.data.server.requests.getChapterQuery
import ca.gosyer.data.server.requests.getMangaChaptersQuery
import ca.gosyer.data.server.requests.getPageQuery
import ca.gosyer.data.server.requests.updateChapterRequest
import ca.gosyer.util.lang.withIOContext
import io.ktor.client.request.parameter
import io.ktor.client.statement.HttpResponse
import io.ktor.http.HttpMethod
import io.ktor.http.Parameters
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import javax.inject.Inject
class ChapterInteractionHandler @Inject constructor(
@@ -27,7 +26,7 @@ class ChapterInteractionHandler @Inject constructor(
serverPreferences: ServerPreferences
) : BaseInteractionHandler(client, serverPreferences) {
suspend fun getChapters(mangaId: Long, refresh: Boolean = false) = withContext(Dispatchers.IO) {
suspend fun getChapters(mangaId: Long, refresh: Boolean = false) = withIOContext {
client.getRepeat<List<Chapter>>(
serverUrl + getMangaChaptersQuery(mangaId)
) {
@@ -41,7 +40,7 @@ class ChapterInteractionHandler @Inject constructor(
suspend fun getChapters(manga: Manga, refresh: Boolean = false) = getChapters(manga.id, refresh)
suspend fun getChapter(mangaId: Long, chapterIndex: Int) = withContext(Dispatchers.IO) {
suspend fun getChapter(mangaId: Long, chapterIndex: Int) = withIOContext {
client.getRepeat<Chapter>(
serverUrl + getChapterQuery(mangaId, chapterIndex)
)
@@ -60,7 +59,7 @@ class ChapterInteractionHandler @Inject constructor(
bookmarked: Boolean? = null,
lastPageRead: Int? = null,
markPreviousRead: Boolean? = null
) = withContext(Dispatchers.IO) {
) = withIOContext {
client.submitFormRepeat<HttpResponse>(
serverUrl + updateChapterRequest(mangaId, chapterIndex),
formParameters = Parameters.build {
@@ -114,7 +113,7 @@ class ChapterInteractionHandler @Inject constructor(
markPreviousRead
)
suspend fun getPage(mangaId: Long, chapterIndex: Int, pageNum: Int) = withContext(Dispatchers.IO) {
suspend fun getPage(mangaId: Long, chapterIndex: Int, pageNum: Int) = withIOContext {
imageFromUrl(
client,
serverUrl + getPageQuery(mangaId, chapterIndex, pageNum)

View File

@@ -14,9 +14,8 @@ import ca.gosyer.data.server.requests.apkInstallQuery
import ca.gosyer.data.server.requests.apkUninstallQuery
import ca.gosyer.data.server.requests.apkUpdateQuery
import ca.gosyer.data.server.requests.extensionListQuery
import ca.gosyer.util.lang.withIOContext
import io.ktor.client.statement.HttpResponse
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import javax.inject.Inject
class ExtensionInteractionHandler @Inject constructor(
@@ -24,31 +23,31 @@ class ExtensionInteractionHandler @Inject constructor(
serverPreferences: ServerPreferences
) : BaseInteractionHandler(client, serverPreferences) {
suspend fun getExtensionList() = withContext(Dispatchers.IO) {
suspend fun getExtensionList() = withIOContext {
client.getRepeat<List<Extension>>(
serverUrl + extensionListQuery()
)
}
suspend fun installExtension(extension: Extension) = withContext(Dispatchers.IO) {
suspend fun installExtension(extension: Extension) = withIOContext {
client.getRepeat<HttpResponse>(
serverUrl + apkInstallQuery(extension.pkgName)
)
}
suspend fun updateExtension(extension: Extension) = withContext(Dispatchers.IO) {
suspend fun updateExtension(extension: Extension) = withIOContext {
client.getRepeat<HttpResponse>(
serverUrl + apkUpdateQuery(extension.pkgName)
)
}
suspend fun uninstallExtension(extension: Extension) = withContext(Dispatchers.IO) {
suspend fun uninstallExtension(extension: Extension) = withIOContext {
client.getRepeat<HttpResponse>(
serverUrl + apkUninstallQuery(extension.pkgName)
)
}
suspend fun getApkIcon(extension: Extension) = withContext(Dispatchers.IO) {
suspend fun getApkIcon(extension: Extension) = withIOContext {
imageFromUrl(
client,
serverUrl + apkIconQuery(extension.apkName)

View File

@@ -12,9 +12,8 @@ import ca.gosyer.data.server.ServerPreferences
import ca.gosyer.data.server.requests.addMangaToLibraryQuery
import ca.gosyer.data.server.requests.getLibraryQuery
import ca.gosyer.data.server.requests.removeMangaFromLibraryRequest
import ca.gosyer.util.lang.withIOContext
import io.ktor.client.statement.HttpResponse
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import javax.inject.Inject
class LibraryInteractionHandler @Inject constructor(
@@ -22,13 +21,13 @@ class LibraryInteractionHandler @Inject constructor(
serverPreferences: ServerPreferences
) : BaseInteractionHandler(client, serverPreferences) {
suspend fun getLibraryManga() = withContext(Dispatchers.IO) {
suspend fun getLibraryManga() = withIOContext {
client.getRepeat<List<Manga>>(
serverUrl + getLibraryQuery()
)
}
suspend fun addMangaToLibrary(mangaId: Long) = withContext(Dispatchers.IO) {
suspend fun addMangaToLibrary(mangaId: Long) = withIOContext {
client.getRepeat<HttpResponse>(
serverUrl + addMangaToLibraryQuery(mangaId)
)
@@ -36,7 +35,7 @@ class LibraryInteractionHandler @Inject constructor(
suspend fun addMangaToLibrary(manga: Manga) = addMangaToLibrary(manga.id)
suspend fun removeMangaFromLibrary(mangaId: Long) = withContext(Dispatchers.IO) {
suspend fun removeMangaFromLibrary(mangaId: Long) = withIOContext {
client.deleteRepeat<HttpResponse>(
serverUrl + removeMangaFromLibraryRequest(mangaId)
)

View File

@@ -11,9 +11,8 @@ import ca.gosyer.data.server.Http
import ca.gosyer.data.server.ServerPreferences
import ca.gosyer.data.server.requests.mangaQuery
import ca.gosyer.data.server.requests.mangaThumbnailQuery
import ca.gosyer.util.lang.withIOContext
import io.ktor.client.request.parameter
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import javax.inject.Inject
class MangaInteractionHandler @Inject constructor(
@@ -21,7 +20,7 @@ class MangaInteractionHandler @Inject constructor(
serverPreferences: ServerPreferences
) : BaseInteractionHandler(client, serverPreferences) {
suspend fun getManga(mangaId: Long, refresh: Boolean = false) = withContext(Dispatchers.IO) {
suspend fun getManga(mangaId: Long, refresh: Boolean = false) = withIOContext {
client.getRepeat<Manga>(
serverUrl + mangaQuery(mangaId)
) {
@@ -35,7 +34,7 @@ class MangaInteractionHandler @Inject constructor(
suspend fun getManga(manga: Manga, refresh: Boolean = false) = getManga(manga.id, refresh)
suspend fun getMangaThumbnail(mangaId: Long) = withContext(Dispatchers.IO) {
suspend fun getMangaThumbnail(mangaId: Long) = withIOContext {
imageFromUrl(
client,
serverUrl + mangaThumbnailQuery(mangaId)

View File

@@ -17,9 +17,8 @@ import ca.gosyer.data.server.requests.sourceLatestQuery
import ca.gosyer.data.server.requests.sourceListQuery
import ca.gosyer.data.server.requests.sourcePopularQuery
import ca.gosyer.data.server.requests.sourceSearchQuery
import ca.gosyer.util.lang.withIOContext
import io.ktor.client.statement.HttpResponse
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import javax.inject.Inject
class SourceInteractionHandler @Inject constructor(
@@ -27,13 +26,13 @@ class SourceInteractionHandler @Inject constructor(
serverPreferences: ServerPreferences
) : BaseInteractionHandler(client, serverPreferences) {
suspend fun getSourceList() = withContext(Dispatchers.IO) {
suspend fun getSourceList() = withIOContext {
client.getRepeat<List<Source>>(
serverUrl + sourceListQuery()
)
}
suspend fun getSourceInfo(sourceId: Long) = withContext(Dispatchers.IO) {
suspend fun getSourceInfo(sourceId: Long) = withIOContext {
client.getRepeat<Source>(
serverUrl + sourceInfoQuery(sourceId)
)
@@ -41,7 +40,7 @@ class SourceInteractionHandler @Inject constructor(
suspend fun getSourceInfo(source: Source) = getSourceInfo(source.id)
suspend fun getPopularManga(sourceId: Long, pageNum: Int) = withContext(Dispatchers.IO) {
suspend fun getPopularManga(sourceId: Long, pageNum: Int) = withIOContext {
client.getRepeat<MangaPage>(
serverUrl + sourcePopularQuery(sourceId, pageNum)
)
@@ -52,7 +51,7 @@ class SourceInteractionHandler @Inject constructor(
pageNum
)
suspend fun getLatestManga(sourceId: Long, pageNum: Int) = withContext(Dispatchers.IO) {
suspend fun getLatestManga(sourceId: Long, pageNum: Int) = withIOContext {
client.getRepeat<MangaPage>(
serverUrl + sourceLatestQuery(sourceId, pageNum)
)
@@ -64,13 +63,13 @@ class SourceInteractionHandler @Inject constructor(
)
// TODO: 2021-03-14
suspend fun getGlobalSearchResults(searchTerm: String) = withContext(Dispatchers.IO) {
suspend fun getGlobalSearchResults(searchTerm: String) = withIOContext {
client.getRepeat<HttpResponse>(
serverUrl + globalSearchQuery(searchTerm)
)
}
suspend fun getSearchResults(sourceId: Long, searchTerm: String, pageNum: Int) = withContext(Dispatchers.IO) {
suspend fun getSearchResults(sourceId: Long, searchTerm: String, pageNum: Int) = withIOContext {
client.getRepeat<MangaPage>(
serverUrl + sourceSearchQuery(sourceId, searchTerm, pageNum)
)
@@ -83,7 +82,7 @@ class SourceInteractionHandler @Inject constructor(
)
// TODO: 2021-03-14
suspend fun getFilterList(sourceId: Long) = withContext(Dispatchers.IO) {
suspend fun getFilterList(sourceId: Long) = withIOContext {
client.getRepeat<HttpResponse>(
serverUrl + getFilterListQuery(sourceId)
)

View File

@@ -28,8 +28,10 @@ import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import ca.gosyer.ui.base.theme.AppTheme
import javax.swing.SwingUtilities
import ca.gosyer.util.lang.launchUI
import kotlinx.coroutines.DelicateCoroutinesApi
@OptIn(DelicateCoroutinesApi::class)
@Suppress("FunctionName")
fun WindowDialog(
title: String = "Dialog",
@@ -43,7 +45,7 @@ fun WindowDialog(
onPositiveButton: (() -> Unit)? = null,
keyboardShortcuts: List<KeyboardShortcut> = emptyList(),
row: @Composable (RowScope.() -> Unit)
) = SwingUtilities.invokeLater {
) = launchUI {
val window = AppWindow(
title = title,
size = size,
@@ -96,6 +98,7 @@ fun WindowDialog(
}
}
@OptIn(DelicateCoroutinesApi::class)
fun WindowDialog(
title: String = "Dialog",
size: IntSize = IntSize(400, 200),
@@ -104,7 +107,7 @@ fun WindowDialog(
keyboardShortcuts: List<KeyboardShortcut> = emptyList(),
buttons: @Composable (AppWindow) -> Unit,
content: @Composable (AppWindow) -> Unit
) = SwingUtilities.invokeLater {
) = launchUI {
val window = AppWindow(
title = title,
size = size,

View File

@@ -21,6 +21,8 @@ import ca.gosyer.data.ui.model.ThemeMode
import ca.gosyer.data.ui.model.WindowSettings
import ca.gosyer.ui.base.components.LoadingScreen
import ca.gosyer.ui.base.theme.AppTheme
import ca.gosyer.util.lang.launchUI
import ca.gosyer.util.lang.withUIContext
import ca.gosyer.util.system.getAsFlow
import com.github.weisj.darklaf.LafManager
import com.github.weisj.darklaf.theme.DarculaTheme
@@ -35,7 +37,6 @@ import org.apache.logging.log4j.core.config.Configurator
import toothpick.configuration.Configuration
import toothpick.ktp.KTP
import toothpick.ktp.extension.getInstance
import javax.swing.SwingUtilities
@OptIn(DelicateCoroutinesApi::class)
fun main() {
@@ -72,7 +73,7 @@ fun main() {
ThemeMode.Dark -> DarculaTheme()
}
LafManager.enableLogging(BuildConfig.DEBUG)
SwingUtilities.invokeLater {
withUIContext {
LafManager.install(theme)
}
}
@@ -85,7 +86,7 @@ fun main() {
maximized
) = windowSettings.get().get()
SwingUtilities.invokeLater {
launchUI {
val window = AppWindow(
title = BuildConfig.NAME,
size = size,

View File

@@ -14,14 +14,13 @@ import ca.gosyer.data.server.interactions.LibraryInteractionHandler
import ca.gosyer.data.server.interactions.MangaInteractionHandler
import ca.gosyer.data.ui.UiPreferences
import ca.gosyer.ui.base.vm.ViewModel
import ca.gosyer.util.lang.withIOContext
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.text.DateFormat
import java.text.SimpleDateFormat
import java.util.Locale
@@ -59,7 +58,7 @@ class MangaMenuViewModel @Inject constructor(
}
}
private suspend fun refreshMangaAsync(mangaId: Long) = withContext(Dispatchers.IO) {
private suspend fun refreshMangaAsync(mangaId: Long) = withIOContext {
async {
try {
_manga.value = mangaHandler.getManga(mangaId)
@@ -69,7 +68,7 @@ class MangaMenuViewModel @Inject constructor(
}
}
private suspend fun refreshChaptersAsync(mangaId: Long) = withContext(Dispatchers.IO) {
private suspend fun refreshChaptersAsync(mangaId: Long) = withIOContext {
async {
try {
_chapters.value = chapterHandler.getChapters(mangaId)

View File

@@ -44,12 +44,13 @@ import ca.gosyer.ui.base.theme.AppTheme
import ca.gosyer.ui.base.vm.viewModel
import ca.gosyer.ui.reader.model.ReaderChapter
import ca.gosyer.ui.reader.model.ReaderPage
import ca.gosyer.util.lang.launchUI
import com.google.accompanist.pager.HorizontalPager
import com.google.accompanist.pager.VerticalPager
import com.google.accompanist.pager.rememberPagerState
import toothpick.ktp.extension.getInstance
import javax.swing.SwingUtilities
import kotlinx.coroutines.DelicateCoroutinesApi
@OptIn(DelicateCoroutinesApi::class)
fun openReaderMenu(chapterIndex: Int, mangaId: Long) {
val windowSettings = AppScope.getInstance<UiPreferences>()
.readerWindow()
@@ -59,7 +60,7 @@ fun openReaderMenu(chapterIndex: Int, mangaId: Long) {
maximized
) = windowSettings.get().get()
SwingUtilities.invokeLater {
launchUI {
val window = AppWindow(
"TachideskJUI - Reader",
size = size,

View File

@@ -8,16 +8,18 @@ package ca.gosyer.util.compose
import androidx.compose.desktop.AppManager
import androidx.compose.ui.unit.IntOffset
import ca.gosyer.util.lang.launchUI
import com.github.weisj.darklaf.listener.MouseClickListener
import kotlinx.coroutines.DelicateCoroutinesApi
import javax.swing.Icon
import javax.swing.JMenuItem
import javax.swing.JPopupMenu
import javax.swing.JSeparator
import javax.swing.SwingUtilities
class ContextMenu internal constructor() {
internal val items = mutableListOf<Pair<Any, (() -> Unit)?>>()
@OptIn(DelicateCoroutinesApi::class)
internal fun popupMenu() = JPopupMenu().apply {
val window = AppManager.focusedWindow
var mouseListener: MouseClickListener? = null
@@ -26,14 +28,14 @@ class ContextMenu internal constructor() {
mouseListener?.let { window?.removeMouseListener(it) }
}
fun (() -> Unit)?.andClose() {
SwingUtilities.invokeLater {
launchUI {
close()
this?.invoke()
this@andClose?.invoke()
}
}
mouseListener = MouseClickListener {
SwingUtilities.invokeLater {
launchUI {
close()
}
}

View File

@@ -0,0 +1,45 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package ca.gosyer.util.lang
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@DelicateCoroutinesApi
fun launch(
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
) = GlobalScope.launch(Dispatchers.Default, start, block)
@DelicateCoroutinesApi
fun launchUI(
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
) = GlobalScope.launch(Dispatchers.Main, start, block)
@DelicateCoroutinesApi
fun launchIO(
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
) = GlobalScope.launch(Dispatchers.IO, start, block)
suspend fun <T> withDefaultContext(
block: suspend CoroutineScope.() -> T
) = withContext(Dispatchers.Default, block)
suspend fun <T> withUIContext(
block: suspend CoroutineScope.() -> T
) = withContext(Dispatchers.Main, block)
suspend fun <T> withIOContext(
block: suspend CoroutineScope.() -> T
) = withContext(Dispatchers.IO, block)

View File

@@ -8,4 +8,5 @@ package ca.gosyer.util.lang
import java.util.Locale
fun String.capitalize() = replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }
fun String.capitalize(locale: Locale = Locale.getDefault()) =
replaceFirstChar { if (it.isLowerCase()) it.titlecase(locale) else it.toString() }

View File

@@ -7,11 +7,12 @@
package ca.gosyer.util.system
import ca.gosyer.BuildConfig
import ca.gosyer.util.lang.launchUI
import kotlinx.coroutines.DelicateCoroutinesApi
import net.harawata.appdirs.AppDirs
import net.harawata.appdirs.AppDirsFactory
import java.io.File
import javax.swing.JFileChooser
import javax.swing.SwingUtilities
import javax.swing.filechooser.FileNameExtensionFilter
val appDirs: AppDirs by lazy {
@@ -58,6 +59,7 @@ fun fileSaver(
* @param onError the listener that is called when picking a file exited with a error
* @param onApprove the listener that is called when picking a file is completed
*/
@OptIn(DelicateCoroutinesApi::class)
private fun fileChooser(
saving: Boolean = false,
builder: JFileChooser.() -> Unit = {},
@@ -66,7 +68,7 @@ private fun fileChooser(
onApprove: (JFileChooser) -> Unit,
extension: String? = null,
defaultFileName: String = ""
) = SwingUtilities.invokeLater {
) = launchUI {
val fileChooser = JFileChooser()
.apply {
val details = actionMap.get("viewTypeDetails")