1
0
mirror of https://github.com/fumiama/copymanga.git synced 2026-06-04 23:10:23 +08:00
新增
1. 漫画详情页加载进度条
修复
1. 本地记录的章节数超过云端现有章节数时闪退(fix #97)
优化
1. 卡片流加载进度条增加动画
2. 下载页底部下载按钮上移规避导航栏(fix #96)
升级
1. net.java.dev.jna -> 5.15.0
This commit is contained in:
源文雨
2024-10-19 18:05:50 +09:00
parent 99a225dc51
commit 09f2ef2e4a
12 changed files with 131 additions and 45 deletions

View File

@@ -11,8 +11,8 @@ android {
applicationId 'top.fumiama.copymanga'
minSdkVersion 23
targetSdkVersion 34
versionCode 63
versionName '2.3.5'
versionCode 64
versionName '2.3.6'
resourceConfigurations += ['zh', 'zh-rCN']
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@@ -95,5 +95,5 @@ dependencies {
//noinspection GradleDependency
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.7.0'
implementation 'com.airbnb.android:lottie:6.5.2'
implementation 'net.java.dev.jna:jna:5.14.0@aar'
implementation 'net.java.dev.jna:jna:5.15.0@aar'
}

View File

@@ -53,6 +53,7 @@ import kotlinx.coroutines.withContext
import top.fumiama.copymanga.manga.Shelf
import top.fumiama.copymanga.tools.ui.UITools
import top.fumiama.copymanga.ui.book.BookFragment.Companion.bookHandler
import top.fumiama.copymanga.ui.book.BookHandler
import top.fumiama.copymanga.ui.cardflow.rank.RankFragment
import top.fumiama.copymanga.ui.comicdl.ComicDlFragment
import top.fumiama.copymanga.ui.download.DownloadFragment
@@ -189,7 +190,7 @@ class MainActivity : AppCompatActivity() {
true
}
R.id.action_download -> {
bookHandler.get()?.sendEmptyMessage(6)
bookHandler.get()?.sendEmptyMessage(BookHandler.NAVIGATE_TO_DOWNLOAD)
true
}
R.id.action_sort -> {

View File

@@ -97,14 +97,16 @@ class Book(val path: String, private val getString: (Int) -> String, private val
/**
* 更新云端最新章节信息并缓存到本地
*/
suspend fun updateVolumes(whenFinish: suspend () -> Unit) = withContext(Dispatchers.IO) withIO@ {
suspend fun updateVolumes(setProgress: (Int) -> Unit, whenFinish: suspend () -> Unit) = withContext(Dispatchers.IO) withIO@ {
var isDownload = false
var volumes = if(loadCache && loadVolumes()) mVolumes else emptyArray<VolumeStructure>()
if(mGroupPathWords.isEmpty()) return@withIO
if(volumes.isEmpty()) {
isDownload = true
val delta = 100/mGroupPathWords.size
mGroupPathWords.forEachIndexed { i, g ->
Volume(path, g, getString) {
return@Volume exit
Volume(path, g, getString, { return@Volume exit }) { p ->
setProgress(i*delta+100*p/delta)
}.updateChapters(mCounts[i])?.let {
volumes += it
}
@@ -116,6 +118,7 @@ class Book(val path: String, private val getString: (Int) -> String, private val
mVolumes = volumes
}
goSaveHead(isDownload)
setProgress(100)
whenFinish()
}
}

View File

@@ -10,7 +10,7 @@ import top.fumiama.copymanga.template.http.PausableDownloader
import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.dmzj.copymanga.R
class Volume(private val path: String, private val groupPathWord: String, getString: (Int) -> String, private val isExit: ()->Boolean) {
class Volume(private val path: String, private val groupPathWord: String, getString: (Int) -> String, private val isExit: ()->Boolean, private val setProgress: ((Int) -> Unit)? = null) {
private val mGroupInfoApiUrlTemplate = getString(R.string.groupInfoApiUrl)
private val exit: Boolean
get() {
@@ -21,12 +21,20 @@ class Volume(private val path: String, private val groupPathWord: String, getStr
}
private var mDownloaders = arrayOf<PausableDownloader>()
private var mVolume: VolumeStructure? = null
private var mProgress = 0
set(value) {
setProgress?.let { it(field) }
field = value
}
private var mDelta = 0
suspend fun updateChapters(count: Int): VolumeStructure? = withContext(Dispatchers.IO) {
val times = count / 100
val remain = count % 100
val re = arrayOfNulls<VolumeStructure>(if(remain != 0) (times+1) else (times))
if (re.isEmpty()) return@withContext null
Log.d("MyV", "${groupPathWord}卷共需加载${if(times == 0) 1 else times}")
mProgress = 0
mDelta = 100/re.size
download(re, 0, count)
return@withContext mVolume
}
@@ -40,6 +48,7 @@ class Volume(private val path: String, private val groupPathWord: String, getStr
mDownloaders += ad
ad.run()
}
mProgress += mDelta
}
private fun whenFinish(re: Array<VolumeStructure?>, c: Int, offset: Int): suspend (ByteArray) -> Unit = lambda@ { result: ByteArray ->
try {

View File

@@ -1,5 +1,6 @@
package top.fumiama.copymanga.template.general
import android.animation.ObjectAnimator
import android.annotation.SuppressLint
import android.content.Context
import android.net.ConnectivityManager
@@ -8,6 +9,7 @@ import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.core.animation.doOnEnd
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
@@ -157,18 +159,31 @@ open class MangaPagesFragmentTemplate(inflateRes:Int, private val isLazy: Boolea
var newP = p
mypl?.post {
if (p == mypl?.progress) return@post
if (newP >= 100) {
Log.d("MyMPFT", "set 100, hide")
mypc?.visibility = View.GONE
return@post
}
if (newP >= 100) newP = 100
else if (newP < 0) newP = 0
if (mypl?.progress == 0) {
Log.d("MyMPFT", "set from 0, show")
mypc?.apply {
visibility = View.VISIBLE
invalidate()
ObjectAnimator.ofFloat(this, "alpha", 0f, 1f)
.setDuration(300)
.start()
}
}
if(newP == 100) {
Log.d("MyMPFT", "set to 100, hide")
mypc?.apply {
val oa = ObjectAnimator.ofFloat(this, "alpha", 1f, 0f).setDuration(300)
oa.doOnEnd { visibility = View.GONE }
oa.start()
}
}
mypl?.apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
setProgress(newP, true)
} else progress = newP
invalidate()
Log.d("MyMPFT", "set ${mypl?.progress}")
val oa = ObjectAnimator.ofInt(this, "progress", newP).setDuration(100)
oa.addUpdateListener { invalidate() }
oa.start()
Log.d("MyMPFT", "set $progress")
}
}
}

View File

@@ -49,7 +49,7 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT
book?.comic?.path_word, null, null,
isFinish = false, isNew = false
)
setProgress(20+80*i/size)
setProgress(20+80*(i+1)/size)
}
offset += size
}
@@ -71,7 +71,7 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT
book?.comic?.path_word, null, null,
book?.comic?.status==1
)
setProgress(20+80*i/size)
setProgress(20+80*(i+1)/size)
}
offset += size
}
@@ -94,7 +94,7 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT
book?.comic?.status==1,
book.comic?.browse?.chapter_uuid != book.comic?.last_chapter_id
)
setProgress(20+80*i/size)
setProgress(20+80*(i+1)/size)
}
offset += size
}
@@ -112,7 +112,7 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT
Log.d("MyICL", "load @ $i")
if(ad?.exit == true) return@PausableDownloader
cardList?.addCard(book?.name?:"null", null, book?.cover, book?.path_word, null, null, false)
setProgress(20+80*i/size)
setProgress(20+80*(i+1)/size)
}
offset += size
}

