WIP
This commit is contained in:
12
.idea/deploymentTargetDropDown.xml
generated
12
.idea/deploymentTargetDropDown.xml
generated
@@ -1,17 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="deploymentTargetDropDown">
|
||||
<targetSelectedWithDropDown>
|
||||
<runningDeviceTargetSelectedWithDropDown>
|
||||
<Target>
|
||||
<type value="QUICK_BOOT_TARGET" />
|
||||
<type value="RUNNING_DEVICE_TARGET" />
|
||||
<deviceKey>
|
||||
<Key>
|
||||
<type value="VIRTUAL_DEVICE_PATH" />
|
||||
<value value="$USER_HOME$/.android/avd/Pixel_3a_API_30_x86.avd" />
|
||||
<type value="SERIAL_NUMBER" />
|
||||
<value value="ce021712e3b19b2b04" />
|
||||
</Key>
|
||||
</deviceKey>
|
||||
</Target>
|
||||
</targetSelectedWithDropDown>
|
||||
<timeTargetWasSelectedWithDropDown value="2021-09-15T00:09:20.844719Z" />
|
||||
</runningDeviceTargetSelectedWithDropDown>
|
||||
<timeTargetWasSelectedWithDropDown value="2021-09-17T13:27:59.107239Z" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -74,7 +74,7 @@ dependencies {
|
||||
implementation("androidx.compose.runtime:runtime-livedata:1.0.2")
|
||||
implementation("androidx.compose.material:material-icons-extended:1.0.2")
|
||||
implementation("androidx.activity:activity-compose:1.3.1")
|
||||
implementation("androidx.navigation:navigation-compose:2.4.0-alpha08")
|
||||
implementation("androidx.navigation:navigation-compose:2.4.0-alpha09")
|
||||
|
||||
implementation("com.google.accompanist:accompanist-flowlayout:0.16.1")
|
||||
implementation("com.google.accompanist:accompanist-appcompat-theme:0.16.0")
|
||||
|
||||
@@ -44,6 +44,8 @@ import io.ktor.client.features.json.*
|
||||
import io.ktor.client.features.json.serializer.*
|
||||
import org.kodein.di.*
|
||||
import org.kodein.di.android.x.androidXModule
|
||||
import org.kodein.log.LoggerFactory
|
||||
import org.kodein.log.newLogger
|
||||
import xyz.quaver.io.FileX
|
||||
import xyz.quaver.pupil.db.databaseModule
|
||||
import xyz.quaver.pupil.sources.sourceModule
|
||||
|
||||
@@ -64,7 +64,7 @@ abstract class Source {
|
||||
@Composable
|
||||
open fun SearchResult(itemInfo: ItemInfo, onEvent: ((SearchResultEvent) -> Unit)? = null) { }
|
||||
|
||||
open fun getHeadersBuilderForImage(itemID: String, url: String): HeadersBuilder.() -> Unit = { }
|
||||
open fun getHeadersForImage(itemID: String, url: String): Map<String, String> = emptyMap()
|
||||
|
||||
open fun onSuggestionBind(binding: SearchSuggestionItemBinding, item: SearchSuggestion) {
|
||||
binding.leftIcon.setImageResource(R.drawable.tag)
|
||||
|
||||
@@ -225,9 +225,9 @@ class Hitomi(app: Application) : Source(), DIAware {
|
||||
FullSearchResult(itemInfo = itemInfo)
|
||||
}
|
||||
|
||||
override fun getHeadersBuilderForImage(itemID: String, url: String): HeadersBuilder.() -> Unit = {
|
||||
append("Referer", getReferer(itemID.toInt()))
|
||||
}
|
||||
override fun getHeadersForImage(itemID: String, url: String) = mapOf(
|
||||
"Referer" to getReferer(itemID.toInt())
|
||||
)
|
||||
|
||||
override fun onSuggestionBind(binding: SearchSuggestionItemBinding, item: SearchSuggestion) {
|
||||
item as TagSuggestion
|
||||
|
||||
@@ -23,10 +23,11 @@ import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.viewModels
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TopAppBar
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Fullscreen
|
||||
import androidx.compose.runtime.getValue
|
||||
@@ -34,13 +35,23 @@ import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.WindowInsetsControllerCompat
|
||||
import coil.annotation.ExperimentalCoilApi
|
||||
import coil.compose.rememberImagePainter
|
||||
import coil.request.ImageRequest
|
||||
import coil.transform.BlurTransformation
|
||||
import com.google.accompanist.appcompattheme.AppCompatTheme
|
||||
import io.ktor.http.*
|
||||
import okhttp3.Headers
|
||||
import org.kodein.di.DIAware
|
||||
import org.kodein.di.android.closestDI
|
||||
import org.kodein.log.LoggerFactory
|
||||
import org.kodein.log.newLogger
|
||||
import xyz.quaver.pupil.R
|
||||
import xyz.quaver.pupil.ui.composable.FloatingActionButtonState
|
||||
import xyz.quaver.pupil.ui.composable.MultipleFloatingActionButton
|
||||
@@ -52,12 +63,24 @@ class ReaderActivity : ComponentActivity(), DIAware {
|
||||
|
||||
private val model: ReaderViewModel by viewModels()
|
||||
|
||||
private val logger = newLogger(LoggerFactory.default)
|
||||
|
||||
@OptIn(ExperimentalCoilApi::class)
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
model.handleIntent(intent)
|
||||
model.load()
|
||||
|
||||
setContent {
|
||||
var isFABExpanded by remember { mutableStateOf(FloatingActionButtonState.COLLAPSED) }
|
||||
val isFullscreen by model.isFullscreen.observeAsState(false)
|
||||
val title by model.title.observeAsState(stringResource(R.string.reader_loading))
|
||||
val sourceIcon by model.sourceIcon.observeAsState()
|
||||
val images by model.images.observeAsState(emptyList())
|
||||
val source by model.sourceInstance.observeAsState()
|
||||
|
||||
logger.debug { "target: ${R.drawable.hitomi} value: $sourceIcon" }
|
||||
|
||||
WindowInsetsControllerCompat(window, window.decorView).run {
|
||||
if (isFullscreen) {
|
||||
@@ -74,30 +97,69 @@ class ReaderActivity : ComponentActivity(), DIAware {
|
||||
TopAppBar(
|
||||
title = {
|
||||
Text(
|
||||
"Reader",
|
||||
title,
|
||||
color = MaterialTheme.colors.onSecondary
|
||||
)
|
||||
},
|
||||
actions = {
|
||||
sourceIcon?.let { sourceIcon ->
|
||||
Image(
|
||||
modifier = Modifier.size(36.dp),
|
||||
painter = painterResource(id = sourceIcon),
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
floatingActionButton = {
|
||||
MultipleFloatingActionButton(
|
||||
items = listOf(
|
||||
SubFabItem(
|
||||
icon = Icons.Default.Fullscreen,
|
||||
label = stringResource(id = R.string.reader_fab_fullscreen)
|
||||
) {
|
||||
model.isFullscreen.postValue(!isFullscreen)
|
||||
if (!isFullscreen)
|
||||
MultipleFloatingActionButton(
|
||||
items = listOf(
|
||||
SubFabItem(
|
||||
icon = Icons.Default.Fullscreen,
|
||||
label = stringResource(id = R.string.reader_fab_fullscreen)
|
||||
) {
|
||||
model.isFullscreen.postValue(!isFullscreen)
|
||||
}
|
||||
),
|
||||
targetState = isFABExpanded,
|
||||
onStateChanged = {
|
||||
isFABExpanded = it
|
||||
}
|
||||
),
|
||||
targetState = isFABExpanded,
|
||||
onStateChanged = {
|
||||
isFABExpanded = it
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
) {
|
||||
|
||||
LazyColumn(
|
||||
verticalArrangement = Arrangement.spacedBy(32.dp)
|
||||
) {
|
||||
items(images) { image ->
|
||||
Image(
|
||||
modifier = Modifier.fillMaxWidth().heightIn(128.dp, 1000.dp),
|
||||
painter = rememberImagePainter(
|
||||
ImageRequest.Builder(this@ReaderActivity)
|
||||
.data(image)
|
||||
.headers(
|
||||
Headers.headersOf(
|
||||
*(source!!.getHeadersForImage(model.itemID.value!!, image).entries.fold(arrayOf()) { acc, entry ->
|
||||
acc + entry.key + entry.value
|
||||
})
|
||||
).also {
|
||||
logger.debug {
|
||||
image
|
||||
}
|
||||
logger.debug {
|
||||
it.toString()
|
||||
}
|
||||
}
|
||||
)
|
||||
.transformations(BlurTransformation(this@ReaderActivity, 1f))
|
||||
.build()
|
||||
),
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -107,4 +169,11 @@ class ReaderActivity : ComponentActivity(), DIAware {
|
||||
super.onNewIntent(intent)
|
||||
model.handleIntent(intent)
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
when {
|
||||
model.isFullscreen.value == true -> model.isFullscreen.postValue(false)
|
||||
else -> super.onBackPressed()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,7 +74,7 @@ fun MiniFloatingActionButton(
|
||||
|
||||
FloatingActionButton(
|
||||
modifier = Modifier
|
||||
.size(32.dp)
|
||||
.size(40.dp)
|
||||
.scale(buttonScale),
|
||||
onClick = { onClick?.invoke(item) },
|
||||
elevation = elevation,
|
||||
@@ -185,7 +185,7 @@ fun MultipleFloatingActionButton(
|
||||
}
|
||||
|
||||
MiniFloatingActionButton(
|
||||
modifier = Modifier.padding(end = 12.dp),
|
||||
modifier = Modifier.padding(end = 8.dp),
|
||||
item = item,
|
||||
buttonScale = buttonScale,
|
||||
labelAlpha = labelAlpha,
|
||||
|
||||
@@ -28,7 +28,10 @@ import io.ktor.client.request.*
|
||||
import kotlinx.coroutines.*
|
||||
import org.kodein.di.DIAware
|
||||
import org.kodein.di.android.x.closestDI
|
||||
import org.kodein.di.direct
|
||||
import org.kodein.di.instance
|
||||
import org.kodein.log.LoggerFactory
|
||||
import org.kodein.log.newLogger
|
||||
import xyz.quaver.pupil.adapters.ReaderItem
|
||||
import xyz.quaver.pupil.db.AppDatabase
|
||||
import xyz.quaver.pupil.db.Bookmark
|
||||
@@ -42,6 +45,8 @@ class ReaderViewModel(app: Application) : AndroidViewModel(app), DIAware {
|
||||
|
||||
override val di by closestDI()
|
||||
|
||||
private val logger = newLogger(LoggerFactory.default)
|
||||
|
||||
val isFullscreen = MutableLiveData(false)
|
||||
|
||||
private val database: AppDatabase by instance()
|
||||
@@ -72,11 +77,11 @@ class ReaderViewModel(app: Application) : AndroidViewModel(app), DIAware {
|
||||
}
|
||||
|
||||
val sourceInstance = Transformations.map(source) {
|
||||
source(it)
|
||||
direct.source(it)
|
||||
}
|
||||
|
||||
val sourceIcon = Transformations.map(sourceInstance) {
|
||||
it.value.iconResID
|
||||
it.iconResID
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,18 +94,18 @@ class ReaderViewModel(app: Application) : AndroidViewModel(app), DIAware {
|
||||
val uri = intent.data
|
||||
val lastPathSegment = uri?.lastPathSegment
|
||||
if (uri != null && lastPathSegment != null) {
|
||||
_source.postValue(uri.host ?: error("Source cannot be null"))
|
||||
_itemID.postValue(when (uri.host) {
|
||||
_source.value = uri.host ?: error("Source cannot be null")
|
||||
_itemID.value = when (uri.host) {
|
||||
"hitomi.la" ->
|
||||
Regex("([0-9]+).html").find(lastPathSegment)?.groupValues?.get(1) ?: error("Invalid itemID")
|
||||
"hiyobi.me" -> lastPathSegment
|
||||
"e-hentai.org" -> uri.pathSegments[1]
|
||||
else -> error("Invalid host")
|
||||
})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_source.postValue(intent.getStringExtra("source") ?: error("Invalid source"))
|
||||
_itemID.postValue(intent.getStringExtra("id") ?: error("Invalid itemID"))
|
||||
_source.value = intent.getStringExtra("source") ?: error("Invalid source")
|
||||
_itemID.value = intent.getStringExtra("id") ?: error("Invalid itemID")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +129,7 @@ class ReaderViewModel(app: Application) : AndroidViewModel(app), DIAware {
|
||||
viewModelScope.launch {
|
||||
_images.postValue(withContext(Dispatchers.IO) {
|
||||
source.images(itemID)
|
||||
})
|
||||
}!!)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user