Merge branch 'devel' into feature/nextgen

This commit is contained in:
Koitharu
2022-07-07 12:07:11 +03:00
11 changed files with 447 additions and 352 deletions

View File

@@ -10,9 +10,9 @@ Kotatsu is a free and open source manga reader for Android.
alt="Get it on F-Droid"
height="80">](https://f-droid.org/packages/org.koitharu.kotatsu)
Download APK from GitHub Releases:
Download APK directly from GitHub:
- [Latest release](https://github.com/KotatsuApp/Kotatsu/releases/latest)
- **[Latest release](https://github.com/KotatsuApp/Kotatsu/releases/latest)**
### Main Features
@@ -24,8 +24,8 @@ Download APK from GitHub Releases:
* Tablet-optimized material design UI
* Standard and Webtoon-optimized reader
* Notifications about new chapters with updates feed
* Available in multiple languages
* Password protect access to the app
* Shikimori integration (manga tracking)
* Password/fingerprint protect access to the app
### Screenshots
@@ -38,23 +38,20 @@ Download APK from GitHub Releases:
### Localization
<a href="https://hosted.weblate.org/engage/kotatsu/">
<img src="https://hosted.weblate.org/widgets/kotatsu/-/287x66-white.png" alt="Translation status" />
</a>
[<img src="https://hosted.weblate.org/widgets/kotatsu/-/287x66-white.png" alt="Translation status">](https://hosted.weblate.org/engage/kotatsu/)
Kotatsu is localized in a number of different languages, if you would like to help improve these or add new languages,
please head over to the Weblate <a href="https://hosted.weblate.org/engage/kotatsu/">project page</a>
please head over to the [Weblate project page](https://hosted.weblate.org/engage/kotatsu/)
### License
[![GNU GPLv3 Image](https://www.gnu.org/graphics/gplv3-127x51.png)](http://www.gnu.org/licenses/gpl-3.0.en.html)
Kotatsu is Free Software: You can use, study share and improve it at your
will. Specifically you can redistribute and/or modify it under the terms of the
[GNU General Public License](https://www.gnu.org/licenses/gpl.html) as
published by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
You may copy, distribute and modify the software as long as you track changes/dates in source files. Any modifications
to or software including (via compiler) GPL-licensed code must also be made available under the GPL along with build &
install instructions.
### Disclaimer
### DMCA disclaimer
The developers of this application does not have any affiliation with the content providers available.
The developers of this application does not have any affiliation with the content available in the app.
It is collecting from the sources freely available through any web browser.

View File

@@ -14,8 +14,8 @@ android {
applicationId 'org.koitharu.kotatsu'
minSdkVersion 21
targetSdkVersion 32
versionCode 412
versionName '3.4'
versionCode 413
versionName '3.4.1'
generatedDensities = []
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@@ -77,7 +77,7 @@ afterEvaluate {
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
implementation('com.github.nv95:kotatsu-parsers:da3b0ae0cf') {
implementation('com.github.nv95:kotatsu-parsers:8c26f3c790') {
exclude group: 'org.json', module: 'json'
}

View File

@@ -0,0 +1,41 @@
package org.koitharu.kotatsu.reader.ui.pager.webtoon
import android.content.Context
import android.util.AttributeSet
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlin.math.sign
class WebtoonLayoutManager : LinearLayoutManager {
private var scrollDirection: Int = 0
constructor(context: Context) : super(context)
constructor(
context: Context,
orientation: Int,
reverseLayout: Boolean,
) : super(context, orientation, reverseLayout)
constructor(
context: Context,
attrs: AttributeSet?,
defStyleAttr: Int,
defStyleRes: Int,
) : super(context, attrs, defStyleAttr, defStyleRes)
override fun scrollVerticallyBy(dy: Int, recycler: RecyclerView.Recycler?, state: RecyclerView.State): Int {
scrollDirection = dy.sign
return super.scrollVerticallyBy(dy, recycler, state)
}
override fun calculateExtraLayoutSpace(state: RecyclerView.State, extraLayoutSpace: IntArray) {
if (state.hasTargetScrollPosition()) {
super.calculateExtraLayoutSpace(state, extraLayoutSpace)
return
}
val pageSize = height
extraLayoutSpace[0] = if (scrollDirection < 0) pageSize else 0
extraLayoutSpace[1] = if (scrollDirection < 0) 0 else pageSize
}
}

View File

@@ -12,7 +12,6 @@ import org.koitharu.kotatsu.reader.ui.ReaderState
import org.koitharu.kotatsu.reader.ui.pager.BaseReader
import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter
import org.koitharu.kotatsu.reader.ui.pager.ReaderPage
import org.koitharu.kotatsu.utils.ext.doOnCurrentItemChanged
import org.koitharu.kotatsu.utils.ext.findCenterViewPosition
import org.koitharu.kotatsu.utils.ext.firstVisibleItemPosition
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
@@ -33,7 +32,7 @@ class WebtoonReaderFragment : BaseReader<FragmentReaderWebtoonBinding>() {
with(binding.recyclerView) {
setHasFixedSize(true)
adapter = webtoonAdapter
doOnCurrentItemChanged(::notifyPageChanged)
addOnPageScrollListener(PageScrollListener())
}
}
@@ -93,4 +92,12 @@ class WebtoonReaderFragment : BaseReader<FragmentReaderWebtoonBinding>() {
override fun switchPageTo(position: Int, smooth: Boolean) {
binding.recyclerView.firstVisibleItemPosition = position
}
private inner class PageScrollListener : WebtoonRecyclerView.OnPageScrollListener() {
override fun onPageChanged(recyclerView: WebtoonRecyclerView, index: Int) {
super.onPageChanged(recyclerView, index)
notifyPageChanged(index)
}
}
}

View File

@@ -2,25 +2,27 @@ package org.koitharu.kotatsu.reader.ui.pager.webtoon
import android.content.Context
import android.util.AttributeSet
import androidx.core.view.ViewCompat
import androidx.core.view.ViewCompat.TYPE_TOUCH
import androidx.recyclerview.widget.RecyclerView
import org.koitharu.kotatsu.utils.ext.findCenterViewPosition
import java.util.*
class WebtoonRecyclerView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : RecyclerView(context, attrs, defStyleAttr) {
override fun startNestedScroll(axes: Int) = startNestedScroll(axes, ViewCompat.TYPE_TOUCH)
private var onPageScrollListeners: MutableList<OnPageScrollListener>? = null
override fun startNestedScroll(axes: Int, type: Int): Boolean {
return true
}
override fun startNestedScroll(axes: Int) = startNestedScroll(axes, TYPE_TOUCH)
override fun startNestedScroll(axes: Int, type: Int): Boolean = true
override fun dispatchNestedPreScroll(
dx: Int,
dy: Int,
consumed: IntArray?,
offsetInWindow: IntArray?
) = dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow, ViewCompat.TYPE_TOUCH)
) = dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow, TYPE_TOUCH)
override fun dispatchNestedPreScroll(
dx: Int,
@@ -34,6 +36,7 @@ class WebtoonRecyclerView @JvmOverloads constructor(
consumed[0] = 0
consumed[1] = consumedY
}
notifyScrollChanged(dy)
return consumedY != 0 || dy == 0
}
@@ -75,4 +78,39 @@ class WebtoonRecyclerView @JvmOverloads constructor(
}
return 0
}
fun addOnPageScrollListener(listener: OnPageScrollListener) {
val list = onPageScrollListeners ?: LinkedList<OnPageScrollListener>().also { onPageScrollListeners = it }
list.add(listener)
}
fun removeOnPageScrollListener(listener: OnPageScrollListener) {
onPageScrollListeners?.remove(listener)
}
private fun notifyScrollChanged(dy: Int) {
val listeners = onPageScrollListeners
if (listeners.isNullOrEmpty()) {
return
}
val centerPosition = findCenterViewPosition()
listeners.forEach { it.dispatchScroll(this, dy, centerPosition) }
}
abstract class OnPageScrollListener {
private var lastPosition = NO_POSITION
fun dispatchScroll(recyclerView: WebtoonRecyclerView, dy: Int, centerPosition: Int) {
onScroll(recyclerView, dy)
if (centerPosition != NO_POSITION && centerPosition != lastPosition) {
lastPosition = centerPosition
onPageChanged(recyclerView, centerPosition)
}
}
open fun onScroll(recyclerView: WebtoonRecyclerView, dy: Int) = Unit
open fun onPageChanged(recyclerView: WebtoonRecyclerView, index: Int) = Unit
}
}

View File

@@ -91,22 +91,6 @@ fun View.resetTransformations() {
rotationY = 0f
}
inline fun RecyclerView.doOnCurrentItemChanged(crossinline callback: (Int) -> Unit) {
addOnScrollListener(object : RecyclerView.OnScrollListener() {
private var lastItem = -1
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val item = recyclerView.findCenterViewPosition()
if (item != RecyclerView.NO_POSITION && item != lastItem) {
lastItem = item
callback(item)
}
}
})
}
fun RecyclerView.findCenterViewPosition(): Int {
val centerX = width / 2f
val centerY = height / 2f

View File

@@ -42,9 +42,8 @@
<LinearLayout
android:id="@+id/layout_titles"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="@id/imageView_cover"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/imageView_cover"
app:layout_constraintTop_toTopOf="parent"
@@ -151,6 +150,14 @@
</LinearLayout>
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier_header"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:barrierDirection="bottom"
app:barrierMargin="8dp"
app:constraint_referenced_ids="layout_titles,imageView_cover" />
<org.koitharu.kotatsu.base.ui.widgets.ChipsView
android:id="@+id/chips_tags"
android:layout_width="0dp"
@@ -162,7 +169,7 @@
app:chipSpacingVertical="6dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/layout_titles" />
app:layout_constraintTop_toBottomOf="@+id/barrier_header" />
<TextView
android:id="@+id/textView_bookmarks"
@@ -223,7 +230,7 @@
android:textIsSelectable="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/recyclerView_bookmarks"
app:layout_constraintTop_toBottomOf="@id/scrobbling_layout"
tools:ignore="UnusedAttribute"
tools:text="@tools:sample/lorem/random[250]" />

View File

@@ -6,4 +6,4 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
app:layoutManager="org.koitharu.kotatsu.reader.ui.pager.webtoon.WebtoonLayoutManager" />

View File

@@ -302,4 +302,19 @@
<string name="use_fingerprint">Использовать отпечаток пальца, если доступно</string>
<string name="appwidget_shelf_description">Манга из Вашего избранного</string>
<string name="appwidget_recent_description">Манга, которую Вы недавно читали</string>
<string name="status_reading">Читаю</string>
<string name="status_planned">Запланировано</string>
<string name="status_on_hold">Отложено</string>
<string name="status_dropped">Заброшено</string>
<string name="status_completed">Завершено</string>
<string name="show_reading_indicators_summary">Показать процент прочитанного в истории и избранном</string>
<string name="exclude_nsfw_from_history_summary">Манга, помеченная как NSFW, никогда не будет добавлена в историю и ваш прогресс чтения не будет сохранен</string>
<string name="percent_string_pattern">%1$s%%</string>
<string name="report">Отчёт</string>
<string name="logout">Выйти</string>
<string name="status_re_reading">Перечитываю</string>
<string name="show_reading_indicators">Показать индикаторы прогресса чтения</string>
<string name="data_deletion">Удаление данных</string>
<string name="clear_cookies_summary">Может помочь в случае каких-либо проблем. Все авторизации будут аннулированы</string>
<string name="show_all">Показать все</string>
</resources>

View File

@@ -1,4 +1,6 @@
Kotatsu is a free and open source manga reader for Android.<br>
Kotatsu is a free and open source manga reader for Android.
**Main Features:**
- Online manga catalogues
@@ -9,5 +11,5 @@ Kotatsu is a free and open source manga reader for Android.<br>
- Tablet-optimized material design UI
- Standard and Webtoon-optimized reader
- Notifications about new chapters with updates feed
- Available in multiple languages
- Password protect access to the app
- Shikimori integration (manga tracking)
- Password/fingerprint protect access to the app

View File

@@ -1,4 +1,6 @@
Kotatsu - приложения для чтения манги с открытым исходным кодом.<br>
Kotatsu - приложения для чтения манги с открытым исходным кодом.
**Основные возможности:**
- Онлайн каталоги с мангой
@@ -9,3 +11,5 @@ Kotatsu - приложения для чтения манги с открыты
- Интерфейс также оптимизирован для планшетов
- Поддержка манхвы (Webtoon)
- Уведомления о новых главах и лента обновлений
- Интеграция с Shikimori
- Защита доступа в приложение паролем/отпечатком пальца