View File

@@ -1,11 +1,14 @@
package top.fumiama.copymanga.ui.book
import android.animation.ObjectAnimator
import android.annotation.SuppressLint
import android.content.Context.MODE_PRIVATE
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Toast
import androidx.core.animation.addListener
import androidx.core.animation.doOnEnd
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import kotlinx.android.synthetic.main.app_bar_main.*
@@ -42,6 +45,12 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
lifecycleScope.launch {
prepareHandler()
try {
fbloading?.apply {
post {
progress = 0
invalidate()
}
}
book?.updateInfo()
} catch (e: Exception) {
e.printStackTrace()
@@ -52,12 +61,25 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
}
Log.d("MyBF", "read path: ${book?.path}")
for (i in 1..3) {
mBookHandler?.sendEmptyMessageDelayed(i, (i*100).toLong())
mBookHandler?.sendEmptyMessage(i)
}
try {
book?.updateVolumes {
delay(300)
mBookHandler?.sendEmptyMessage(10)
fbc?.apply {
alpha = 0f
visibility = View.VISIBLE
invalidate()
ObjectAnimator.ofFloat(this, "alpha", 0f, 1f)
.setDuration(300)
.start()
}
book?.updateVolumes({ fbloading?.apply { post {
val oa = ObjectAnimator.ofInt(this, "progress", 20 + it*8/10)
.setDuration(128)
oa.addUpdateListener { invalidate() }
oa.start()
Log.d("MyBF", "set progress $it")
} } }) {
mBookHandler?.sendEmptyMessage(BookHandler.SET_VOLUMES)
}
} catch (e: Exception) {
e.printStackTrace()
@@ -95,14 +117,15 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
}
fun setStartRead() {
if(mBookHandler?.chapterNames?.isNotEmpty() == true) activity?.apply {
if(mBookHandler?.chapterNames?.isNotEmpty() != true) return
activity?.apply {
book?.name?.let { name ->
getPreferences(MODE_PRIVATE).getInt(name, -1).let { p ->
this@BookFragment.lbbstart.apply {
var i = 0
if(p >= 0) {
text = mBookHandler!!.chapterNames[p]
i = p
if(p >= 0) mBookHandler!!.chapterNames.let {
i = if (p >= it.size) it.size-1 else p
text = it[i]
}
setOnClickListener {
mBookHandler?.apply {

View File

@@ -1,5 +1,6 @@
package top.fumiama.copymanga.ui.book
import android.animation.ObjectAnimator
import android.graphics.drawable.Drawable
import android.os.Bundle
import android.os.Handler
@@ -10,6 +11,7 @@ import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.animation.doOnEnd
import androidx.core.widget.NestedScrollView
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
@@ -70,9 +72,10 @@ class BookHandler(private val th: WeakReference<BookFragment>): Handler(Looper.m
private fun endSetLayouts() {
if (exit) return
that?.fbloading?.apply {
pauseAnimation()
visibility = View.GONE
that?.fbc?.apply {
val oa = ObjectAnimator.ofFloat(this, "alpha", 1f, 0f).setDuration(300)
oa.doOnEnd { visibility = View.GONE }
oa.start()
}
complete = true
that?.setStartRead()
@@ -291,7 +294,7 @@ class BookHandler(private val th: WeakReference<BookFragment>): Handler(Looper.m
}
}
}
sendEmptyMessage(9) // end set layout
sendEmptyMessage(END_SET_LAYOUTS)
}
private fun loadVolume(name: String, path: String, nav: Int){
@@ -331,4 +334,10 @@ class BookHandler(private val th: WeakReference<BookFragment>): Handler(Looper.m
override fun getItemCount(): Int = that?.book?.keys?.size?:0
}
}
companion object {
const val NAVIGATE_TO_DOWNLOAD = 6
const val END_SET_LAYOUTS = 9
const val SET_VOLUMES = 10
}
}

View File

@@ -8,6 +8,7 @@ import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import com.google.gson.Gson
import kotlinx.android.synthetic.main.fragment_dlcomic.*
import kotlinx.android.synthetic.main.widget_downloadbar.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@@ -24,6 +25,7 @@ class ComicDlFragment: NoBackRefreshFragment(R.layout.fragment_dlcomic) {
super.onViewCreated(view, savedInstanceState)
exit = false
ldwn?.setPadding(0, 0, 0, navBarHeight)
dlsdwn?.translationY = -navBarHeight.toFloat()
if(isFirstInflate) lifecycleScope.launch {
withContext(Dispatchers.IO) {
when {

View File

@@ -199,8 +199,11 @@ class ComicDlHandler(looper: Looper, private val th: WeakReference<ComicDlFragme
dl?.setContentView(R.layout.dialog_unzipping)
that?.dlsdwn?.viewTreeObserver?.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener{
override fun onGlobalLayout() {
cdwnWidth = that!!.dlsdwn.width
Log.d("MyDl", "Get dlsdwn height: $cdwnWidth")
that!!.apply {
cdwnWidth = dlsdwn.width
Log.d("MyDl", "Get dlsdwn width: $cdwnWidth")
ldwn?.setPadding(0, 0, 0, dlsdwn.height+navBarHeight)
}
that!!.dlsdwn.viewTreeObserver.removeOnGlobalLayoutListener(this)
}
})

View File

@@ -44,12 +44,29 @@
app:layout_constraintTop_toBottomOf="@+id/fbiinf"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/fbloading"
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/fbc"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:alpha="0.5"
app:lottie_autoPlay="true"
app:lottie_loop="true"
app:lottie_rawRes="@raw/lottie_loading" />
android:alpha="0">
<androidx.cardview.widget.CardView
android:layout_width="@dimen/book_card_width"
android:layout_height="@dimen/icon_size_middle"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ProgressBar
android:id="@+id/fbloading"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="16dp" />
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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">
@@ -34,17 +35,20 @@
android:id="@+id/mypc"
android:layout_width="@dimen/book_card_width"
android:layout_height="@dimen/icon_size_middle"
android:alpha="0"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible">
<ProgressBar
android:id="@+id/mypl"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="16dp"
style="?android:attr/progressBarStyleHorizontal"/>
android:padding="16dp" />
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>