Convert Batch Add to Compose + Voyager
This commit is contained in:
parent
0142e0f771
commit
c14b7879a4
@ -1,168 +1,16 @@
|
||||
package exh.ui.batchadd
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.isVisible
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import dev.chrisbanes.insetter.applyInsetter
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.databinding.EhFragmentBatchAddBinding
|
||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.buffer
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.mapLatest
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import reactivecircus.flowbinding.android.view.clicks
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
import androidx.compose.runtime.Composable
|
||||
import cafe.adriel.voyager.navigator.Navigator
|
||||
import eu.kanade.tachiyomi.ui.base.controller.BasicFullComposeController
|
||||
|
||||
/**
|
||||
* Batch add screen
|
||||
*/
|
||||
class BatchAddController : NucleusController<EhFragmentBatchAddBinding, BatchAddPresenter>() {
|
||||
override fun getTitle() = activity!!.getString(R.string.batch_add)
|
||||
class BatchAddController : BasicFullComposeController() {
|
||||
|
||||
override fun createPresenter() = BatchAddPresenter()
|
||||
|
||||
override fun createBinding(inflater: LayoutInflater) = EhFragmentBatchAddBinding.inflate(inflater)
|
||||
|
||||
override fun onViewCreated(view: View) {
|
||||
super.onViewCreated(view)
|
||||
|
||||
binding.btnAddGalleries.clicks()
|
||||
.onEach {
|
||||
addGalleries(binding.galleriesBox.text.toString())
|
||||
}
|
||||
.launchIn(viewScope)
|
||||
|
||||
binding.progressDismissBtn.clicks()
|
||||
.onEach {
|
||||
presenter.currentlyAddingFlow.value = BatchAddPresenter.STATE_PROGRESS_TO_INPUT
|
||||
}
|
||||
.launchIn(viewScope)
|
||||
|
||||
binding.scrollView.applyInsetter {
|
||||
type(navigationBars = true) {
|
||||
padding()
|
||||
}
|
||||
}
|
||||
|
||||
presenter.currentlyAddingFlow
|
||||
.buffer(capacity = 0, onBufferOverflow = BufferOverflow.SUSPEND)
|
||||
.mapLatest { event ->
|
||||
when (event) {
|
||||
BatchAddPresenter.STATE_INPUT_TO_PROGRESS -> coroutineScope {
|
||||
showProgress(binding)
|
||||
presenter.progressFlow
|
||||
.buffer(capacity = Channel.RENDEZVOUS)
|
||||
.combine(presenter.progressTotalFlow) { progress, total ->
|
||||
// Show hide dismiss button
|
||||
binding.progressDismissBtn.isVisible = progress == total
|
||||
formatProgress(progress, total)
|
||||
}
|
||||
.onEach {
|
||||
binding.progressText.text = it
|
||||
}
|
||||
.launchIn(this)
|
||||
|
||||
presenter.progressTotalFlow
|
||||
.buffer(capacity = Channel.RENDEZVOUS)
|
||||
.onEach {
|
||||
binding.progressBar.max = it
|
||||
}
|
||||
.launchIn(this)
|
||||
|
||||
presenter.progressFlow
|
||||
.buffer(capacity = Channel.RENDEZVOUS)
|
||||
.onEach {
|
||||
binding.progressBar.progress = it
|
||||
}
|
||||
.launchIn(this)
|
||||
|
||||
presenter.eventFlow
|
||||
?.buffer(capacity = Channel.RENDEZVOUS)
|
||||
?.onEach {
|
||||
binding.progressLog.append("$it\n")
|
||||
}
|
||||
?.launchIn(this)
|
||||
Unit
|
||||
}
|
||||
BatchAddPresenter.STATE_PROGRESS_TO_INPUT -> {
|
||||
hideProgress(binding)
|
||||
presenter.currentlyAddingFlow.value = BatchAddPresenter.STATE_IDLE
|
||||
}
|
||||
}
|
||||
}
|
||||
.launchIn(viewScope)
|
||||
}
|
||||
|
||||
private val EhFragmentBatchAddBinding.progressViews
|
||||
get() = listOf(
|
||||
progressTitleView,
|
||||
progressLog,
|
||||
progressBar,
|
||||
progressText,
|
||||
)
|
||||
|
||||
private val EhFragmentBatchAddBinding.inputViews
|
||||
get() = listOf(
|
||||
inputTitleView,
|
||||
galleriesBox,
|
||||
btnAddGalleries,
|
||||
)
|
||||
|
||||
private var List<View>.isVisible: Boolean
|
||||
get() = throw UnsupportedOperationException()
|
||||
set(v) {
|
||||
forEach { it.isVisible = v }
|
||||
}
|
||||
|
||||
private fun showProgress(target: EhFragmentBatchAddBinding = binding) {
|
||||
target.apply {
|
||||
viewScope.launch {
|
||||
inputViews.isVisible = false
|
||||
delay(0.5.seconds)
|
||||
progressViews.isVisible = true
|
||||
}
|
||||
}.progressLog.text = ""
|
||||
}
|
||||
|
||||
private fun hideProgress(target: EhFragmentBatchAddBinding = binding) {
|
||||
target.apply {
|
||||
viewScope.launch {
|
||||
progressViews.isVisible = false
|
||||
binding.progressDismissBtn.isVisible = false
|
||||
delay(0.5.seconds)
|
||||
inputViews.isVisible = true
|
||||
}
|
||||
}.galleriesBox.setText("", TextView.BufferType.EDITABLE)
|
||||
}
|
||||
|
||||
private fun formatProgress(progress: Int, total: Int) = "$progress/$total"
|
||||
|
||||
private fun addGalleries(galleries: String) {
|
||||
// Check text box has content
|
||||
if (galleries.isBlank()) {
|
||||
noGalleriesSpecified()
|
||||
return
|
||||
}
|
||||
|
||||
presenter.addGalleries(applicationContext!!, galleries)
|
||||
}
|
||||
|
||||
private fun noGalleriesSpecified() {
|
||||
activity?.let {
|
||||
MaterialAlertDialogBuilder(it)
|
||||
.setTitle(R.string.batch_add_no_valid_galleries)
|
||||
.setMessage(R.string.batch_add_no_valid_galleries_message)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
@Composable
|
||||
override fun ComposeContent() {
|
||||
Navigator(screen = BatchAddScreen())
|
||||
}
|
||||
}
|
||||
|
@ -1,93 +0,0 @@
|
||||
package exh.ui.batchadd
|
||||
|
||||
import android.content.Context
|
||||
import eu.kanade.domain.UnsortedPreferences
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
import eu.kanade.tachiyomi.util.lang.withIOContext
|
||||
import exh.GalleryAddEvent
|
||||
import exh.GalleryAdder
|
||||
import exh.log.xLogE
|
||||
import exh.util.trimOrNull
|
||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ensureActive
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
class BatchAddPresenter : BasePresenter<BatchAddController>() {
|
||||
private val preferences: UnsortedPreferences by injectLazy()
|
||||
|
||||
private val galleryAdder by lazy { GalleryAdder() }
|
||||
|
||||
val progressTotalFlow = MutableStateFlow(0)
|
||||
val progressFlow = MutableStateFlow(0)
|
||||
var eventFlow: MutableSharedFlow<String>? = null
|
||||
val currentlyAddingFlow = MutableStateFlow(STATE_IDLE)
|
||||
|
||||
fun addGalleries(context: Context, galleries: String) {
|
||||
eventFlow = MutableSharedFlow(1)
|
||||
|
||||
val splitGalleries = if (ehVisitedRegex.containsMatchIn(galleries)) {
|
||||
val url = if (preferences.enableExhentai().get()) {
|
||||
"https://exhentai.org/g/"
|
||||
} else {
|
||||
"https://e-hentai.org/g/"
|
||||
}
|
||||
ehVisitedRegex.findAll(galleries).map { galleryKeys ->
|
||||
val linkParts = galleryKeys.value.split(".")
|
||||
url + linkParts[0] + "/" + linkParts[1].replace(":", "")
|
||||
}.toList()
|
||||
} else {
|
||||
galleries.split("\n")
|
||||
.mapNotNull(String::trimOrNull)
|
||||
}
|
||||
|
||||
progressFlow.value = 0
|
||||
progressTotalFlow.value = splitGalleries.size
|
||||
|
||||
currentlyAddingFlow.value = STATE_INPUT_TO_PROGRESS
|
||||
|
||||
val handler = CoroutineExceptionHandler { _, throwable ->
|
||||
xLogE("Batch add error", throwable)
|
||||
}
|
||||
|
||||
presenterScope.launch(Dispatchers.IO + handler) {
|
||||
val succeeded = mutableListOf<String>()
|
||||
val failed = mutableListOf<String>()
|
||||
|
||||
splitGalleries.forEachIndexed { i, s ->
|
||||
ensureActive()
|
||||
val result = withIOContext { galleryAdder.addGallery(context, s, true) }
|
||||
if (result is GalleryAddEvent.Success) {
|
||||
succeeded.add(s)
|
||||
} else {
|
||||
failed.add(s)
|
||||
}
|
||||
progressFlow.value = i + 1
|
||||
eventFlow?.emit(
|
||||
(
|
||||
when (result) {
|
||||
is GalleryAddEvent.Success -> context.getString(R.string.batch_add_ok)
|
||||
is GalleryAddEvent.Fail -> context.getString(R.string.batch_add_error)
|
||||
}
|
||||
) + " " + result.logMessage,
|
||||
)
|
||||
}
|
||||
|
||||
// Show report
|
||||
val summary = context.getString(R.string.batch_add_summary, succeeded.size, failed.size)
|
||||
eventFlow?.emit(summary)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val STATE_IDLE = 0
|
||||
const val STATE_INPUT_TO_PROGRESS = 1
|
||||
const val STATE_PROGRESS_TO_INPUT = 2
|
||||
|
||||
val ehVisitedRegex = """[0-9]*?\.[a-z0-9]*?:""".toRegex()
|
||||
}
|
||||
}
|
174
app/src/main/java/exh/ui/batchadd/BatchAddScreen.kt
Normal file
174
app/src/main/java/exh/ui/batchadd/BatchAddScreen.kt
Normal file
@ -0,0 +1,174 @@
|
||||
package exh.ui.batchadd
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
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.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.LinearProgressIndicator
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||
import cafe.adriel.voyager.core.screen.Screen
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import eu.kanade.presentation.components.AppBar
|
||||
import eu.kanade.presentation.components.Button
|
||||
import eu.kanade.presentation.components.LazyColumn
|
||||
import eu.kanade.presentation.components.Scaffold
|
||||
import eu.kanade.presentation.util.LocalRouter
|
||||
import eu.kanade.presentation.util.padding
|
||||
import eu.kanade.presentation.util.plus
|
||||
import eu.kanade.tachiyomi.R
|
||||
|
||||
class BatchAddScreen : Screen {
|
||||
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val screenModel = rememberScreenModel { BatchAddScreenModel() }
|
||||
val state by screenModel.state.collectAsState()
|
||||
val navigator = LocalNavigator.currentOrThrow
|
||||
val router = LocalRouter.currentOrThrow
|
||||
val context = LocalContext.current
|
||||
|
||||
Scaffold(
|
||||
topBar = { scrollBehavior ->
|
||||
AppBar(
|
||||
title = stringResource(R.string.batch_add),
|
||||
navigateUp = {
|
||||
when {
|
||||
navigator.canPop -> navigator.pop()
|
||||
else -> router.popCurrentController()
|
||||
}
|
||||
},
|
||||
scrollBehavior = scrollBehavior,
|
||||
)
|
||||
},
|
||||
) { paddingValues ->
|
||||
when (state.state) {
|
||||
BatchAddScreenModel.State.INPUT -> {
|
||||
Column(
|
||||
Modifier
|
||||
.padding(paddingValues)
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(MaterialTheme.padding.medium),
|
||||
) {
|
||||
Text(text = stringResource(R.string.eh_batch_add_title), style = MaterialTheme.typography.titleLarge)
|
||||
Spacer(Modifier.height(8.dp))
|
||||
TextField(
|
||||
value = state.galleries,
|
||||
onValueChange = screenModel::updateGalleries,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
placeholder = {
|
||||
Text(
|
||||
text = stringResource(R.string.eh_batch_add_description),
|
||||
)
|
||||
},
|
||||
keyboardOptions = KeyboardOptions(autoCorrect = false),
|
||||
textStyle = MaterialTheme.typography.bodyLarge,
|
||||
|
||||
)
|
||||
Spacer(Modifier.height(8.dp))
|
||||
Button(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onClick = { screenModel.addGalleries(context) },
|
||||
) {
|
||||
Text(text = stringResource(R.string.eh_batch_add_button))
|
||||
}
|
||||
}
|
||||
}
|
||||
BatchAddScreenModel.State.PROGRESS -> {
|
||||
LazyColumn(
|
||||
contentPadding = paddingValues + PaddingValues(MaterialTheme.padding.medium),
|
||||
) {
|
||||
item(key = "top") {
|
||||
Column {
|
||||
Text(text = stringResource(R.string.eh_batch_add_adding_galleries), style = MaterialTheme.typography.titleLarge)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Row(
|
||||
Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
LinearProgressIndicator(
|
||||
progress = state.progress.toFloat() / state.progressTotal,
|
||||
Modifier
|
||||
.padding(top = 2.dp)
|
||||
.weight(1f),
|
||||
)
|
||||
Text(
|
||||
text = state.progress.toString() + "/" + state.progressTotal,
|
||||
modifier = Modifier.weight(0.15f),
|
||||
textAlign = TextAlign.Center,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
}
|
||||
}
|
||||
itemsIndexed(
|
||||
state.events,
|
||||
key = { index, text -> index + text.hashCode() },
|
||||
) { _, text ->
|
||||
Text(
|
||||
text = text,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
if (state.progress == state.progressTotal) {
|
||||
item(key = "finish") {
|
||||
Column {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Button(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onClick = screenModel::finish,
|
||||
) {
|
||||
Text(text = stringResource(R.string.eh_batch_add_finish))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val onDismissRequest = screenModel::dismissDialog
|
||||
when (state.dialog) {
|
||||
BatchAddScreenModel.Dialog.NoGalleriesSpecified -> AlertDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
confirmButton = {
|
||||
TextButton(onClick = onDismissRequest) {
|
||||
Text(text = stringResource(android.R.string.ok))
|
||||
}
|
||||
},
|
||||
title = {
|
||||
Text(text = stringResource(R.string.batch_add_no_valid_galleries))
|
||||
},
|
||||
text = {
|
||||
Text(text = stringResource(R.string.batch_add_no_valid_galleries_message))
|
||||
},
|
||||
)
|
||||
null -> Unit
|
||||
}
|
||||
}
|
||||
}
|
141
app/src/main/java/exh/ui/batchadd/BatchAddScreenModel.kt
Normal file
141
app/src/main/java/exh/ui/batchadd/BatchAddScreenModel.kt
Normal file
@ -0,0 +1,141 @@
|
||||
package exh.ui.batchadd
|
||||
|
||||
import android.content.Context
|
||||
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||
import cafe.adriel.voyager.core.model.coroutineScope
|
||||
import eu.kanade.domain.UnsortedPreferences
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.util.lang.withIOContext
|
||||
import exh.GalleryAddEvent
|
||||
import exh.GalleryAdder
|
||||
import exh.log.xLogE
|
||||
import exh.util.trimOrNull
|
||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ensureActive
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class BatchAddScreenModel(
|
||||
private val unsortedPreferences: UnsortedPreferences = Injekt.get(),
|
||||
) : StateScreenModel<BatchAddState>(BatchAddState()) {
|
||||
private val galleryAdder by lazy { GalleryAdder() }
|
||||
|
||||
fun addGalleries(context: Context) {
|
||||
val galleries = state.value.galleries
|
||||
// Check text box has content
|
||||
if (galleries.isBlank()) {
|
||||
mutableState.update { it.copy(dialog = Dialog.NoGalleriesSpecified) }
|
||||
return
|
||||
}
|
||||
|
||||
addGalleries(context, galleries)
|
||||
}
|
||||
|
||||
private fun addGalleries(context: Context, galleries: String) {
|
||||
val splitGalleries = if (ehVisitedRegex.containsMatchIn(galleries)) {
|
||||
val url = if (unsortedPreferences.enableExhentai().get()) {
|
||||
"https://exhentai.org/g/"
|
||||
} else {
|
||||
"https://e-hentai.org/g/"
|
||||
}
|
||||
ehVisitedRegex.findAll(galleries).map { galleryKeys ->
|
||||
val linkParts = galleryKeys.value.split(".")
|
||||
url + linkParts[0] + "/" + linkParts[1].replace(":", "")
|
||||
}.toList()
|
||||
} else {
|
||||
galleries.split("\n")
|
||||
.mapNotNull(String::trimOrNull)
|
||||
}
|
||||
|
||||
mutableState.update { state ->
|
||||
state.copy(
|
||||
progress = 0,
|
||||
progressTotal = splitGalleries.size,
|
||||
state = State.PROGRESS,
|
||||
)
|
||||
}
|
||||
|
||||
val handler = CoroutineExceptionHandler { _, throwable ->
|
||||
xLogE("Batch add error", throwable)
|
||||
}
|
||||
|
||||
coroutineScope.launch(Dispatchers.IO + handler) {
|
||||
val succeeded = mutableListOf<String>()
|
||||
val failed = mutableListOf<String>()
|
||||
|
||||
splitGalleries.forEachIndexed { i, s ->
|
||||
ensureActive()
|
||||
val result = withIOContext { galleryAdder.addGallery(context, s, true) }
|
||||
if (result is GalleryAddEvent.Success) {
|
||||
succeeded.add(s)
|
||||
} else {
|
||||
failed.add(s)
|
||||
}
|
||||
mutableState.update { state ->
|
||||
state.copy(
|
||||
progress = i + 1,
|
||||
events = state.events.plus(
|
||||
when (result) {
|
||||
is GalleryAddEvent.Success -> context.getString(R.string.batch_add_ok)
|
||||
is GalleryAddEvent.Fail -> context.getString(R.string.batch_add_error)
|
||||
} + " " + result.logMessage,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Show report
|
||||
val summary = context.getString(R.string.batch_add_summary, succeeded.size, failed.size)
|
||||
mutableState.update { state ->
|
||||
state.copy(
|
||||
events = state.events + summary,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun finish() {
|
||||
mutableState.update { state ->
|
||||
state.copy(
|
||||
progressTotal = 0,
|
||||
progress = 0,
|
||||
galleries = "",
|
||||
state = State.INPUT,
|
||||
events = emptyList(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateGalleries(galleries: String) {
|
||||
mutableState.update { it.copy(galleries = galleries) }
|
||||
}
|
||||
|
||||
fun dismissDialog() {
|
||||
mutableState.update { it.copy(dialog = null) }
|
||||
}
|
||||
|
||||
enum class State {
|
||||
INPUT,
|
||||
PROGRESS,
|
||||
}
|
||||
|
||||
sealed class Dialog {
|
||||
object NoGalleriesSpecified : Dialog()
|
||||
}
|
||||
|
||||
companion object {
|
||||
val ehVisitedRegex = """[0-9]*?\.[a-z0-9]*?:""".toRegex()
|
||||
}
|
||||
}
|
||||
|
||||
data class BatchAddState(
|
||||
val progressTotal: Int = 0,
|
||||
val progress: Int = 0,
|
||||
val galleries: String = "",
|
||||
val state: BatchAddScreenModel.State = BatchAddScreenModel.State.INPUT,
|
||||
val events: List<String> = emptyList(),
|
||||
val dialog: BatchAddScreenModel.Dialog? = null,
|
||||
)
|
@ -1,115 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/scroll_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:animateLayoutChanges="true"
|
||||
android:padding="16dp">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/input_title_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/eh_batch_add_title"
|
||||
android:textAppearance="?attr/textAppearanceTitleLarge"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<eu.kanade.tachiyomi.widget.TachiyomiTextInputEditText
|
||||
android:id="@+id/galleries_box"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:ems="10"
|
||||
android:gravity="top"
|
||||
android:hint="@string/eh_batch_add_description"
|
||||
android:inputType="textUri|textMultiLine|textNoSuggestions"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/input_title_view" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_add_galleries"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/eh_batch_add_button"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/galleries_box" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/progress_title_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/eh_batch_add_adding_galleries"
|
||||
android:textAppearance="?attr/textAppearanceTitleLarge"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/progress_bar_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="8dp"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/progress_title_view">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress_bar"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:paddingTop="2dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/progress_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0.15"
|
||||
android:background="#00000000"
|
||||
android:scrollHorizontally="false"
|
||||
android:textAlignment="center"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/progress_log"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:textAlignment="center"
|
||||
android:textAppearance="?attr/textAppearanceBodyMedium"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/progress_bar_text" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/progress_dismiss_btn"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/eh_batch_add_finish"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/progress_log" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
Loading…
x
Reference in New Issue
Block a user