Pages color filter implementation draft

This commit is contained in:
Koitharu
2022-08-13 16:27:53 +03:00
parent 68dcacb918
commit d853bb2c62
10 changed files with 270 additions and 21 deletions

View File

@@ -132,11 +132,14 @@
<activity
android:name="org.koitharu.kotatsu.sync.ui.SyncAuthActivity"
android:label="@string/sync" />
<activity
android:name="org.koitharu.kotatsu.reader.ui.colorfilter.ColorFilterConfigActivity"
android:label="@string/color_filter" />
<service
android:name="org.koitharu.kotatsu.download.ui.service.DownloadService"
android:stopWithTask="false"
android:foregroundServiceType="dataSync" />
android:foregroundServiceType="dataSync"
android:stopWithTask="false" />
<service android:name="org.koitharu.kotatsu.local.ui.LocalChaptersRemoveService" />
<service android:name="org.koitharu.kotatsu.local.ui.ImportService" />
<service

View File

@@ -14,6 +14,7 @@ import androidx.core.graphics.Insets
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import com.google.android.material.R as materialR
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
import org.koitharu.kotatsu.R
@@ -46,7 +47,7 @@ class FavouritesCategoryEditActivity :
setContentView(ActivityCategoryEditBinding.inflate(layoutInflater))
supportActionBar?.run {
setDisplayHomeAsUpEnabled(true)
setHomeAsUpIndicator(com.google.android.material.R.drawable.abc_ic_clear_material)
setHomeAsUpIndicator(materialR.drawable.abc_ic_clear_material)
}
initSortSpinner()
binding.buttonDone.setOnClickListener(this)

View File

@@ -0,0 +1,108 @@
package org.koitharu.kotatsu.reader.ui.colorfilter
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.graphics.LightingColorFilter
import android.os.Bundle
import android.view.ViewGroup
import androidx.core.graphics.Insets
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import androidx.lifecycle.lifecycleScope
import coil.ImageLoader
import coil.request.ImageRequest
import coil.size.Scale
import coil.size.ViewSizeResolver
import com.google.android.material.slider.Slider
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import org.koitharu.kotatsu.base.ui.BaseActivity
import org.koitharu.kotatsu.core.model.parcelable.ParcelableMangaPages
import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.databinding.ActivityColorFilterBinding
import org.koitharu.kotatsu.parsers.model.MangaPage
import org.koitharu.kotatsu.utils.ext.enqueueWith
import org.koitharu.kotatsu.utils.ext.referer
import javax.inject.Inject
import kotlin.math.roundToInt
import com.google.android.material.R as materialR
@AndroidEntryPoint
class ColorFilterConfigActivity : BaseActivity<ActivityColorFilterBinding>(), Slider.OnChangeListener {
@Inject
lateinit var coil: ImageLoader
@Inject
lateinit var mangaRepositoryFacotry: MangaRepository.Factory
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(ActivityColorFilterBinding.inflate(layoutInflater))
supportActionBar?.run {
setDisplayHomeAsUpEnabled(true)
setHomeAsUpIndicator(materialR.drawable.abc_ic_clear_material)
}
binding.sliderLightness.addOnChangeListener(this)
binding.sliderSaturation.addOnChangeListener(this)
initPreview()
updateFilter()
}
override fun onValueChange(slider: Slider, value: Float, fromUser: Boolean) {
updateFilter()
}
override fun onWindowInsetsChanged(insets: Insets) {
binding.root.updatePadding(
left = insets.left,
right = insets.right,
)
binding.scrollView.updatePadding(
bottom = insets.bottom,
)
binding.toolbar.updateLayoutParams<ViewGroup.MarginLayoutParams> {
topMargin = insets.top
}
}
private fun updateFilter() {
fun Int.toColor() = Color.rgb(this, this, this)
val cf = LightingColorFilter(
binding.sliderSaturation.value.roundToInt().toColor(),
binding.sliderLightness.value.roundToInt().toColor(),
)
binding.imageViewAfter.colorFilter = cf
}
private fun initPreview() {
val page = intent?.getParcelableExtra<ParcelableMangaPages>(EXTRA_PAGES)?.pages?.firstOrNull()
if (page == null) {
finishAfterTransition()
return
}
lifecycleScope.launch {
val repository = mangaRepositoryFacotry.create(page.source)
val url = repository.getPageUrl(page)
ImageRequest.Builder(this@ColorFilterConfigActivity)
.data(url)
.referer(page.referer)
.scale(Scale.FILL)
.size(ViewSizeResolver(binding.imageViewBefore))
.allowRgb565(false)
.target(ShadowViewTarget(binding.imageViewBefore, binding.imageViewAfter))
.enqueueWith(coil)
}
}
companion object {
private const val EXTRA_PAGES = "pages"
fun newIntent(context: Context, page: MangaPage) = Intent(context, ColorFilterConfigActivity::class.java)
.putExtra(EXTRA_PAGES, ParcelableMangaPages(listOf(page)))
}
}

View File

@@ -0,0 +1,18 @@
package org.koitharu.kotatsu.reader.ui.colorfilter
import android.graphics.drawable.Drawable
import android.widget.ImageView
import coil.target.ImageViewTarget
class ShadowViewTarget(
view: ImageView,
private val shadowView: ImageView,
) : ImageViewTarget(view) {
override var drawable: Drawable?
get() = super.drawable
set(value) {
super.drawable = value
shadowView.setImageDrawable(value?.constantState?.newDrawable())
}
}

