一些优化
This commit is contained in:
@@ -45,6 +45,7 @@ import io.legado.app.domain.usecase.CacheBookChaptersUseCase
|
||||
import io.legado.app.domain.usecase.ChangeBookSourceUseCase
|
||||
import io.legado.app.domain.usecase.ClearBookCacheUseCase
|
||||
import io.legado.app.domain.usecase.DeleteBooksUseCase
|
||||
import io.legado.app.domain.usecase.ExploreKindUiUseCase
|
||||
import io.legado.app.domain.usecase.GetReadingProgressUseCase
|
||||
import io.legado.app.domain.usecase.RemoveBookGroupAssignmentUseCase
|
||||
import io.legado.app.domain.usecase.ResolveBookShelfStateUseCase
|
||||
@@ -103,7 +104,6 @@ import io.legado.app.ui.rss.favorites.RssFavoritesViewModel
|
||||
import io.legado.app.ui.rss.read.ReadRssViewModel
|
||||
import io.legado.app.ui.rss.source.manage.RssSourceViewModel
|
||||
import io.legado.app.ui.rss.subscription.RuleSubViewModel
|
||||
import io.legado.app.ui.widget.components.explore.ExploreKindUiUseCase
|
||||
import org.koin.core.module.dsl.singleOf
|
||||
import org.koin.core.module.dsl.viewModel
|
||||
import org.koin.core.module.dsl.viewModelOf
|
||||
|
||||
+5
-5
@@ -1,4 +1,4 @@
|
||||
package io.legado.app.ui.widget.components.explore
|
||||
package io.legado.app.domain.usecase
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.script.rhino.runScriptWithContext
|
||||
@@ -10,7 +10,7 @@ import io.legado.app.data.entities.rule.ExploreKind
|
||||
import io.legado.app.help.source.getExploreInfoMap
|
||||
import io.legado.app.ui.login.SourceLoginJsExtensions
|
||||
import io.legado.app.utils.InfoMap
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
@@ -76,7 +76,7 @@ class ExploreKindUiUseCase(
|
||||
override fun reUiView() = onRefreshKinds()
|
||||
}
|
||||
)
|
||||
withContext(IO) {
|
||||
withContext(Dispatchers.IO) {
|
||||
evalButtonClick(actionText, source, effectiveInfoMap, title, sourceJsExtensions)
|
||||
}
|
||||
}
|
||||
@@ -92,7 +92,7 @@ class ExploreKindUiUseCase(
|
||||
|
||||
private suspend fun getOrLoadBookSource(sourceUrl: String): BookSource? {
|
||||
sourceCache[sourceUrl]?.let { return it }
|
||||
return withContext(IO) {
|
||||
return withContext(Dispatchers.IO) {
|
||||
bookSourceDao.getBookSource(sourceUrl)
|
||||
}?.also { source ->
|
||||
sourceCache[sourceUrl] = source
|
||||
@@ -127,4 +127,4 @@ class ExploreKindUiUseCase(
|
||||
AppLog.put("ExploreUI Button $name JavaScript error", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,6 +61,7 @@ import dev.chrisbanes.haze.HazeState
|
||||
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
|
||||
import io.legado.app.data.entities.SearchBook
|
||||
import io.legado.app.domain.model.BookShelfState
|
||||
import io.legado.app.domain.usecase.ExploreKindUiUseCase
|
||||
import io.legado.app.ui.main.bookCoverSharedElementKey
|
||||
import io.legado.app.ui.theme.LegadoTheme
|
||||
import io.legado.app.ui.theme.ThemeResolver
|
||||
@@ -74,7 +75,6 @@ import io.legado.app.ui.widget.components.book.SearchBookListItem
|
||||
import io.legado.app.ui.widget.components.button.AnimatedTextButton
|
||||
import io.legado.app.ui.widget.components.card.TextCard
|
||||
import io.legado.app.ui.widget.components.explore.ExploreKindMultiTypeItem
|
||||
import io.legado.app.ui.widget.components.explore.ExploreKindUiUseCase
|
||||
import io.legado.app.ui.widget.components.explore.calculateExploreKindRows
|
||||
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu
|
||||
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
|
||||
|
||||
@@ -36,7 +36,7 @@ import io.legado.app.ui.widget.components.alert.AppAlertDialog
|
||||
import io.legado.app.ui.widget.components.button.ConfirmDismissButtonsRow
|
||||
import io.legado.app.ui.widget.components.button.MediumIconButton
|
||||
import io.legado.app.ui.widget.components.card.GlassCard
|
||||
import io.legado.app.ui.widget.components.cover.CoilBookCover
|
||||
import io.legado.app.ui.widget.components.image.cover.CoilBookCover
|
||||
import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet
|
||||
import io.legado.app.ui.widget.components.settingItem.CompactDropdownSettingItem
|
||||
import io.legado.app.ui.widget.components.settingItem.CompactSwitchSettingItem
|
||||
|
||||
@@ -91,9 +91,9 @@ import io.legado.app.ui.widget.components.AppTextField
|
||||
import io.legado.app.ui.widget.components.alert.AppAlertDialog
|
||||
import io.legado.app.ui.widget.components.card.GlassCard
|
||||
import io.legado.app.ui.widget.components.card.TextCard
|
||||
import io.legado.app.ui.widget.components.cover.CoilBookCover
|
||||
import io.legado.app.ui.widget.components.cover.buildCoverImageRequest
|
||||
import io.legado.app.ui.widget.components.icon.AppIcon
|
||||
import io.legado.app.ui.widget.components.image.cover.CoilBookCover
|
||||
import io.legado.app.ui.widget.components.image.cover.buildCoverImageRequest
|
||||
import io.legado.app.ui.widget.components.log.AppLogSheet
|
||||
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu
|
||||
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
|
||||
|
||||
@@ -77,7 +77,7 @@ import io.legado.app.ui.widget.components.button.SmallIconButton
|
||||
import io.legado.app.ui.widget.components.card.GlassCard
|
||||
import io.legado.app.ui.widget.components.card.SelectionItemCard
|
||||
import io.legado.app.ui.widget.components.checkBox.AppCheckbox
|
||||
import io.legado.app.ui.widget.components.cover.CoilBookCover
|
||||
import io.legado.app.ui.widget.components.image.cover.CoilBookCover
|
||||
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu
|
||||
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
|
||||
import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet
|
||||
|
||||
@@ -50,7 +50,7 @@ import io.legado.app.model.analyzeRule.AnalyzeUrl
|
||||
import io.legado.app.model.localBook.LocalBook
|
||||
import io.legado.app.model.webBook.WebBook
|
||||
import io.legado.app.ui.config.coverConfig.CoverConfig
|
||||
import io.legado.app.ui.widget.components.cover.buildCoverImageRequest
|
||||
import io.legado.app.ui.widget.components.image.cover.buildCoverImageRequest
|
||||
import io.legado.app.utils.ArchiveUtils
|
||||
import io.legado.app.utils.GSON
|
||||
import io.legado.app.utils.ImageSaveUtils
|
||||
|
||||
@@ -60,7 +60,7 @@ import io.legado.app.ui.widget.components.AppScaffold
|
||||
import io.legado.app.ui.widget.components.AppTextField
|
||||
import io.legado.app.ui.widget.components.alert.AppAlertDialog
|
||||
import io.legado.app.ui.widget.components.button.MediumOutlinedIconButton
|
||||
import io.legado.app.ui.widget.components.cover.CoilBookCover
|
||||
import io.legado.app.ui.widget.components.image.cover.CoilBookCover
|
||||
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu
|
||||
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
|
||||
import io.legado.app.ui.widget.components.settingItem.SwitchSettingItem
|
||||
|
||||
@@ -88,10 +88,10 @@ import io.legado.app.ui.widget.components.card.GlassCard
|
||||
import io.legado.app.ui.widget.components.card.ReorderableSelectionItem
|
||||
import io.legado.app.ui.widget.components.card.SelectionItemCard
|
||||
import io.legado.app.ui.widget.components.card.TextCard
|
||||
import io.legado.app.ui.widget.components.cover.CoilBookCover
|
||||
import io.legado.app.ui.widget.components.divider.PillDivider
|
||||
import io.legado.app.ui.widget.components.filePicker.FilePickerSheet
|
||||
import io.legado.app.ui.widget.components.icon.AppIcons
|
||||
import io.legado.app.ui.widget.components.image.cover.CoilBookCover
|
||||
import io.legado.app.ui.widget.components.list.ListScaffold
|
||||
import io.legado.app.ui.widget.components.list.ListUiState
|
||||
import io.legado.app.ui.widget.components.log.AppLogSheet
|
||||
|
||||
@@ -56,8 +56,8 @@ import io.legado.app.ui.theme.adaptiveHorizontalPadding
|
||||
import io.legado.app.ui.widget.components.AppScaffold
|
||||
import io.legado.app.ui.widget.components.button.MediumIconButton
|
||||
import io.legado.app.ui.widget.components.card.GlassCard
|
||||
import io.legado.app.ui.widget.components.cover.CoilBookCover
|
||||
import io.legado.app.ui.widget.components.heatmap.HeatmapMode
|
||||
import io.legado.app.ui.widget.components.image.cover.CoilBookCover
|
||||
import io.legado.app.ui.widget.components.tabRow.AppTabRow
|
||||
import io.legado.app.ui.widget.components.text.AppText
|
||||
import io.legado.app.ui.widget.components.topbar.GlassMediumFlexibleTopAppBar
|
||||
|
||||
@@ -66,8 +66,8 @@ import io.legado.app.ui.theme.LegadoTheme
|
||||
import io.legado.app.ui.theme.adaptiveContentPaddingOnlyVertical
|
||||
import io.legado.app.ui.theme.adaptiveHorizontalPadding
|
||||
import io.legado.app.ui.theme.fadingEdge
|
||||
import io.legado.app.ui.widget.CollapsibleHeader
|
||||
import io.legado.app.ui.widget.components.AppScaffold
|
||||
import io.legado.app.ui.widget.components.CollapsibleHeader
|
||||
import io.legado.app.ui.widget.components.EmptyMessage
|
||||
import io.legado.app.ui.widget.components.SearchBar
|
||||
import io.legado.app.ui.widget.components.alert.AppAlertDialog
|
||||
@@ -75,7 +75,6 @@ import io.legado.app.ui.widget.components.button.AppIconButton
|
||||
import io.legado.app.ui.widget.components.card.GlassCard
|
||||
import io.legado.app.ui.widget.components.card.TextCard
|
||||
import io.legado.app.ui.widget.components.checkBox.CheckboxItem
|
||||
import io.legado.app.ui.widget.components.cover.CoilBookCover
|
||||
import io.legado.app.ui.widget.components.heatmap.HEATMAP_CALENDAR_TITLE
|
||||
import io.legado.app.ui.widget.components.heatmap.HeatmapCalendarEndAction
|
||||
import io.legado.app.ui.widget.components.heatmap.HeatmapCalendarStartAction
|
||||
@@ -89,6 +88,7 @@ import io.legado.app.ui.widget.components.heatmap.rememberDateRange
|
||||
import io.legado.app.ui.widget.components.heatmap.rememberDaysInRange
|
||||
import io.legado.app.ui.widget.components.heatmap.rememberWeeks
|
||||
import io.legado.app.ui.widget.components.icon.AppIcon
|
||||
import io.legado.app.ui.widget.components.image.cover.CoilBookCover
|
||||
import io.legado.app.ui.widget.components.list.TopFloatingStickyItem
|
||||
import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet
|
||||
import io.legado.app.ui.widget.components.swipe.SwipeAction
|
||||
|
||||
+15
-3
@@ -2,8 +2,20 @@ package io.legado.app.ui.book.readRecord.component
|
||||
|
||||
import androidx.compose.foundation.basicMarquee
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
@@ -16,7 +28,7 @@ import io.legado.app.ui.book.readRecord.ReadRecordFormatter
|
||||
import io.legado.app.ui.book.readRecord.ReadRecordViewModel
|
||||
import io.legado.app.ui.book.readRecord.TimelineItem
|
||||
import io.legado.app.ui.theme.LegadoTheme
|
||||
import io.legado.app.ui.widget.components.cover.CoilBookCover
|
||||
import io.legado.app.ui.widget.components.image.cover.CoilBookCover
|
||||
import io.legado.app.ui.widget.components.text.AppText
|
||||
import io.legado.app.utils.StringUtils.formatFriendlyDate
|
||||
|
||||
|
||||
@@ -1,10 +1,21 @@
|
||||
package io.legado.app.ui.book.readRecord.component
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.legado.app.ui.book.readRecord.ReadRecordFormatter
|
||||
import io.legado.app.ui.book.readRecord.ReadRecordUiState
|
||||
@@ -12,7 +23,7 @@ import io.legado.app.ui.book.readRecord.ReadRecordViewModel
|
||||
import io.legado.app.ui.theme.LegadoTheme
|
||||
import io.legado.app.ui.theme.adaptiveHorizontalPadding
|
||||
import io.legado.app.ui.widget.components.card.GlassCard
|
||||
import io.legado.app.ui.widget.components.cover.CoilBookCover
|
||||
import io.legado.app.ui.widget.components.image.cover.CoilBookCover
|
||||
import io.legado.app.ui.widget.components.text.AppText
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
@@ -23,17 +22,12 @@ import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Book
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.material.icons.filled.History
|
||||
import androidx.compose.material.icons.filled.Layers
|
||||
import androidx.compose.material.icons.filled.PlayArrow
|
||||
import androidx.compose.material.icons.filled.Stop
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import io.legado.app.ui.widget.components.progressIndicator.AppCircularProgressIndicator
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import io.legado.app.ui.widget.components.topbar.GlassMediumFlexibleTopAppBar
|
||||
import io.legado.app.ui.widget.components.topbar.M3GlassScrollBehavior
|
||||
import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
@@ -42,9 +36,9 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.snapshotFlow
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
@@ -58,6 +52,7 @@ import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import io.legado.app.R
|
||||
import io.legado.app.data.entities.SearchKeyword
|
||||
import io.legado.app.ui.main.bookCoverSharedElementKey
|
||||
import io.legado.app.ui.main.bookshelf.BookShelfItem
|
||||
import io.legado.app.ui.theme.LegadoTheme
|
||||
import io.legado.app.ui.theme.ThemeResolver
|
||||
@@ -68,22 +63,23 @@ import io.legado.app.ui.widget.components.AppFloatingActionButton
|
||||
import io.legado.app.ui.widget.components.AppScaffold
|
||||
import io.legado.app.ui.widget.components.SearchBar
|
||||
import io.legado.app.ui.widget.components.alert.AppAlertDialog
|
||||
import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet
|
||||
import io.legado.app.ui.widget.components.book.SearchBookListItem
|
||||
import io.legado.app.ui.widget.components.button.SmallIconButton
|
||||
import io.legado.app.ui.widget.components.button.SmallTextButton
|
||||
import io.legado.app.ui.widget.components.card.NormalCard
|
||||
import io.legado.app.ui.widget.components.card.SelectionItemCard
|
||||
import io.legado.app.ui.widget.components.icon.AppIcon
|
||||
import io.legado.app.ui.widget.components.icon.AppIcons
|
||||
import io.legado.app.ui.widget.components.list.TopFloatingStickyItem
|
||||
import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet
|
||||
import io.legado.app.ui.widget.components.progressIndicator.AppCircularProgressIndicator
|
||||
import io.legado.app.ui.widget.components.text.AppText
|
||||
import io.legado.app.ui.widget.components.topbar.GlassMediumFlexibleTopAppBar
|
||||
import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults
|
||||
import io.legado.app.ui.widget.components.topbar.M3GlassScrollBehavior
|
||||
import io.legado.app.ui.widget.components.topbar.TopBarActionButton
|
||||
import io.legado.app.ui.widget.components.topbar.TopBarAnimatedActionButton
|
||||
import io.legado.app.ui.widget.components.topbar.TopBarNavigationButton
|
||||
import io.legado.app.ui.widget.components.icon.AppIcon
|
||||
import io.legado.app.ui.widget.components.icon.AppIcons
|
||||
import io.legado.app.ui.book.search.ScopeSelectSheet
|
||||
import io.legado.app.ui.widget.components.list.TopFloatingStickyItem
|
||||
import io.legado.app.ui.widget.components.tabRow.AppTabRow
|
||||
import io.legado.app.ui.widget.components.text.AppText
|
||||
import io.legado.app.ui.main.bookCoverSharedElementKey
|
||||
import io.legado.app.utils.toastOnUi
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.flow.debounce
|
||||
@@ -480,19 +476,17 @@ fun SearchScreen(
|
||||
viewModel.onIntent(SearchIntent.DismissEmptyScopeAction)
|
||||
},
|
||||
title = stringResource(R.string.draw),
|
||||
textProvider = {
|
||||
if (wasPrecisionSearch) {
|
||||
stringResource(R.string.search_empty_scope_disable_precision, scopeDisplay)
|
||||
} else {
|
||||
stringResource(R.string.search_empty_scope_switch_all, scopeDisplay)
|
||||
}
|
||||
},
|
||||
confirmText = stringResource(R.string.ok),
|
||||
onConfirm = { viewModel.onIntent(SearchIntent.ConfirmEmptyScopeAction) },
|
||||
dismissText = stringResource(R.string.cancel),
|
||||
onDismiss = { viewModel.onIntent(SearchIntent.DismissEmptyScopeAction) },
|
||||
content = {
|
||||
Text(
|
||||
text = if (it.wasPrecisionSearch) {
|
||||
stringResource(R.string.search_empty_scope_disable_precision, it.scopeDisplay)
|
||||
} else {
|
||||
stringResource(R.string.search_empty_scope_switch_all, it.scopeDisplay)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
ScopeSelectSheet(
|
||||
@@ -681,12 +675,8 @@ private fun SearchResultFooter(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier.size(18.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
AppCircularProgressIndicator()
|
||||
}
|
||||
AppCircularProgressIndicator()
|
||||
Spacer(modifier = Modifier.padding(horizontal = 8.dp))
|
||||
AppText(text = stringResource(R.string.is_loading))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,10 +84,10 @@ import io.legado.app.ui.replace.ReplaceEditRoute
|
||||
import io.legado.app.ui.theme.LegadoTheme
|
||||
import io.legado.app.ui.theme.adaptiveContentPaddingOnlyVertical
|
||||
import io.legado.app.ui.theme.adaptiveHorizontalPadding
|
||||
import io.legado.app.ui.widget.CollapsibleHeader
|
||||
import io.legado.app.ui.widget.components.ActionItem
|
||||
import io.legado.app.ui.widget.components.AppFloatingActionButtonMenu
|
||||
import io.legado.app.ui.widget.components.AppScaffold
|
||||
import io.legado.app.ui.widget.components.CollapsibleHeader
|
||||
import io.legado.app.ui.widget.components.EmptyMessage
|
||||
import io.legado.app.ui.widget.components.FabMenuItem
|
||||
import io.legado.app.ui.widget.components.SelectionBottomBar
|
||||
|
||||
@@ -1,328 +0,0 @@
|
||||
package io.legado.app.ui.book.toc.rule
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import io.legado.app.R
|
||||
import io.legado.app.base.BaseDialogFragment
|
||||
import io.legado.app.base.adapter.ItemViewHolder
|
||||
import io.legado.app.base.adapter.RecyclerAdapter
|
||||
import io.legado.app.constant.AppLog
|
||||
import io.legado.app.data.appDb
|
||||
import io.legado.app.data.entities.TxtTocRule
|
||||
import io.legado.app.databinding.DialogEditTextBinding
|
||||
import io.legado.app.databinding.DialogTocRegexBinding
|
||||
import io.legado.app.databinding.ItemTocRegexBinding
|
||||
import io.legado.app.lib.dialogs.alert
|
||||
//import io.legado.app.lib.theme.backgroundColor
|
||||
//import io.legado.app.lib.theme.primaryColor
|
||||
import io.legado.app.ui.association.ImportTxtTocRuleDialog
|
||||
import io.legado.app.ui.file.HandleFileContract
|
||||
import io.legado.app.ui.qrcode.QrCodeResult
|
||||
import io.legado.app.ui.widget.recycler.ItemTouchCallback
|
||||
import io.legado.app.ui.widget.recycler.VerticalDivider
|
||||
import io.legado.app.utils.ACache
|
||||
import io.legado.app.utils.isAbsUrl
|
||||
import io.legado.app.utils.launch
|
||||
import io.legado.app.utils.readText
|
||||
import io.legado.app.utils.showDialogFragment
|
||||
import io.legado.app.utils.showHelp
|
||||
import io.legado.app.utils.splitNotBlank
|
||||
import io.legado.app.utils.toastOnUi
|
||||
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.conflate
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* txt目录规则
|
||||
*/
|
||||
class TxtTocRuleDialog() : BaseDialogFragment(R.layout.dialog_toc_regex),
|
||||
Toolbar.OnMenuItemClickListener,
|
||||
TxtTocRuleEditDialog.Callback {
|
||||
|
||||
constructor(tocRegex: String?) : this() {
|
||||
arguments = Bundle().apply {
|
||||
putString("tocRegex", tocRegex)
|
||||
}
|
||||
}
|
||||
|
||||
private val importTocRuleKey = "tocRuleUrl"
|
||||
private val viewModel: TxtTocRuleViewModel by viewModels()
|
||||
private val binding by viewBinding(DialogTocRegexBinding::bind)
|
||||
private val adapter by lazy { TocRegexAdapter(requireContext()) }
|
||||
var selectedName: String? = null
|
||||
private var durRegex: String? = null
|
||||
private val qrCodeResult = registerForActivityResult(QrCodeResult()) {
|
||||
it ?: return@registerForActivityResult
|
||||
showDialogFragment(ImportTxtTocRuleDialog(it))
|
||||
}
|
||||
private val importDoc = registerForActivityResult(HandleFileContract()) {
|
||||
kotlin.runCatching {
|
||||
it.uri?.readText(requireContext())?.let {
|
||||
showDialogFragment(ImportTxtTocRuleDialog(it))
|
||||
}
|
||||
}.onFailure {
|
||||
toastOnUi("readTextError:${it.localizedMessage}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
}
|
||||
|
||||
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
|
||||
//binding.toolBar.setBackgroundColor(primaryColor)
|
||||
durRegex = arguments?.getString("tocRegex")
|
||||
binding.toolBar.setTitle(R.string.txt_toc_rule)
|
||||
binding.toolBar.inflateMenu(R.menu.txt_toc_rule)
|
||||
//binding.toolBar.menu.applyTint(requireContext())
|
||||
binding.toolBar.setOnMenuItemClickListener(this)
|
||||
initView()
|
||||
initData()
|
||||
}
|
||||
|
||||
private fun initView() = binding.run {
|
||||
recyclerView.addItemDecoration(VerticalDivider(requireContext()))
|
||||
recyclerView.adapter = adapter
|
||||
val itemTouchCallback = ItemTouchCallback(adapter)
|
||||
itemTouchCallback.isCanDrag = true
|
||||
ItemTouchHelper(itemTouchCallback).attachToRecyclerView(recyclerView)
|
||||
tvCancel.setOnClickListener {
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
tvOk.setOnClickListener {
|
||||
adapter.getItems().forEach { tocRule ->
|
||||
if (selectedName == tocRule.name) {
|
||||
val callBack = activity as? CallBack
|
||||
callBack?.onTocRegexDialogResult(tocRule.rule)
|
||||
dismissAllowingStateLoss()
|
||||
return@setOnClickListener
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun initData() {
|
||||
lifecycleScope.launch {
|
||||
appDb.txtTocRuleDao.observeAll().catch {
|
||||
AppLog.put("TXT目录规则对话框获取数据失败\n${it.localizedMessage}", it)
|
||||
}.flowOn(IO).conflate().collect { tocRules ->
|
||||
initSelectedName(tocRules)
|
||||
adapter.setItems(tocRules, adapter.diffItemCallBack)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun initSelectedName(tocRules: List<TxtTocRule>) {
|
||||
if (selectedName == null && durRegex != null) {
|
||||
tocRules.forEach {
|
||||
if (durRegex == it.rule) {
|
||||
selectedName = it.name
|
||||
return@forEach
|
||||
}
|
||||
}
|
||||
if (selectedName == null) {
|
||||
selectedName = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onMenuItemClick(item: MenuItem?): Boolean {
|
||||
when (item?.itemId) {
|
||||
R.id.menu_add -> showDialogFragment(TxtTocRuleEditDialog())
|
||||
R.id.menu_import_local -> importDoc.launch {
|
||||
mode = HandleFileContract.FILE
|
||||
allowExtensions = arrayOf("txt", "json")
|
||||
}
|
||||
R.id.menu_import_onLine -> showImportDialog()
|
||||
R.id.menu_import_qr -> qrCodeResult.launch()
|
||||
R.id.menu_help -> showHelp("txtTocRuleHelp")
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun saveTxtTocRule(txtTocRule: TxtTocRule) {
|
||||
//viewModel.update(txtTocRule)
|
||||
}
|
||||
|
||||
@SuppressLint("InflateParams")
|
||||
private fun showImportDialog() {
|
||||
val aCache = ACache.get(cacheDir = false)
|
||||
val defaultUrl = "https://gitee.com/fisher52/YueDuJson/raw/master/myTxtChapterRule.json"
|
||||
val cacheUrls: MutableList<String> = aCache
|
||||
.getAsString(importTocRuleKey)
|
||||
?.splitNotBlank(",")
|
||||
?.toMutableList()
|
||||
?: mutableListOf()
|
||||
if (!cacheUrls.contains(defaultUrl)) {
|
||||
cacheUrls.add(0, defaultUrl)
|
||||
}
|
||||
requireContext().alert(titleResource = R.string.import_on_line) {
|
||||
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
|
||||
editView.hint = "url"
|
||||
editView.setFilterValues(cacheUrls)
|
||||
editView.delCallBack = {
|
||||
cacheUrls.remove(it)
|
||||
aCache.put(importTocRuleKey, cacheUrls.joinToString(","))
|
||||
}
|
||||
}
|
||||
customView { alertBinding.root }
|
||||
okButton {
|
||||
val text = alertBinding.editView.text?.toString()
|
||||
text?.let {
|
||||
if (it.isAbsUrl() && !cacheUrls.contains(it)) {
|
||||
cacheUrls.add(0, it)
|
||||
aCache.put(importTocRuleKey, cacheUrls.joinToString(","))
|
||||
}
|
||||
showDialogFragment(ImportTxtTocRuleDialog(it))
|
||||
}
|
||||
}
|
||||
cancelButton()
|
||||
}
|
||||
}
|
||||
|
||||
inner class TocRegexAdapter(context: Context) :
|
||||
RecyclerAdapter<TxtTocRule, ItemTocRegexBinding>(context),
|
||||
ItemTouchCallback.Callback {
|
||||
|
||||
val diffItemCallBack = object : DiffUtil.ItemCallback<TxtTocRule>() {
|
||||
|
||||
override fun areItemsTheSame(oldItem: TxtTocRule, newItem: TxtTocRule): Boolean {
|
||||
return oldItem.id == newItem.id
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: TxtTocRule, newItem: TxtTocRule): Boolean {
|
||||
if (oldItem.name != newItem.name) {
|
||||
return false
|
||||
}
|
||||
if (oldItem.enable != newItem.enable) {
|
||||
return false
|
||||
}
|
||||
if (oldItem.example != newItem.example) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getChangePayload(oldItem: TxtTocRule, newItem: TxtTocRule): Any? {
|
||||
val payload = Bundle()
|
||||
if (oldItem.name != newItem.name) {
|
||||
payload.putBoolean("upName", true)
|
||||
}
|
||||
if (oldItem.enable != newItem.enable) {
|
||||
payload.putBoolean("enabled", newItem.enable)
|
||||
}
|
||||
if (oldItem.example != newItem.example) {
|
||||
payload.putBoolean("upExample", true)
|
||||
}
|
||||
if (payload.isEmpty) {
|
||||
return null
|
||||
}
|
||||
return payload
|
||||
}
|
||||
}
|
||||
|
||||
override fun getViewBinding(parent: ViewGroup): ItemTocRegexBinding {
|
||||
return ItemTocRegexBinding.inflate(inflater, parent, false)
|
||||
}
|
||||
|
||||
override fun convert(
|
||||
holder: ItemViewHolder,
|
||||
binding: ItemTocRegexBinding,
|
||||
item: TxtTocRule,
|
||||
payloads: MutableList<Any>
|
||||
) {
|
||||
binding.apply {
|
||||
if (payloads.isEmpty()) {
|
||||
//root.setBackgroundColor(context.backgroundColor)
|
||||
rbRegexName.text = item.name
|
||||
titleExample.text = item.example
|
||||
rbRegexName.isChecked = item.name == selectedName
|
||||
swtEnabled.isChecked = item.enable
|
||||
} else {
|
||||
for (i in payloads.indices) {
|
||||
val bundle = payloads[i] as Bundle
|
||||
bundle.keySet().forEach {
|
||||
when (it) {
|
||||
"upName" -> rbRegexName.text = item.name
|
||||
"upExample" -> titleExample.text = item.example
|
||||
"enabled" -> swtEnabled.isChecked = item.enable
|
||||
"upSelect" -> rbRegexName.isChecked = item.name == selectedName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun registerListener(holder: ItemViewHolder, binding: ItemTocRegexBinding) {
|
||||
binding.apply {
|
||||
rbRegexName.setOnCheckedChangeListener { buttonView, isChecked ->
|
||||
if (buttonView.isPressed && isChecked) {
|
||||
selectedName = getItem(holder.layoutPosition)?.name
|
||||
updateItems(0, itemCount - 1, bundleOf("upSelect" to null))
|
||||
}
|
||||
}
|
||||
swtEnabled.setOnCheckedChangeListener { buttonView, isChecked ->
|
||||
if (buttonView.isPressed) {
|
||||
getItem(holder.layoutPosition)?.let {
|
||||
it.enable = isChecked
|
||||
//viewModel.update(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
ivEdit.setOnClickListener {
|
||||
showDialogFragment(TxtTocRuleEditDialog(getItem(holder.layoutPosition)?.id))
|
||||
}
|
||||
ivDelete.setOnClickListener {
|
||||
getItem(holder.layoutPosition)?.let { item ->
|
||||
alert(R.string.draw) {
|
||||
setMessage(getString(R.string.sure_del) + "\n" + item.name)
|
||||
noButton()
|
||||
yesButton {
|
||||
//viewModel.delete(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var isMoved = false
|
||||
|
||||
override fun swap(srcPosition: Int, targetPosition: Int): Boolean {
|
||||
swapItem(srcPosition, targetPosition)
|
||||
isMoved = true
|
||||
return super.swap(srcPosition, targetPosition)
|
||||
}
|
||||
|
||||
override fun onClearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
|
||||
super.onClearView(recyclerView, viewHolder)
|
||||
if (isMoved) {
|
||||
for ((index, item) in getItems().withIndex()) {
|
||||
item.serialNumber = index + 1
|
||||
}
|
||||
//viewModel.update(*getItems().toTypedArray())
|
||||
}
|
||||
isMoved = false
|
||||
}
|
||||
}
|
||||
|
||||
interface CallBack {
|
||||
fun onTocRegexDialogResult(tocRegex: String) {}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
package io.legado.app.ui.book.toc.rule
|
||||
|
||||
import android.app.Application
|
||||
import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.fragment.app.viewModels
|
||||
import io.legado.app.R
|
||||
import io.legado.app.base.BaseBottomSheetDialogFragment
|
||||
import io.legado.app.base.BaseViewModel
|
||||
import io.legado.app.constant.AppLog
|
||||
import io.legado.app.data.appDb
|
||||
import io.legado.app.data.entities.TxtTocRule
|
||||
import io.legado.app.databinding.DialogTocRegexEditBinding
|
||||
import io.legado.app.exception.NoStackTraceException
|
||||
//import io.legado.app.lib.theme.primaryColor
|
||||
import io.legado.app.utils.*
|
||||
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import java.util.regex.Pattern
|
||||
import java.util.regex.PatternSyntaxException
|
||||
|
||||
class TxtTocRuleEditDialog() : BaseBottomSheetDialogFragment(R.layout.dialog_toc_regex_edit),
|
||||
Toolbar.OnMenuItemClickListener {
|
||||
|
||||
constructor(id: Long?) : this() {
|
||||
id ?: return
|
||||
arguments = Bundle().apply {
|
||||
putLong("id", id)
|
||||
}
|
||||
}
|
||||
|
||||
private val binding by viewBinding(DialogTocRegexEditBinding::bind)
|
||||
private val viewModel by viewModels<ViewModel>()
|
||||
private val callback get() = (parentFragment as? Callback) ?: activity as? Callback
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
|
||||
}
|
||||
|
||||
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
|
||||
//binding.toolBar.setBackgroundColor(primaryColor)
|
||||
initMenu()
|
||||
viewModel.initData(arguments?.getLong("id")) {
|
||||
upRuleView(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun initMenu() {
|
||||
binding.toolBar.inflateMenu(R.menu.txt_toc_rule_edit)
|
||||
//binding.toolBar.menu.applyTint(requireContext())
|
||||
binding.toolBar.setOnMenuItemClickListener(this)
|
||||
}
|
||||
|
||||
override fun onMenuItemClick(item: MenuItem?): Boolean {
|
||||
when (item?.itemId) {
|
||||
R.id.menu_save -> {
|
||||
val tocRule = getRuleFromView()
|
||||
if (checkValid(tocRule)) {
|
||||
callback?.saveTxtTocRule(getRuleFromView())
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
R.id.menu_copy_rule -> context?.sendToClip(GSON.toJson(getRuleFromView()))
|
||||
R.id.menu_paste_rule -> viewModel.pasteRule {
|
||||
upRuleView(it)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun checkValid(tocRule: TxtTocRule): Boolean {
|
||||
if (tocRule.name.isEmpty()) {
|
||||
toastOnUi("名称不能为空")
|
||||
return false
|
||||
}
|
||||
|
||||
try {
|
||||
Pattern.compile(tocRule.rule, Pattern.MULTILINE)
|
||||
} catch (ex: PatternSyntaxException) {
|
||||
AppLog.put("正则语法错误或不支持(txt):${ex.localizedMessage}", ex, true)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun upRuleView(tocRule: TxtTocRule?) {
|
||||
binding.tvRuleName.setText(tocRule?.name)
|
||||
binding.tvRuleRegex.setText(tocRule?.rule)
|
||||
binding.tvRuleExample.setText(tocRule?.example)
|
||||
}
|
||||
|
||||
private fun getRuleFromView(): TxtTocRule {
|
||||
val tocRule = viewModel.tocRule ?: TxtTocRule().apply {
|
||||
viewModel.tocRule = this
|
||||
}
|
||||
binding.run {
|
||||
tocRule.name = tvRuleName.text.toString()
|
||||
tocRule.rule = tvRuleRegex.text.toString()
|
||||
tocRule.example = tvRuleExample.text.toString()
|
||||
}
|
||||
return tocRule
|
||||
}
|
||||
|
||||
class ViewModel(application: Application) : BaseViewModel(application) {
|
||||
|
||||
var tocRule: TxtTocRule? = null
|
||||
|
||||
fun initData(id: Long?, finally: (tocRule: TxtTocRule?) -> Unit) {
|
||||
if (tocRule != null) return
|
||||
execute {
|
||||
if (id == null) return@execute
|
||||
tocRule = appDb.txtTocRuleDao.get(id)
|
||||
}.onFinally {
|
||||
finally.invoke(tocRule)
|
||||
}
|
||||
}
|
||||
|
||||
fun pasteRule(success: (TxtTocRule) -> Unit) {
|
||||
execute(context = Dispatchers.Main) {
|
||||
val text = context.getClipText()
|
||||
if (text.isNullOrBlank()) {
|
||||
throw NoStackTraceException("剪贴板为空")
|
||||
}
|
||||
GSON.fromJsonObject<TxtTocRule>(text).getOrNull()
|
||||
?: throw NoStackTraceException("格式不对")
|
||||
}.onSuccess {
|
||||
success.invoke(it)
|
||||
}.onError {
|
||||
context.toastOnUi(it.localizedMessage ?: "Error")
|
||||
it.printOnDebug()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface Callback {
|
||||
|
||||
fun saveTxtTocRule(txtTocRule: TxtTocRule)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
package io.legado.app.ui.config
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import io.legado.app.R
|
||||
import io.legado.app.base.BaseBottomSheetDialogFragment
|
||||
import io.legado.app.databinding.DialogCoverRuleConfigBinding
|
||||
//import io.legado.app.lib.theme.primaryColor
|
||||
import io.legado.app.model.BookCover
|
||||
import io.legado.app.utils.GSON
|
||||
import io.legado.app.utils.toastOnUi
|
||||
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import splitties.views.onClick
|
||||
|
||||
class CoverRuleConfigDialog : BaseBottomSheetDialogFragment(R.layout.dialog_cover_rule_config) {
|
||||
|
||||
val binding by viewBinding(DialogCoverRuleConfigBinding::bind)
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
|
||||
}
|
||||
|
||||
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
|
||||
//binding.toolBar.setBackgroundColor(primaryColor)
|
||||
initData()
|
||||
binding.tvCancel.onClick {
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
binding.tvOk.onClick {
|
||||
val enable = binding.cbEnable.isChecked
|
||||
val searchUrl = binding.editSearchUrl.text?.toString()
|
||||
val coverRule = binding.editCoverUrlRule.text?.toString()
|
||||
if (searchUrl.isNullOrBlank() || coverRule.isNullOrBlank()) {
|
||||
toastOnUi("搜索url和cover规则不能为空")
|
||||
} else {
|
||||
BookCover.CoverRule(enable, searchUrl, coverRule).let { config ->
|
||||
BookCover.saveCoverRule(config)
|
||||
}
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
binding.tvFooterLeft.onClick {
|
||||
BookCover.delCoverRule()
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
|
||||
private fun initData() {
|
||||
lifecycleScope.launch {
|
||||
val rule = withContext(IO) {
|
||||
BookCover.getCoverRule()
|
||||
}
|
||||
Log.e("coverRule", GSON.toJson(rule))
|
||||
binding.cbEnable.isChecked = rule.enable
|
||||
binding.editSearchUrl.setText(rule.searchUrl)
|
||||
binding.editCoverUrlRule.setText(rule.coverRule)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
package io.legado.app.ui.config
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import io.legado.app.R
|
||||
import io.legado.app.base.BaseBottomSheetDialogFragment
|
||||
import io.legado.app.databinding.DialogDirectLinkUploadConfigBinding
|
||||
import io.legado.app.help.DirectLinkUpload
|
||||
import io.legado.app.lib.dialogs.alert
|
||||
import io.legado.app.lib.dialogs.selector
|
||||
//import io.legado.app.lib.theme.primaryColor
|
||||
import io.legado.app.utils.GSON
|
||||
import io.legado.app.utils.applyTint
|
||||
import io.legado.app.utils.fromJsonObject
|
||||
import io.legado.app.utils.getClipText
|
||||
import io.legado.app.utils.sendToClip
|
||||
import io.legado.app.utils.toastOnUi
|
||||
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
||||
import splitties.init.appCtx
|
||||
import splitties.views.onClick
|
||||
|
||||
class DirectLinkUploadConfig : BaseBottomSheetDialogFragment(R.layout.dialog_direct_link_upload_config),
|
||||
Toolbar.OnMenuItemClickListener {
|
||||
|
||||
private val binding by viewBinding(DialogDirectLinkUploadConfigBinding::bind)
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
//setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
}
|
||||
|
||||
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
|
||||
//binding.toolBar.setBackgroundColor(primaryColor)
|
||||
binding.toolBar.inflateMenu(R.menu.direct_link_upload_config)
|
||||
binding.toolBar.menu.applyTint(requireContext())
|
||||
binding.toolBar.setOnMenuItemClickListener(this)
|
||||
upView(DirectLinkUpload.getRule())
|
||||
binding.tvCancel.onClick {
|
||||
dismiss()
|
||||
}
|
||||
binding.tvFooterLeft.onClick {
|
||||
test()
|
||||
}
|
||||
binding.tvOk.onClick {
|
||||
getRule()?.let { rule ->
|
||||
DirectLinkUpload.putConfig(rule)
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onMenuItemClick(item: MenuItem?): Boolean {
|
||||
when (item?.itemId) {
|
||||
R.id.menu_import_default -> importDefault()
|
||||
R.id.menu_copy_rule -> getRule()?.let { rule ->
|
||||
requireContext().sendToClip(GSON.toJson(rule))
|
||||
}
|
||||
|
||||
R.id.menu_paste_rule -> runCatching {
|
||||
requireContext().getClipText()!!.let {
|
||||
val rule = GSON.fromJsonObject<DirectLinkUpload.Rule>(it).getOrThrow()
|
||||
upView(rule)
|
||||
}
|
||||
}.onFailure {
|
||||
toastOnUi("剪贴板为空或格式不对")
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun upView(rule: DirectLinkUpload.Rule) {
|
||||
binding.editUploadUrl.setText(rule.uploadUrl)
|
||||
binding.editDownloadUrlRule.setText(rule.downloadUrlRule)
|
||||
binding.editSummary.setText(rule.summary)
|
||||
binding.cbCompress.isChecked = rule.compress
|
||||
}
|
||||
|
||||
private fun getRule(): DirectLinkUpload.Rule? {
|
||||
val uploadUrl = binding.editUploadUrl.text?.toString()
|
||||
val downloadUrlRule = binding.editDownloadUrlRule.text?.toString()
|
||||
val summary = binding.editSummary.text?.toString()
|
||||
val compress = binding.cbCompress.isChecked
|
||||
if (uploadUrl.isNullOrBlank()) {
|
||||
toastOnUi("上传Url不能为空")
|
||||
return null
|
||||
}
|
||||
if (downloadUrlRule.isNullOrBlank()) {
|
||||
toastOnUi("下载Url规则不能为空")
|
||||
return null
|
||||
}
|
||||
if (summary.isNullOrBlank()) {
|
||||
toastOnUi("注释不能为空")
|
||||
return null
|
||||
}
|
||||
return DirectLinkUpload.Rule(uploadUrl, downloadUrlRule, summary, compress)
|
||||
}
|
||||
|
||||
private fun importDefault() {
|
||||
requireContext().selector(DirectLinkUpload.defaultRules) { _, rule, _ ->
|
||||
upView(rule)
|
||||
}
|
||||
}
|
||||
|
||||
private fun test() {
|
||||
val rule = getRule() ?: return
|
||||
execute {
|
||||
DirectLinkUpload.upLoad("test.json", "{}", "application/json", rule)
|
||||
}.onError {
|
||||
alertTestResult(it.localizedMessage ?: "ERROR")
|
||||
}.onSuccess { result ->
|
||||
alertTestResult(result)
|
||||
}
|
||||
}
|
||||
|
||||
private fun alertTestResult(result: String) {
|
||||
alert {
|
||||
setTitle("result")
|
||||
setMessage(result)
|
||||
okButton()
|
||||
negativeButton(R.string.copy_text) {
|
||||
appCtx.sendToClip(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,105 +2,56 @@ package io.legado.app.ui.config.coverConfig
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Save
|
||||
import androidx.compose.material.icons.filled.SettingsBackupRestore
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.legado.app.R
|
||||
import io.legado.app.help.DefaultData
|
||||
import io.legado.app.model.BookCover
|
||||
import io.legado.app.ui.theme.LegadoTheme
|
||||
import io.legado.app.ui.widget.components.AppTextField
|
||||
import io.legado.app.ui.widget.components.button.MediumIconButton
|
||||
import io.legado.app.ui.widget.components.card.GlassCard
|
||||
import io.legado.app.ui.widget.components.checkBox.CheckboxItem
|
||||
import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet
|
||||
import io.legado.app.ui.widget.components.text.AppText
|
||||
import io.legado.app.utils.toastOnUi
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import splitties.init.appCtx
|
||||
|
||||
private const val DEFAULT_SEARCH_URL = "data:;base64,{{java.base64Encode(key)}},{\"type\":\"lyc\"}"
|
||||
private val DEFAULT_COVER_RULE = """
|
||||
@js:
|
||||
var key = java.hexDecodeToString(result);
|
||||
var url1 = `https://pre-api.tuishujun.com/api/searchBook?search_value=${'$'}{key}&page=1&pageSize=20`;
|
||||
var url2 = `http://m.ypshuo.com/api/novel/search?keyword=${'$'}{key}&searchType=1&page=1`;
|
||||
var [rr1, rr2] = java.ajaxAll([url1, url2]).map(r => r.body());
|
||||
function jjson(str, rule) {
|
||||
try {
|
||||
return com.jayway.jsonpath.JsonPath.read(str, rule);
|
||||
} catch (e) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
rr1 = jjson(rr1, '$.data.data[*]');
|
||||
rr2 = jjson(rr2, '$.data.data[*]');
|
||||
var na = String(book.name),
|
||||
au = String(book.author);
|
||||
function search() {
|
||||
for (let char of rr1) {
|
||||
//本地书名包含搜索结果书名
|
||||
if (na.includes(char.title + '')) {
|
||||
let au2 = char.author_nickname + '';
|
||||
//作者匹配
|
||||
if (au.includes(au2) || au2.includes(au)) {
|
||||
return char.cover;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let char of rr2) {
|
||||
if (na.includes(char.novel_name + '')) {
|
||||
let au2 = char.author_name + '';
|
||||
if (au.includes(au2) || au2.includes(au)) {
|
||||
return char.novel_img;
|
||||
}
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
search()
|
||||
""".trimIndent()
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun CoverRuleConfigSheet(
|
||||
show: Boolean,
|
||||
onDismissRequest: () -> Unit
|
||||
) {
|
||||
var ruleState by remember { mutableStateOf<BookCover.CoverRule?>(null) }
|
||||
var enable by remember { mutableStateOf(false) }
|
||||
var searchUrl by remember { mutableStateOf("") }
|
||||
var coverRule by remember { mutableStateOf("") }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
val rule = withContext(Dispatchers.IO) {
|
||||
BookCover.getCoverRule()
|
||||
LaunchedEffect(show) {
|
||||
if (show) {
|
||||
val rule = withContext(Dispatchers.IO) {
|
||||
BookCover.getCoverRule()
|
||||
}
|
||||
ruleState = rule
|
||||
enable = rule.enable
|
||||
searchUrl = rule.searchUrl
|
||||
coverRule = rule.coverRule
|
||||
}
|
||||
enable = rule.enable
|
||||
searchUrl = rule.searchUrl
|
||||
coverRule = rule.coverRule
|
||||
}
|
||||
|
||||
AppModalBottomSheet(
|
||||
@@ -111,8 +62,11 @@ fun CoverRuleConfigSheet(
|
||||
MediumIconButton(
|
||||
imageVector = Icons.Default.SettingsBackupRestore,
|
||||
onClick = {
|
||||
searchUrl = DEFAULT_SEARCH_URL
|
||||
coverRule = DEFAULT_COVER_RULE
|
||||
DefaultData.coverRule.let {
|
||||
enable = it.enable
|
||||
searchUrl = it.searchUrl
|
||||
coverRule = it.coverRule
|
||||
}
|
||||
appCtx.toastOnUi(R.string.restore_default)
|
||||
}
|
||||
)
|
||||
@@ -124,8 +78,16 @@ fun CoverRuleConfigSheet(
|
||||
if (searchUrl.isBlank() || coverRule.isBlank()) {
|
||||
appCtx.toastOnUi("搜索url和cover规则不能为空")
|
||||
} else {
|
||||
BookCover.CoverRule(enable, searchUrl, coverRule).let { config ->
|
||||
BookCover.saveCoverRule(config)
|
||||
val newConfig = ruleState?.copy(
|
||||
enable = enable,
|
||||
searchUrl = searchUrl,
|
||||
coverRule = coverRule
|
||||
) ?: BookCover.CoverRule(enable, searchUrl, coverRule)
|
||||
|
||||
if (newConfig == DefaultData.coverRule) {
|
||||
BookCover.delCoverRule()
|
||||
} else {
|
||||
BookCover.saveCoverRule(newConfig)
|
||||
}
|
||||
onDismissRequest()
|
||||
}
|
||||
@@ -136,6 +98,7 @@ fun CoverRuleConfigSheet(
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(bottom = 24.dp)
|
||||
.verticalScroll(rememberScrollState()),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
|
||||
@@ -50,9 +50,9 @@ import io.legado.app.ui.config.themeConfig.ThemeConfig
|
||||
import io.legado.app.ui.theme.LegadoTheme
|
||||
import io.legado.app.ui.widget.components.card.NormalCard
|
||||
import io.legado.app.ui.widget.components.card.TextCard
|
||||
import io.legado.app.ui.widget.components.cover.BookshelfCover
|
||||
import io.legado.app.ui.widget.components.cover.CoilBookCover
|
||||
import io.legado.app.ui.widget.components.icon.AppIcon
|
||||
import io.legado.app.ui.widget.components.image.cover.BookshelfCover
|
||||
import io.legado.app.ui.widget.components.image.cover.CoilBookCover
|
||||
import io.legado.app.ui.widget.components.text.AppText
|
||||
import io.legado.app.utils.toTimeAgo
|
||||
|
||||
@@ -214,7 +214,7 @@ fun BookshelfItem(
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(top = 4.dp, bottom = 4.dp, end = 4.dp),
|
||||
.padding(top = 4.dp, bottom = 4.dp, end = 8.dp, start = 4.dp),
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Row(
|
||||
@@ -232,7 +232,7 @@ fun BookshelfItem(
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
titleEnd?.let {
|
||||
Box(modifier = Modifier.padding(top = 4.dp)) {
|
||||
Box(modifier = Modifier.padding(top = 4.dp, start = 4.dp)) {
|
||||
it.invoke()
|
||||
}
|
||||
}
|
||||
@@ -523,7 +523,7 @@ fun BookGroupItemHorizontalCovers(
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(vertical = 4.dp),
|
||||
.padding(vertical = 8.dp, horizontal = 4.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
Row(
|
||||
|
||||
@@ -29,7 +29,6 @@ import androidx.compose.material.icons.filled.Refresh
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material.icons.filled.VerticalAlignTop
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import io.legado.app.ui.widget.components.progressIndicator.AppCircularProgressIndicator
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.ListItem
|
||||
import androidx.compose.material3.ListItemDefaults
|
||||
@@ -41,8 +40,8 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.rotate
|
||||
@@ -53,23 +52,22 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import io.legado.app.R
|
||||
import io.legado.app.data.entities.BookSourcePart
|
||||
import io.legado.app.domain.usecase.ExploreKindUiUseCase
|
||||
import io.legado.app.help.source.getExploreInfoMap
|
||||
import io.legado.app.ui.widget.components.explore.ExploreKindUiUseCase
|
||||
import io.legado.app.ui.book.search.SearchActivity
|
||||
import io.legado.app.ui.book.search.SearchScope
|
||||
import io.legado.app.ui.book.source.edit.BookSourceEditActivity
|
||||
import io.legado.app.ui.login.SourceLoginActivity
|
||||
import io.legado.app.ui.config.themeConfig.ThemeConfig
|
||||
import io.legado.app.ui.theme.LegadoTheme
|
||||
import io.legado.app.ui.theme.LegadoTheme.composeEngine
|
||||
import io.legado.app.ui.theme.ThemeResolver
|
||||
import io.legado.app.ui.theme.adaptiveContentPadding
|
||||
import io.legado.app.ui.widget.components.EmptyMessage
|
||||
import io.legado.app.ui.widget.components.alert.AppAlertDialog
|
||||
import io.legado.app.ui.widget.components.card.GlassCard
|
||||
import io.legado.app.ui.widget.components.card.TextCard
|
||||
import io.legado.app.ui.widget.components.divider.PillHeaderDivider
|
||||
import io.legado.app.ui.widget.components.explore.ExploreKindMultiTypeItem
|
||||
import io.legado.app.ui.widget.components.EmptyMessage
|
||||
import io.legado.app.ui.widget.components.lazylist.FastScrollLazyColumn
|
||||
import io.legado.app.ui.widget.components.list.ListScaffold
|
||||
import io.legado.app.ui.widget.components.list.TopFloatingStickyItem
|
||||
@@ -79,7 +77,6 @@ import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
|
||||
import io.legado.app.ui.widget.components.progressIndicator.AppContainedLoadingIndicator
|
||||
import io.legado.app.ui.widget.components.text.AppText
|
||||
import io.legado.app.utils.startActivity
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.androidx.compose.koinViewModel
|
||||
import org.koin.compose.koinInject
|
||||
|
||||
@@ -6,10 +6,10 @@ import io.legado.app.base.BaseViewModel
|
||||
import io.legado.app.data.entities.BookSourcePart
|
||||
import io.legado.app.data.entities.rule.ExploreKind
|
||||
import io.legado.app.data.repository.ExploreRepository
|
||||
import io.legado.app.domain.usecase.ExploreKindUiUseCase
|
||||
import io.legado.app.help.source.clearExploreKindsCache
|
||||
import io.legado.app.help.source.exploreKinds
|
||||
import io.legado.app.help.source.getExploreInfoMap
|
||||
import io.legado.app.ui.widget.components.explore.ExploreKindUiUseCase
|
||||
import io.legado.app.ui.widget.components.explore.calculateExploreKindRows
|
||||
import io.legado.app.ui.widget.components.list.ListUiState
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
@@ -52,12 +52,12 @@ import io.legado.app.ui.rss.source.edit.RssSourceEditActivity
|
||||
import io.legado.app.ui.rss.source.manage.RssSourceActivity
|
||||
import io.legado.app.ui.theme.LegadoTheme
|
||||
import io.legado.app.ui.theme.adaptiveContentPadding
|
||||
import io.legado.app.ui.widget.components.SourceIcon
|
||||
import io.legado.app.ui.widget.components.alert.AppAlertDialog
|
||||
import io.legado.app.ui.widget.components.card.GlassCard
|
||||
import io.legado.app.ui.widget.components.divider.PillDivider
|
||||
import io.legado.app.ui.widget.components.divider.PillHeaderDivider
|
||||
import io.legado.app.ui.widget.components.icon.AppIcon
|
||||
import io.legado.app.ui.widget.components.image.sourceIcon.SourceIcon
|
||||
import io.legado.app.ui.widget.components.list.ListScaffold
|
||||
import io.legado.app.ui.widget.components.menuItem.MenuItemIcon
|
||||
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu
|
||||
|
||||
@@ -61,7 +61,7 @@ import io.legado.app.ui.theme.adaptiveContentPadding
|
||||
import io.legado.app.ui.widget.components.AppPullToRefresh
|
||||
import io.legado.app.ui.widget.components.EmptyMessage
|
||||
import io.legado.app.ui.widget.components.card.GlassCard
|
||||
import io.legado.app.ui.widget.components.cover.buildCoverImageRequest
|
||||
import io.legado.app.ui.widget.components.image.cover.buildCoverImageRequest
|
||||
import io.legado.app.utils.toastOnUi
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.flow.catch
|
||||
|
||||
@@ -33,11 +33,11 @@ import io.legado.app.data.entities.RssStar
|
||||
import io.legado.app.ui.theme.adaptiveContentPadding
|
||||
import io.legado.app.ui.widget.components.ActionItem
|
||||
import io.legado.app.ui.widget.components.EmptyMessage
|
||||
import io.legado.app.ui.widget.components.SourceIcon
|
||||
import io.legado.app.ui.widget.components.button.SmallIconButton
|
||||
import io.legado.app.ui.widget.components.card.SelectionItemCard
|
||||
import io.legado.app.ui.widget.components.dialog.TextListInputDialog
|
||||
import io.legado.app.ui.widget.components.divider.PillDivider
|
||||
import io.legado.app.ui.widget.components.image.sourceIcon.SourceIcon
|
||||
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
|
||||
import io.legado.app.ui.widget.components.rules.RuleListScaffold
|
||||
import org.koin.androidx.compose.koinViewModel
|
||||
|
||||
+1
-2
@@ -1,4 +1,4 @@
|
||||
package io.legado.app.ui.widget
|
||||
package io.legado.app.ui.widget.components
|
||||
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -10,7 +10,6 @@ import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ExpandMore
|
||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
@@ -1,40 +0,0 @@
|
||||
package io.legado.app.ui.widget.components
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Composable
|
||||
fun SectionHeader(
|
||||
// 左侧主标题内容
|
||||
titleContent: @Composable () -> Unit,
|
||||
// 右侧或副标题内容
|
||||
detailContent: @Composable (() -> Unit)? = null,
|
||||
// 主要内容的排列方式
|
||||
verticalArrangement: Arrangement.Vertical = Arrangement.Center,
|
||||
// 定义水平对齐方式
|
||||
horizontalArrangement: Arrangement.Horizontal = Arrangement.SpaceBetween,
|
||||
// 根容器的 Padding
|
||||
contentPadding: PaddingValues = PaddingValues(horizontal = 16.dp, vertical = 8.dp)
|
||||
) {
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(contentPadding),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = horizontalArrangement
|
||||
) {
|
||||
titleContent()
|
||||
detailContent?.let {
|
||||
it()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -144,6 +144,7 @@ fun <T> AppAlertDialog(
|
||||
onDismissRequest: () -> Unit,
|
||||
title: String? = null,
|
||||
text: String? = null,
|
||||
textProvider: @Composable (T.() -> String)? = null,
|
||||
confirmText: String = "确定",
|
||||
onConfirm: ((T) -> Unit)? = null,
|
||||
dismissText: String = "取消",
|
||||
@@ -159,11 +160,17 @@ fun <T> AppAlertDialog(
|
||||
|
||||
val currentData = cachedData
|
||||
if (currentData != null) {
|
||||
val currentText = text ?: textProvider?.invoke(currentData)
|
||||
var cachedText by remember { mutableStateOf(currentText) }
|
||||
if (currentText != null) {
|
||||
cachedText = currentText
|
||||
}
|
||||
|
||||
AppAlertDialog(
|
||||
show = data != null,
|
||||
onDismissRequest = onDismissRequest,
|
||||
title = title,
|
||||
text = text,
|
||||
text = currentText ?: cachedText,
|
||||
modifier = modifier,
|
||||
confirmText = confirmText,
|
||||
onConfirm = onConfirm?.let { { it(currentData) } },
|
||||
|
||||
@@ -33,7 +33,7 @@ import io.legado.app.data.entities.SearchBook
|
||||
import io.legado.app.domain.model.BookShelfState
|
||||
import io.legado.app.ui.theme.LegadoTheme
|
||||
import io.legado.app.ui.widget.components.card.TextCard
|
||||
import io.legado.app.ui.widget.components.cover.CoilBookCover
|
||||
import io.legado.app.ui.widget.components.image.cover.CoilBookCover
|
||||
import io.legado.app.ui.widget.components.text.AppText
|
||||
|
||||
@OptIn(ExperimentalSharedTransitionApi::class)
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
package io.legado.app.ui.widget.components.cover
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Book
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import coil.ImageLoader
|
||||
import coil.compose.AsyncImage
|
||||
import io.legado.app.ui.theme.LegadoTheme
|
||||
import org.koin.compose.koinInject
|
||||
|
||||
@Composable
|
||||
fun Cover(
|
||||
path: Any?,
|
||||
modifier: Modifier = Modifier.width(48.dp),
|
||||
badgeContent: (@Composable RowScope.() -> Unit)? = null,
|
||||
loadOnlyWifi: Boolean = false,
|
||||
sourceOrigin: String? = null,
|
||||
imageLoader: ImageLoader = koinInject(),
|
||||
onLoadFinish: (() -> Unit)? = null
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
val boxModifier = modifier
|
||||
.aspectRatio(3f / 4f)
|
||||
.clip(RoundedCornerShape(4.dp))
|
||||
.background(LegadoTheme.colorScheme.surfaceContainer)
|
||||
|
||||
Box(modifier = boxModifier) {
|
||||
if (path == null) {
|
||||
Icon(
|
||||
Icons.Default.Book,
|
||||
contentDescription = null,
|
||||
tint = LegadoTheme.colorScheme.surfaceContainerHighest,
|
||||
modifier = Modifier
|
||||
.size(24.dp)
|
||||
.align(Alignment.Center)
|
||||
)
|
||||
} else {
|
||||
AsyncImage(
|
||||
model = buildCoverImageRequest(
|
||||
context = context,
|
||||
data = path,
|
||||
sourceOrigin = sourceOrigin,
|
||||
loadOnlyWifi = loadOnlyWifi,
|
||||
crossfade = true,
|
||||
) {
|
||||
listener(
|
||||
onSuccess = { _, _ -> onLoadFinish?.invoke() },
|
||||
onError = { _, _ -> onLoadFinish?.invoke() }
|
||||
)
|
||||
},
|
||||
imageLoader = imageLoader,
|
||||
contentDescription = null,
|
||||
contentScale = ContentScale.Crop,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
}
|
||||
|
||||
if (badgeContent != null) {
|
||||
Surface(
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopEnd)
|
||||
.padding(2.dp),
|
||||
shape = RoundedCornerShape(4.dp),
|
||||
color = LegadoTheme.colorScheme.secondaryContainer,
|
||||
contentColor = LegadoTheme.colorScheme.onSecondaryContainer,
|
||||
tonalElevation = 2.dp
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.padding(2.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
content = badgeContent
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-12
@@ -10,13 +10,9 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.BasicTextField
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowRight
|
||||
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
|
||||
import androidx.compose.material.icons.automirrored.filled.OpenInNew
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowDown
|
||||
import androidx.compose.material.icons.filled.Refresh
|
||||
import androidx.compose.material.icons.filled.UnfoldMore
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
@@ -25,32 +21,28 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.legado.app.App
|
||||
import io.legado.app.data.entities.rule.ExploreKind
|
||||
import io.legado.app.ui.widget.components.explore.ExploreKindUiUseCase
|
||||
import io.legado.app.domain.usecase.ExploreKindUiUseCase
|
||||
import io.legado.app.help.source.getExploreInfoMap
|
||||
import io.legado.app.ui.config.themeConfig.ThemeConfig
|
||||
import io.legado.app.ui.theme.LegadoTheme
|
||||
import io.legado.app.ui.widget.components.icon.AppIcon
|
||||
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu
|
||||
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
|
||||
import io.legado.app.ui.widget.components.text.AppText
|
||||
import io.legado.app.ui.widget.dialog.TextDialog
|
||||
import io.legado.app.ui.theme.LegadoTheme
|
||||
import io.legado.app.ui.widget.components.icon.AppIcon
|
||||
import io.legado.app.utils.showDialogFragment
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import top.yukonga.miuix.kmp.icon.MiuixIcons
|
||||
import top.yukonga.miuix.kmp.icon.basic.ArrowUpDown
|
||||
|
||||
@Composable
|
||||
fun ExploreKindMultiTypeItem(
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
package io.legado.app.ui.widget.components.cover
|
||||
package io.legado.app.ui.widget.components.image.cover
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibilityScope
|
||||
import androidx.compose.animation.ExperimentalSharedTransitionApi
|
||||
@@ -14,8 +14,8 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.legado.app.ui.theme.LegadoTheme
|
||||
import io.legado.app.ui.widget.components.progressIndicator.AppLinearProgressIndicator
|
||||
import io.legado.app.ui.widget.components.card.TextCard
|
||||
import io.legado.app.ui.widget.components.progressIndicator.AppLinearProgressIndicator
|
||||
|
||||
@OptIn(ExperimentalSharedTransitionApi::class)
|
||||
@Composable
|
||||
+7
-4
@@ -1,4 +1,4 @@
|
||||
package io.legado.app.ui.widget.components.cover
|
||||
package io.legado.app.ui.widget.components.image.cover
|
||||
|
||||
import android.graphics.Paint
|
||||
import android.graphics.Typeface
|
||||
@@ -15,7 +15,6 @@ import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
@@ -122,7 +121,9 @@ fun CoilBookCover(
|
||||
contentDescription = null,
|
||||
imageLoader = koinInject(),
|
||||
contentScale = ContentScale.Crop,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.clip(RoundedCornerShape(4.dp))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -138,7 +139,9 @@ fun CoilBookCover(
|
||||
contentDescription = null,
|
||||
imageLoader = koinInject(),
|
||||
contentScale = ContentScale.Crop,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.clip(RoundedCornerShape(4.dp)),
|
||||
onSuccess = {
|
||||
isOnlineCoverLoaded = true
|
||||
onLoadFinish?.invoke()
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package io.legado.app.ui.widget.components.cover
|
||||
package io.legado.app.ui.widget.components.image.cover
|
||||
|
||||
import android.content.Context
|
||||
import coil.request.ImageRequest
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package io.legado.app.ui.widget.components
|
||||
package io.legado.app.ui.widget.components.image.sourceIcon
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
@@ -87,6 +87,7 @@ private fun AppTab(
|
||||
text = title,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
style = LegadoTheme.typography.labelLargeEmphasized,
|
||||
modifier = Modifier.padding(horizontal = 8.dp),
|
||||
color = if (selected) LegadoTheme.colorScheme.primary else LegadoTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user