diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml index f4d6d06e..4c7eefc2 100644 --- a/.idea/deploymentTargetDropDown.xml +++ b/.idea/deploymentTargetDropDown.xml @@ -1,17 +1,17 @@ - + - + - - + + - - + + \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index bebf3976..1e273c91 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -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") diff --git a/app/src/main/java/xyz/quaver/pupil/Pupil.kt b/app/src/main/java/xyz/quaver/pupil/Pupil.kt index bd4fa425..b2d061a4 100644 --- a/app/src/main/java/xyz/quaver/pupil/Pupil.kt +++ b/app/src/main/java/xyz/quaver/pupil/Pupil.kt @@ -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 diff --git a/app/src/main/java/xyz/quaver/pupil/sources/Common.kt b/app/src/main/java/xyz/quaver/pupil/sources/Common.kt index f8a6adb5..57eefd11 100644 --- a/app/src/main/java/xyz/quaver/pupil/sources/Common.kt +++ b/app/src/main/java/xyz/quaver/pupil/sources/Common.kt @@ -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 = emptyMap() open fun onSuggestionBind(binding: SearchSuggestionItemBinding, item: SearchSuggestion) { binding.leftIcon.setImageResource(R.drawable.tag) diff --git a/app/src/main/java/xyz/quaver/pupil/sources/hitomi/Hitomi.kt b/app/src/main/java/xyz/quaver/pupil/sources/hitomi/Hitomi.kt index 7e95be63..4ab25149 100644 --- a/app/src/main/java/xyz/quaver/pupil/sources/hitomi/Hitomi.kt +++ b/app/src/main/java/xyz/quaver/pupil/sources/hitomi/Hitomi.kt @@ -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 diff --git a/app/src/main/java/xyz/quaver/pupil/ui/ReaderActivity.kt b/app/src/main/java/xyz/quaver/pupil/ui/ReaderActivity.kt index 2bb693e4..931bfdfc 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/ReaderActivity.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/ReaderActivity.kt @@ -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() + } + } } \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/ui/composable/MultipleFloatingActionButton.kt b/app/src/main/java/xyz/quaver/pupil/ui/composable/MultipleFloatingActionButton.kt index f649e5d4..9bd49333 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/composable/MultipleFloatingActionButton.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/composable/MultipleFloatingActionButton.kt @@ -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, diff --git a/app/src/main/java/xyz/quaver/pupil/ui/viewmodel/ReaderViewModel.kt b/app/src/main/java/xyz/quaver/pupil/ui/viewmodel/ReaderViewModel.kt index 87c6ee1e..bb1d0e1a 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/viewmodel/ReaderViewModel.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/viewmodel/ReaderViewModel.kt @@ -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) - }) + }!!) } }