View File

@@ -20,6 +20,7 @@ import org.koitharu.kotatsu.core.prefs.ReaderMode
import org.koitharu.kotatsu.databinding.SheetReaderConfigBinding
import org.koitharu.kotatsu.reader.ui.PageSaveContract
import org.koitharu.kotatsu.reader.ui.ReaderViewModel
import org.koitharu.kotatsu.reader.ui.colorfilter.ColorFilterConfigActivity
import org.koitharu.kotatsu.settings.SettingsActivity
import org.koitharu.kotatsu.utils.ScreenOrientationHelper
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
@@ -59,6 +60,7 @@ class ReaderConfigBottomSheet :
binding.buttonSavePage.setOnClickListener(this)
binding.buttonScreenRotate.setOnClickListener(this)
binding.buttonSettings.setOnClickListener(this)
binding.buttonColorFilter.setOnClickListener(this)
binding.sliderTimer.addOnSliderTouchListener(this)
binding.sliderTimer.setLabelFormatter(PageSwitchTimer.DelayLabelFormatter(view.resources))
@@ -80,6 +82,10 @@ class ReaderConfigBottomSheet :
R.id.button_screen_rotate -> {
orientationHelper?.toggleOrientation()
}
R.id.button_color_filter -> {
val page = viewModel.getCurrentPage() ?: return
startActivity(ColorFilterConfigActivity.newIntent(v.context, page))
}
}
}

View File

@@ -1,5 +1,12 @@
<vector android:autoMirrored="true" android:height="24dp"
android:tint="#000000" android:viewportHeight="24"
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,4l-1.41,1.41L16.17,11H4v2h12.17l-5.58,5.59L12,20l8,-8z"/>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:autoMirrored="true"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M12,4l-1.41,1.41L16.17,11H4v2h12.17l-5.58,5.59L12,20l8,-8z" />
</vector>

View File

@@ -0,0 +1,108 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
tools:navigationIcon="@drawable/abc_ic_clear_material"
tools:title="@string/color_filter">
<Button
android:id="@+id/button_done"
style="@style/Widget.Material3.Button.UnelevatedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginHorizontal="@dimen/toolbar_button_margin"
android:text="@string/done" />
</com.google.android.material.appbar.MaterialToolbar>
<ScrollView
android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:overScrollMode="ifContentScrolls">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="@dimen/margin_normal">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/imageView_before"
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleType="centerCrop"
app:layout_constraintDimensionRatio="W,14:9"
app:layout_constraintEnd_toStartOf="@id/imageView_arrow"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:shapeAppearance="?shapeAppearanceCornerLarge"
app:strokeColor="?colorOutline"
app:strokeWidth="1dp"
tools:src="@sample/covers" />
<ImageView
android:id="@+id/imageView_arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/margin_normal"
android:src="@drawable/ic_arrow_forward"
app:layout_constraintBottom_toBottomOf="@id/imageView_before"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/imageView_before" />
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/imageView_after"
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleType="centerCrop"
app:layout_constraintDimensionRatio="W,14:9"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/imageView_arrow"
app:layout_constraintTop_toTopOf="parent"
app:shapeAppearance="?shapeAppearanceCornerLarge"
app:strokeColor="?colorOutline"
app:strokeWidth="1dp"
tools:src="@sample/covers" />
<com.google.android.material.slider.Slider
android:id="@+id/slider_saturation"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_normal"
android:value="255.0"
android:valueFrom="0.0"
android:valueTo="255.0"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/imageView_before" />
<com.google.android.material.slider.Slider
android:id="@+id/slider_lightness"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_normal"
android:value="0.0"
android:valueFrom="0.0"
android:valueTo="255.0"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/slider_saturation" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
</LinearLayout>

View File

@@ -1,14 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/textView"
android:padding="8dp"
android:textAppearance="@style/TextAppearance.AppCompat"
android:textSize="20sp"
app:drawableEndCompat="@drawable/ic_arrow_forward"
app:drawableTint="?attr/colorPrimary"
tools:text="History" />

View File

@@ -133,6 +133,17 @@
</LinearLayout>
<org.koitharu.kotatsu.base.ui.widgets.ListItemTextView
android:id="@+id/button_color_filter"
android:layout_width="match_parent"
android:layout_height="?android:listPreferredItemHeightSmall"
android:drawablePadding="?android:listPreferredItemPaddingStart"
android:paddingStart="?android:listPreferredItemPaddingStart"
android:paddingEnd="?android:listPreferredItemPaddingEnd"
android:text="@string/color_filter"
android:textAppearance="?attr/textAppearanceButton"
app:drawableStartCompat="@drawable/ic_appearance" />
<org.koitharu.kotatsu.base.ui.widgets.ListItemTextView
android:id="@+id/button_settings"
android:layout_width="match_parent"

View File

@@ -376,4 +376,5 @@
<string name="import_completed_hint">You can delete the original file from storage to save space</string>
<string name="import_will_start_soon">Import will start soon</string>
<string name="feed">Feed</string>
<string name="color_filter">Color filter</string>
</resources>