1
0
mirror of https://github.com/fumiama/copymanga.git synced 2026-06-05 23:40:24 +08:00
正式版发布!
新增
1. 漫画下载页退出多选模式
2. 我的下载反转排序
3. 分类页 日漫/韩漫/美漫/已完结 筛选标签
4. 排行页 男频/女频 筛选菜单
5. 已完结/更新 标签
6. Token 失效时自动退出登录
7. 我的订阅/漫画详情增加云端读到记录
8. 浏览历史增加最新话提示
9. 漫画详情支持取消订阅
修复
1. 下拉刷新无法回到最开头
2. 断网时无法进入下载
优化
1. 卡片翻页加载效率
This commit is contained in:
源文雨
2023-10-29 17:11:50 +09:00
parent 0c470ff912
commit 44c67838ad
33 changed files with 810 additions and 376 deletions

View File

@@ -8,8 +8,8 @@ android {
applicationId 'top.fumiama.copymanga'
minSdkVersion 23
targetSdkVersion 33
versionCode 35
versionName '2.0.beta23'
versionCode 36
versionName '2.0.0'
resConfigs 'zh', 'zh-rCN'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

View File

@@ -2,7 +2,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<application

View File

@@ -2,6 +2,7 @@ package top.fumiama.copymanga
import android.app.Activity
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import com.google.gson.Gson
import kotlinx.android.synthetic.main.activity_login.*
@@ -30,52 +31,26 @@ class LoginActivity:Activity() {
Toast.makeText(this, R.string.login_null_pwd, Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
Thread{
Thread {
if (isLogout) {
pref.edit()?.apply {
remove("token")
remove("user_id")
remove("username")
remove("nickname")
remove("avatar")
apply()
runOnUiThread {
MainActivity.mainWeakReference?.get()?.refreshUserInfo()
Toast.makeText(this@LoginActivity, R.string.login_restart_to_apply, Toast.LENGTH_SHORT).show()
finish()
}
MainActivity.member?.logout()
runOnUiThread {
MainActivity.mainWeakReference?.get()?.refreshUserInfo()
Toast.makeText(this@LoginActivity, R.string.login_restart_to_apply, Toast.LENGTH_SHORT).show()
finish()
}
return@Thread
}
try {
CMApi.getLoginConnection(username, pwd, salt)?.apply {
Gson().fromJson(inputStream.reader(), LoginInfoStructure::class.java)?.let { data ->
if(data.code == 200) {
pref.edit()?.apply {
putString("token", data.results?.token)
putString("user_id", data.results?.user_id)
putString("username", data.results?.username)
putString("nickname", data.results?.nickname)
apply()
DownloadTools.getHttpContent(getString(R.string.memberInfoApiUrl).format(CMApi.myHostApiUrl))?.decodeToString()?.let {
val l = Gson().fromJson(it, LoginInfoStructure::class.java)
if(l.code == 200) {
putString("avatar", l.results.avatar)
apply()
runOnUiThread {
MainActivity.mainWeakReference?.get()?.refreshUserInfo()
}
} else runOnUiThread { Toast.makeText(this@LoginActivity, l.message, Toast.LENGTH_SHORT).show() }
}
runOnUiThread { finish() }
}?:runOnUiThread { Toast.makeText(this@LoginActivity, R.string.login_get_conn_failed, Toast.LENGTH_SHORT).show() }
} else runOnUiThread { Toast.makeText(this@LoginActivity, data.message, Toast.LENGTH_SHORT).show() }
}
disconnect()
}?:runOnUiThread { Toast.makeText(this, R.string.login_get_conn_failed, Toast.LENGTH_SHORT).show() }
} catch (e: Exception) {
runOnUiThread { Toast.makeText(this, e.localizedMessage, Toast.LENGTH_SHORT).show() }
val l = MainActivity.member?.login(username, pwd, salt)
Log.d("MyLA", "login return code: ${l?.code}")
if (l?.code == 200) {
runOnUiThread {
MainActivity.mainWeakReference?.get()?.refreshUserInfo()
finish()
}
return@Thread
}
runOnUiThread { Toast.makeText(this@LoginActivity, l?.message, Toast.LENGTH_SHORT).show() }
}.start()
}
}

View File

@@ -45,9 +45,13 @@ import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.dmzj.copymanga.R
import top.fumiama.copymanga.tools.api.UITools
import top.fumiama.copymanga.ui.book.BookFragment.Companion.bookHandler
import top.fumiama.copymanga.ui.cardflow.rank.RankFragment
import top.fumiama.copymanga.ui.comicdl.ComicDlFragment
import top.fumiama.copymanga.ui.download.DownloadFragment
import top.fumiama.copymanga.ui.download.NewDownloadFragment
import top.fumiama.copymanga.update.Update
import top.fumiama.copymanga.user.Member
import top.fumiama.dmzj.copymanga.BuildConfig
import java.io.File
import java.io.FileInputStream
import java.lang.Thread.sleep
@@ -60,11 +64,16 @@ class MainActivity : AppCompatActivity() {
private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var headPic: File
private lateinit var toolsBox: UITools
private var latestDestination = 0
private var isMenuWaiting = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mainWeakReference = WeakReference(this)
toolsBox = UITools(this)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
@@ -108,10 +117,19 @@ class MainActivity : AppCompatActivity() {
ime = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
navController!!.addOnDestinationChangedListener { _, destination, _ ->
latestDestination = destination.id
Log.d("MyMA", "latestDestination: $latestDestination")
if (isMenuWaiting) {
return@addOnDestinationChangedListener
}
isMenuWaiting = true
Log.d("MyMA", "start menu waiting")
Thread {
sleep(1000)
isMenuWaiting = false
Log.d("MyMA", "finish menu waiting")
runOnUiThread {
when (destination.id) {
when (latestDestination) {
R.id.nav_home -> {
Log.d("MyMA", "enter home")
menuMain?.findItem(R.id.action_info)?.isVisible = true
@@ -130,6 +148,18 @@ class MainActivity : AppCompatActivity() {
menuMain?.findItem(R.id.action_download)?.isVisible = false
menuMain?.findItem(R.id.action_sort)?.isVisible = true
}
R.id.nav_new_download -> {
Log.d("MyMA", "enter new_download")
menuMain?.findItem(R.id.action_info)?.isVisible = false
menuMain?.findItem(R.id.action_download)?.isVisible = false
menuMain?.findItem(R.id.action_sort)?.isVisible = true
}
R.id.nav_rank -> {
Log.d("MyMA", "enter rank")
menuMain?.findItem(R.id.action_info)?.isVisible = false
menuMain?.findItem(R.id.action_download)?.isVisible = false
menuMain?.findItem(R.id.action_sort)?.isVisible = true
}
else -> {
Log.d("MyMA", "enter others")
menuMain?.findItem(R.id.action_info)?.isVisible = false
@@ -149,6 +179,7 @@ class MainActivity : AppCompatActivity() {
return true
}
@OptIn(ExperimentalStdlibApi::class)
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.action_info -> {
@@ -161,6 +192,8 @@ class MainActivity : AppCompatActivity() {
}
R.id.action_sort -> {
ComicDlFragment.handler?.sendEmptyMessage(13)
NewDownloadFragment.wn?.get()?.showReverseInfo(toolsBox)
RankFragment.wr?.get()?.showSexInfo(toolsBox)
true
}
else -> super.onOptionsItemSelected(item)
@@ -320,14 +353,14 @@ class MainActivity : AppCompatActivity() {
private fun checkUpdate(ignoreSkip: Boolean) {
Thread{
Update.checkUpdate(this, UITools(this), ignoreSkip)
Update.checkUpdate(this, toolsBox, ignoreSkip)
}.start()
}
private fun showAbout() {
val dl = android.app.AlertDialog.Builder(this)
dl.setMessage(R.string.app_description)
dl.setTitle(R.string.action_info)
dl.setTitle("${getString(R.string.action_info)} ${BuildConfig.VERSION_NAME}")
dl.setIcon(R.mipmap.ic_launcher)
dl.setPositiveButton(android.R.string.ok) { _, _ -> }
dl.setNeutralButton(R.string.check_update) {_, _ ->
@@ -368,9 +401,22 @@ class MainActivity : AppCompatActivity() {
if (field != null) return field
return mainWeakReference?.get()?.let {
field = Shelf(
it.getPreferences(Context.MODE_PRIVATE).getString("token", "")?:return@let null,
it.getString(R.string.shelfOperateApiUrl).format(CMApi.myHostApiUrl), it.getString(R.string.referer), it.getString(R.string.pc_ua)
)
it.getPreferences(Context.MODE_PRIVATE)
.getString("token", "")?:return@let null) { id ->
return@Shelf it.getString(id)
}
field
}
}
var member: Member? = null
get() {
if (field != null) return field
return mainWeakReference?.get()?.let {
it.getPreferences(MODE_PRIVATE)?.let { pref ->
field = Member(pref) { id ->
return@Member it.getString(id)
}
}
field
}
}

View File

@@ -0,0 +1,21 @@
package top.fumiama.copymanga.json;
public class BookQueryStructure extends ReturnBase {
public Results results;
public static class Results{
public Browse browse;
public int collect;
public boolean is_lock;
public boolean is_login;
public boolean is_mobile_bind;
public boolean is_vip;
public static class Browse {
public String comic_uuid;
public String comic_id;
public String path_word;
public String chapter_uuid;
public String chapter_id;
public String chapter_name;
}
}
}

View File

@@ -4,5 +4,6 @@ public class FilterStructure extends ReturnBase {
public Results results;
public static class Results{
public ThemeStructure[] theme;
public ThemeStructure[] top;
}
}

View File

@@ -13,4 +13,13 @@ public class HistoryComicStructure {
public String datetime_updated;
public String last_chapter_id;
public String last_chapter_name;
public Browse browse;
public static class Browse {
public String comic_uuid;
public String path_word;
public String chapter_uuid;
public String chapter_name;
}
}

View File

@@ -4,8 +4,11 @@ import android.content.Context
import android.content.Intent
import android.util.Log
import androidx.core.content.edit
import com.google.gson.Gson
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
import top.fumiama.copymanga.json.VolumeStructure
import top.fumiama.copymanga.ui.vm.ViewMangaActivity
import java.io.File
object Reader {
fun viewMangaAt(name: String, pos: Int, fromFirstPage: Boolean = false) {
@@ -35,4 +38,23 @@ object Reader {
}
}
}
}
fun getComicPathWordInFile(file: File): String {
if(!file.exists()) {
return "N/A:!file.exists()"
}
val jsonFile = File(file, "info.json")
if(!jsonFile.exists()) {
return "N/A:!jsonFile.exists()"
}
Gson().fromJson(jsonFile.readText(), Array<VolumeStructure>::class.java)?.let { volumes ->
if(volumes.isEmpty()) {
return "N/A:volumes.isEmpty()"
}
if(volumes[0].results.list.isEmpty()) {
return "N/A:volumes[0].results.list.isEmpty()"
}
return volumes[0].results.list[0].comic_path_word
}
return "N/A:null_gson"
}
}

View File

@@ -1,11 +1,17 @@
package top.fumiama.copymanga.manga
import android.content.SharedPreferences
import com.google.gson.Gson
import top.fumiama.copymanga.json.BookQueryStructure
import top.fumiama.copymanga.json.ReturnBase
import top.fumiama.copymanga.tools.http.DownloadTools
import top.fumiama.dmzj.copymanga.R
class Shelf(private val token: String, private val apiUrl: String, private val referer: String, private val ua: String) {
class Shelf(private val token: String, getString: (Int) -> String) {
private val hostUrl: String = getString(R.string.hostUrl)
private val apiUrl: String = getString(R.string.shelfOperateApiUrl).format(hostUrl)
private val queryApiUrl = getString(R.string.bookUserQueryApiUrl)
private val referer: String = getString(R.string.referer)
private val ua: String = getString(R.string.pc_ua)
fun add(comicId: String): String {
if (comicId.isEmpty()) {
return "空漫画ID"
@@ -41,4 +47,13 @@ class Shelf(private val token: String, private val apiUrl: String, private val r
)?.decodeToString() ?: return "空回应"
return Gson().fromJson(re, ReturnBase::class.java).message
}
fun query(pathWord: String): BookQueryStructure {
DownloadTools.getHttpContent(queryApiUrl.format(hostUrl, pathWord), referer, ua)?.let {
return Gson().fromJson(it.decodeToString(), BookQueryStructure::class.java)
}
val b = BookQueryStructure()
b.code = 400
return b
}
}

View File

@@ -1,16 +1,22 @@
package top.fumiama.copymanga.template.general
import android.annotation.SuppressLint
import android.content.Context
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Bundle
import android.util.JsonReader
import android.util.Log
import android.view.View
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import com.liaoinstan.springview.widget.SpringView
import kotlinx.android.synthetic.main.line_header.view.*
import kotlinx.android.synthetic.main.line_lazybooklines.*
import top.fumiama.copymanga.MainActivity
import top.fumiama.copymanga.template.ui.CardList
import top.fumiama.copymanga.template.handler.MPATHandler
import top.fumiama.copymanga.tools.api.UITools
import top.fumiama.dmzj.copymanga.R
import java.lang.Thread.sleep
import java.lang.ref.WeakReference
@@ -19,23 +25,51 @@ open class MangaPagesFragmentTemplate(inflateRes:Int, val isLazy: Boolean = true
var cardWidth = 0
var cardHeight = 0
var cardList: CardList? = null
var mh: MPATHandler? = null
var row: View? = null
//var row: View? = null
var isEnd = false
var jsonReaderNow: JsonReader? = null
//var jsonReaderNow: JsonReader? = null
var page = 0
var isRefresh = false
private val transportStringNull = context?.getString(R.string.TRANSPORT_NULL) ?: "TRANSPORT_NULL"
private val transportStringError = context?.getString(R.string.TRANSPORT_ERROR) ?: "TRANSPORT_ERROR"
private val netInfo: String
get() {
val cm: ConnectivityManager =
context?.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
return cm.getNetworkCapabilities(cm.activeNetwork)?.let {
when {
it.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> return@let context?.getString(
R.string.TRANSPORT_WIFI)
it.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> return@let context?.getString(
R.string.TRANSPORT_CELLULAR)
it.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) -> return@let context?.getString(
R.string.TRANSPORT_BLUETOOTH)
it.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> return@let context?.getString(
R.string.TRANSPORT_ETHERNET)
it.hasTransport(NetworkCapabilities.TRANSPORT_LOWPAN) -> return@let context?.getString(
R.string.TRANSPORT_LOWPAN)
it.hasTransport(NetworkCapabilities.TRANSPORT_VPN) -> return@let "VPN"
else -> return@let transportStringNull
}
} ?: transportStringError
}
@SuppressLint("ClickableViewAccessibility")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if(isFirstInflate) {
mh = MPATHandler(WeakReference(this))
if (!forceLoad && (netInfo == transportStringNull || netInfo == transportStringError)) {
findNavController().popBackStack()
return
}
Thread {
sleep(600)
mh?.sendEmptyMessage(0)
MainActivity.mainWeakReference?.get()?.runOnUiThread {
setLayouts()
}
}.start()
}
}
@@ -43,12 +77,11 @@ open class MangaPagesFragmentTemplate(inflateRes:Int, val isLazy: Boolean = true
override fun onDestroy() {
super.onDestroy()
cardList?.exitCardList = true
mh = null
row = null
jsonReaderNow = null
//row = null
//jsonReaderNow = null
}
fun setLayouts() {
open fun setLayouts() {
val toolsBox = this.context?.let { UITools(it) }
val widthData = toolsBox?.calcWidthFromDp(8, 135)
cardPerRow = widthData?.get(0) ?: 3
@@ -59,17 +92,47 @@ open class MangaPagesFragmentTemplate(inflateRes:Int, val isLazy: Boolean = true
Log.d("MyMPAT", "Card per row: $cardPerRow")
Log.d("MyMPAT", "Card width: $cardWidth")
pageHandler?.initCardList(WeakReference(this))
Thread { mh?.sendEmptyMessage(1) }.start()
pageHandler?.setListeners()
initCardList(WeakReference(this))
managePage()
setListeners()
//mypl.visibility = View.GONE
}
var pageHandler: PageHandler? = null
interface PageHandler {
fun addPage()
fun initCardList(weakReference: WeakReference<Fragment>)
fun setListeners()
private fun managePage() {
addPage()
if (isLazy) mysp.setListener(object : SpringView.OnFreshListener {
override fun onLoadmore() {
addPage()
}
override fun onRefresh() {
reset()
Thread {
sleep(600)
MainActivity.mainWeakReference?.get()?.runOnUiThread {
addPage()
}
}.start()
}
})
}
open fun addPage() {}
open fun onLoadFinish() {
//myp?.visibility = View.GONE
mysp?.onFinishFreshAndLoad()
//mys?.fullScroll(ScrollView.FOCUS_UP)
}
open fun reset() {
mydll.removeAllViews()
isEnd = false
page = 0
cardList?.reset()
mypl?.visibility = View.VISIBLE
}
open fun initCardList(weakReference: WeakReference<Fragment>) {}
open fun setListeners() {}
}

View File

@@ -1,83 +0,0 @@
package top.fumiama.copymanga.template.handler
import android.content.Context
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Handler
import android.os.Message
import android.view.View
import android.widget.Toast
import com.liaoinstan.springview.widget.SpringView
import top.fumiama.dmzj.copymanga.R
import kotlinx.android.synthetic.main.line_lazybooklines.*
import top.fumiama.copymanga.template.general.MangaPagesFragmentTemplate
import java.lang.ref.WeakReference
class MPATHandler(private val w: WeakReference<MangaPagesFragmentTemplate>) : Handler() {
private val wa get() = w.get()
private val netinfo: String
get() {
val cm: ConnectivityManager =
wa?.context?.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
return cm.getNetworkCapabilities(cm.activeNetwork)?.let {
when {
it.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> return@let wa?.context?.getString(
R.string.TRANSPORT_WIFI)
it.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> return@let wa?.context?.getString(
R.string.TRANSPORT_CELLULAR)
it.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) -> return@let wa?.context?.getString(
R.string.TRANSPORT_BLUETOOTH)
it.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> return@let wa?.context?.getString(
R.string.TRANSPORT_ETHERNET)
it.hasTransport(NetworkCapabilities.TRANSPORT_LOWPAN) -> return@let wa?.context?.getString(
R.string.TRANSPORT_LOWPAN)
it.hasTransport(NetworkCapabilities.TRANSPORT_VPN) -> return@let "VPN"
else -> return@let wa?.context?.getString(R.string.TRANSPORT_NULL)
}
} ?: "错误"
}
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
if (wa?.forceLoad == true || netinfo != "无网络" && netinfo != "错误") {
when (msg.what) {
0 -> wa?.setLayouts()
1 -> managePage()
2 -> addPageHandler()
3 -> {
wa?.pageHandler?.addPage()
//wa?.myp?.visibility = View.GONE
wa?.mysp?.onFinishFreshAndLoad()
//wa?.mys?.fullScroll(ScrollView.FOCUS_UP)
}
4 ->{
wa?.mydll?.removeAllViews()
wa?.isEnd = false
wa?.jsonReaderNow = null
wa?.page = 0
wa?.cardList?.reset()
addPageHandler()
wa?.mysp?.onFinishFreshAndLoad()
wa?.mypl?.visibility = View.VISIBLE
}
}
} else Toast.makeText(wa?.context, "${netinfo}链接!", Toast.LENGTH_SHORT).show()
}
private fun managePage() {
addPageHandler()
if (wa?.isLazy == true) wa?.mysp?.setListener(object :SpringView.OnFreshListener{
override fun onLoadmore() {
Thread { this@MPATHandler.sendEmptyMessage(2) }.start()
}
override fun onRefresh() {
Thread { this@MPATHandler.sendEmptyMessage(4) }.start()
}
})
}
private fun addPageHandler() {
//wa?.myp?.visibility = View.VISIBLE
Thread { this.sendEmptyMessage(3) }.start()
}
}

View File

@@ -11,12 +11,14 @@ import top.fumiama.copymanga.json.ReturnBase
import top.fumiama.copymanga.tools.http.DownloadTools
import top.fumiama.copymanga.tools.thread.TimeThread
import java.io.File
import java.lang.Thread.sleep
import java.security.MessageDigest
open class AutoDownloadHandler(private val url: String, private val jsonClass: Class<*>, looper: Looper, private val callCheckMsg: Int = -1, private val loadFromCache: Boolean = false, private val customCacheFile: File? = null): Handler(looper) {
var exit = false
private var timeThread: TimeThread? = null
private var checkTimes = 0
private var cnt = 0
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
when(msg.what){
@@ -72,6 +74,8 @@ open class AutoDownloadHandler(private val url: String, private val jsonClass: C
DownloadTools.getHttpContent(url, null, mainWeakReference?.get()?.getString(R.string.pc_ua)!!).let {
if(exit) return
if(it == null) {
if (cnt++>3) return
sleep(1000)
dlThread()
return
}

View File

@@ -70,7 +70,7 @@ class CardList(
}
@ExperimentalStdlibApi
fun addCard(name: String, append: String? = null, head: String? = null, path: String? = null, chapterUUID: String? = null, pn: Int? = null, isFinish: Boolean = false){
fun addCard(name: String, append: String? = null, head: String? = null, path: String? = null, chapterUUID: String? = null, pn: Int? = null, isFinish: Boolean = false, isNew: Boolean = false){
if(exitCardList) return
manageRow()
that?.layoutInflater?.inflate(R.layout.card_book, that.mydll.ltbtn, false)?.let {
@@ -83,6 +83,7 @@ class CardList(
card.chapterUUID = chapterUUID
card.pageNumber = pn
card.isFinish = isFinish
card.isNew = isNew
mainWeakReference?.get()?.runOnUiThread{
if(exitCardList) return@runOnUiThread
addCard(it)
@@ -115,6 +116,7 @@ class CardList(
if(img.exists()) it.imic.setImageURI(Uri.fromFile(img))
}
if(card.isFinish) it.sgnic.visibility = View.VISIBLE
if(card.isNew) it.sgnnew.visibility = View.VISIBLE
initClickListeners?.prepareListeners(card, card.name, card.path, card.chapterUUID, card.pageNumber)
rows[card.index % 20]?.ltbtn?.addView(it)
it.layoutParams?.height = cardHeight

View File

@@ -22,92 +22,103 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT
var offset = 0
private val subUrl get() = getApiUrl()
var ad: AutoDownloadThread? = null
init {
pageHandler = object : PageHandler {
override fun addPage(){
ad = AutoDownloadThread(subUrl){
if(isRefresh){
page = 0
isRefresh = false
}
if(isTypeBook) {
val bookList = Gson().fromJson(it?.decodeToString(), TypeBookListStructure::class.java)
bookList?.apply {
Log.d("MyICL", "offset:${results.offset}, total:${results.total}")
if(results.offset < results.total) {
if(code == 200) {
results.list.forEach { book ->
if(ad?.exit == true) return@AutoDownloadThread
cardList?.addCard(book.comic.name, null, book.comic.cover, book.comic.path_word, null, null, false)
}
offset += results.list.size
}
}
page++
}
} else if(isHistoryBook) {
val bookList = Gson().fromJson(it?.decodeToString(), HistoryBookListStructure::class.java)
bookList?.apply {
Log.d("MyICL", "offset:${results.offset}, total:${results.total}")
if(results.offset < results.total) {
if(code == 200) {
results.list.forEach{ book ->
if(ad?.exit == true) return@AutoDownloadThread
cardList?.addCard(book.comic.name, null, book.comic.cover, book.comic.path_word, null, null, false)
}
offset += results.list.size
}
}
page++
}
} else if (isShelfBook) {
val bookList = Gson().fromJson(it?.decodeToString(), ShelfStructure::class.java)
bookList?.apply {
Log.d("MyICL", "offset:${results.offset}, total:${results.total}")
if(results.offset < results.total) {
if(code == 200) {
results.list.forEach{ book ->
if(ad?.exit == true) return@AutoDownloadThread
cardList?.addCard(book.comic.name, null, book.comic.cover, book.comic.path_word, null, null, false)
}
offset += results.list.size
}
}
page++
}
} else {
val bookList = Gson().fromJson(it?.decodeToString(), BookListStructure::class.java)
bookList?.apply {
Log.d("MyICL", "offset:${results.offset}, total:${results.total}")
if(results.offset < results.total) {
if(code == 200) {
results.list.forEach{ book ->
if(ad?.exit == true) return@AutoDownloadThread
cardList?.addCard(book.name, null, book.cover, book.path_word, null, null, false)
}
offset += results.list.size
}
}
page++
}
}
onLoadFinish()
}
ad?.start()
override fun addPage(){
super.addPage()
ad = AutoDownloadThread(subUrl) {
if(isRefresh){
page = 0
isRefresh = false
}
override fun initCardList(weakReference: WeakReference<Fragment>) {
cardList = CardList(weakReference, cardWidth, cardHeight, cardPerRow)
cardList?.initClickListeners = object : CardList.InitClickListeners {
override fun prepareListeners(v: View, name: String, path: String?, chapterUUID: String?, pn: Int?) {
v.setOnClickListener {
val bundle = Bundle()
bundle.putString("path", path)
Navigate.safeNavigateTo(findNavController(), navId, bundle)
if(isTypeBook) {
val bookList = Gson().fromJson(it?.decodeToString(), TypeBookListStructure::class.java)
bookList?.apply {
Log.d("MyICL", "offset:${results.offset}, total:${results.total}")
if(results.offset < results.total) {
if(code == 200) {
results.list.forEach { book ->
if(ad?.exit == true) return@AutoDownloadThread
cardList?.addCard(
book?.comic?.name?:"null", null, book?.comic?.cover,
book?.comic?.path_word, null, null,
isFinish = false, isNew = false
)
}
offset += results.list.size
}
}
page++
}
} else if(isHistoryBook) {
val bookList = Gson().fromJson(it?.decodeToString(), HistoryBookListStructure::class.java)
bookList?.apply {
Log.d("MyICL", "offset:${results?.offset}, total:${results?.total}")
if(results.offset < results.total) {
if(code == 200) {
results?.list?.forEach{ book ->
if(ad?.exit == true) return@AutoDownloadThread
cardList?.addCard(
book?.comic?.name?:"null", "\n最新${book?.last_chapter_name}", book?.comic?.cover,
book?.comic?.path_word, null, null,
book?.comic?.status==1
)
}
offset += results.list.size
}
}
page++
}
} else if (isShelfBook) {
val bookList = Gson().fromJson(it?.decodeToString(), ShelfStructure::class.java)
bookList?.apply {
Log.d("MyICL", "offset:${results?.offset}, total:${results?.total}")
if(results.offset < results.total) {
if(code == 200) {
results?.list?.forEach{ book ->
if(ad?.exit == true) return@AutoDownloadThread
cardList?.addCard(
book?.comic?.name?:"null", "\n读到${book?.last_browse?.last_browse_name}", book?.comic?.cover,
book?.comic?.path_word, null, null,
book?.comic?.status==1,
book.comic?.browse?.chapter_uuid != book.comic?.last_chapter_id
)
}
offset += results.list.size
}
}
page++
}
} else {
val bookList = Gson().fromJson(it?.decodeToString(), BookListStructure::class.java)
bookList?.apply {
Log.d("MyICL", "offset:${results?.offset}, total:${results?.total}")
if(results.offset < results.total) {
if(code == 200) {
results?.list?.forEach{ book ->
if(ad?.exit == true) return@AutoDownloadThread
cardList?.addCard(book?.name?:"null", null, book?.cover, book?.path_word, null, null, false)
}
offset += results.list.size
}
}
page++
}
}
onLoadFinish()
}
ad?.start()
}
override fun initCardList(weakReference: WeakReference<Fragment>) {
super.initCardList(weakReference)
cardList = CardList(weakReference, cardWidth, cardHeight, cardPerRow)
cardList?.initClickListeners = object : CardList.InitClickListeners {
override fun prepareListeners(v: View, name: String, path: String?, chapterUUID: String?, pn: Int?) {
v.setOnClickListener {
val bundle = Bundle()
bundle.putString("path", path)
Navigate.safeNavigateTo(findNavController(), navId, bundle)
}
}
override fun setListeners() { this@InfoCardLoader.setListeners() }
}
}
@@ -115,14 +126,18 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT
return ""
}
open fun setListeners(){}
open fun onLoadFinish(){
override fun onLoadFinish() {
super.onLoadFinish()
MainActivity.mainWeakReference?.get()?.runOnUiThread {
if(ad?.exit != true) mypl.visibility = View.GONE
}
}
override fun reset() {
super.reset()
offset = 0
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
ad?.exit = false

View File

@@ -4,7 +4,6 @@ import android.animation.ObjectAnimator
import android.view.View
import kotlinx.android.synthetic.main.anchor_popular.view.*
import kotlinx.android.synthetic.main.line_finish.*
import kotlinx.android.synthetic.main.line_lazybooklines.*
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.dmzj.copymanga.R
@@ -40,7 +39,10 @@ open class StatusCardFlow(private val api: Int, nav: Int) : InfoCardLoader(R.lay
}
Thread{
Thread.sleep(400)
mh?.sendEmptyMessage(4)
mainWeakReference?.get()?.runOnUiThread {
reset()
addPage()
}
}.start()
}
}
@@ -59,7 +61,10 @@ open class StatusCardFlow(private val api: Int, nav: Int) : InfoCardLoader(R.lay
}
Thread {
Thread.sleep(400)
mh?.sendEmptyMessage(4)
mainWeakReference?.get()?.runOnUiThread {
reset()
addPage()
}
}.start()
}
}

View File

@@ -11,4 +11,12 @@ object FileUtils {
}
f.delete()
}
fun sizeOf(f: File): Long{
var size = 0L
if (f.isDirectory) f.listFiles()?.apply {
for (i in this)
size += if (i.isDirectory) sizeOf(i) else i.length()
}
return size
}
}

View File

@@ -1,5 +1,6 @@
package top.fumiama.copymanga.ui.book
import android.annotation.SuppressLint
import android.content.Context.MODE_PRIVATE
import android.os.Bundle
import android.util.Log
@@ -7,6 +8,7 @@ import android.view.View
import android.widget.Toast
import androidx.navigation.fragment.findNavController
import com.google.gson.Gson
import kotlinx.android.synthetic.main.line_bookinfo_text.*
import kotlinx.android.synthetic.main.line_booktandb.*
import top.fumiama.copymanga.MainActivity
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
@@ -100,18 +102,49 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
}
}
@SuppressLint("SetTextI18n")
fun setAddToShelf() {
if(bookHandler?.chapterNames?.isNotEmpty() == true)
if(bookHandler?.chapterNames?.isNotEmpty() == true) {
val b = MainActivity.shelf?.query(bookHandler?.path!!)
bookHandler?.collect = b?.results?.collect?:-2
Log.d("MyBF", "get collect of ${bookHandler?.path} = ${bookHandler?.collect}")
b?.results?.browse?.chapter_name?.let { name ->
btsub.text = "${btsub.text} ${getString(R.string.text_format_cloud_read_to).format(name)}"
}
bookHandler?.collect?.let { collect ->
if (collect > 0) {
this@BookFragment.lbbsub.setText(R.string.button_sub_subscribed)
}
}
bookHandler?.book?.results?.comic?.let { comic ->
this@BookFragment.lbbsub.setOnClickListener {
if (this@BookFragment.lbbsub.text != getString(R.string.button_sub)) {
bookHandler?.collect?.let { collect ->
if (collect < 0) return@setOnClickListener
Thread{
val re = MainActivity.shelf?.del(collect)
mainWeakReference?.get()?.runOnUiThread {
Toast.makeText(context, re, Toast.LENGTH_SHORT).show()
if (re == "请求成功") {
this@BookFragment.lbbsub.setText(R.string.button_sub)
}
}
}.start()
}
return@setOnClickListener
}
Thread{
val re = MainActivity.shelf?.add(comic.uuid)
mainWeakReference?.get()?.runOnUiThread {
Toast.makeText(context, re, Toast.LENGTH_SHORT).show()
if (re == "修改成功") {
this@BookFragment.lbbsub.setText(R.string.button_sub_subscribed)
}
}
}.start()
}
}
}
}
fun navigate2dl(){

View File

@@ -43,7 +43,7 @@ import java.io.File
import java.lang.Thread.sleep
import java.lang.ref.WeakReference
class BookHandler(private val th: WeakReference<BookFragment>, private val path: String)
class BookHandler(private val th: WeakReference<BookFragment>, val path: String)
: AutoDownloadHandler(th.get()?.getString(R.string.bookInfoApiUrl)?.format(CMApi.myHostApiUrl, path)?: "",
BookInfoStructure::class.java,
Looper.myLooper()!!){
@@ -62,6 +62,7 @@ class BookHandler(private val th: WeakReference<BookFragment>, private val path:
var cnts = intArrayOf()
var vols: Array<VolumeStructure>? = null
var chapterNames = arrayOf<String>()
var collect: Int = -1
private val divider get() = that?.layoutInflater?.inflate(R.layout.div_h, that?.fbl, false)
override fun handleMessage(msg: Message) {
@@ -133,8 +134,8 @@ class BookHandler(private val th: WeakReference<BookFragment>, private val path:
fbl.addView(fbibinfo)
} catch (e: Exception) {
e.printStackTrace()
(fbibinfo!!.parent as LinearLayout).removeAllViews()
fbl.addView(fbibinfo)
(fbibinfo?.parent as LinearLayout?)?.removeAllViews()
fbl?.addView(fbibinfo)
}
book?.results?.comic?.cover?.let { cover ->
val load = Glide.with(this).load(
@@ -145,8 +146,8 @@ class BookHandler(private val th: WeakReference<BookFragment>, private val path:
?.let { it2 -> RequestOptions.bitmapTransform(it2) }
?.let { it3 -> load.apply(it3).into(lbibg) }
}
imf.visibility = View.GONE
fbl.addView(divider)
imf?.visibility = View.GONE
fbl?.addView(divider)
}
}

View File

@@ -1,23 +1,52 @@
package top.fumiama.copymanga.ui.cardflow.rank
import android.os.Bundle
import com.google.android.material.tabs.TabLayout
import kotlinx.android.synthetic.main.fragment_rank.*
import kotlinx.android.synthetic.main.line_rank.view.*
import top.fumiama.copymanga.MainActivity
import top.fumiama.copymanga.template.ui.InfoCardLoader
import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.copymanga.tools.api.UITools
import top.fumiama.copymanga.ui.download.NewDownloadFragment
import top.fumiama.dmzj.copymanga.R
import java.lang.Thread.sleep
import java.lang.ref.WeakReference
@ExperimentalStdlibApi
class RankFragment : InfoCardLoader(R.layout.fragment_rank, R.id.action_nav_rank_to_nav_book, true) {
private val sortWay = listOf("day", "week", "month", "total")
private var sortValue = 0
private val audienceWay = listOf("", "male", "female")
private var audience = 0 // 0 all 1 male 2 female
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
wr = WeakReference(this)
}
override fun onPause() {
super.onPause()
ad?.exit = true
}
override fun onResume() {
super.onResume()
ad?.exit = true
}
override fun onDestroy() {
super.onDestroy()
wr = null
ad?.exit = true
}
override fun getApiUrl() =
getString(R.string.rankApiUrl).format(
CMApi.myHostApiUrl,
page * 21,
sortWay[sortValue]
sortWay[sortValue],
audienceWay[audience]
)
override fun setListeners() {
@@ -37,7 +66,41 @@ class RankFragment : InfoCardLoader(R.layout.fragment_rank, R.id.action_nav_rank
sortValue = value
Thread{
sleep(400)
if(ad?.exit != true) mh?.sendEmptyMessage(4)
if(ad?.exit != true) MainActivity.mainWeakReference?.get()?.runOnUiThread {
reset()
addPage()
}
}.start()
}
fun showSexInfo(toolsBox: UITools) {
if (ad?.exit != false) return
toolsBox.buildInfo("切换类型", "选择一种想筛选的漫画类型",
"男频", "全部", "女频", {
audience = 1
reset()
Thread {
sleep(600)
addPage()
}.start()
}, {
audience = 0
reset()
Thread {
sleep(600)
addPage()
}.start()
}, {
audience = 2
reset()
Thread {
sleep(600)
addPage()
}.start()
})
}
companion object {
var wr: WeakReference<RankFragment>? = null
}
}

View File

@@ -3,6 +3,7 @@ package top.fumiama.copymanga.ui.cardflow.shelf
import android.animation.ObjectAnimator
import kotlinx.android.synthetic.main.anchor_popular.view.*
import kotlinx.android.synthetic.main.line_shelf.*
import top.fumiama.copymanga.MainActivity
import top.fumiama.copymanga.template.ui.InfoCardLoader
import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.dmzj.copymanga.R
@@ -47,7 +48,10 @@ class ShelfFragment : InfoCardLoader(R.layout.fragment_shelf, R.id.action_nav_su
}
Thread {
sleep(400)
mh?.sendEmptyMessage(4)
MainActivity.mainWeakReference?.get()?.runOnUiThread {
reset()
addPage()
}
}.start()
}
}
@@ -65,7 +69,10 @@ class ShelfFragment : InfoCardLoader(R.layout.fragment_shelf, R.id.action_nav_su
}
Thread {
sleep(400)
mh?.sendEmptyMessage(4)
MainActivity.mainWeakReference?.get()?.runOnUiThread {
reset()
addPage()
}
}.start()
}
}
@@ -83,7 +90,10 @@ class ShelfFragment : InfoCardLoader(R.layout.fragment_shelf, R.id.action_nav_su
}
Thread {
sleep(400)
mh?.sendEmptyMessage(4)
MainActivity.mainWeakReference?.get()?.runOnUiThread {
reset()
addPage()
}
}.start()
}
}

View File

@@ -15,8 +15,9 @@ import java.lang.Thread.sleep
@ExperimentalStdlibApi
class SortFragment : InfoCardLoader(R.layout.fragment_sort, R.id.action_nav_sort_to_nav_book) {
private val sortWay = listOf("-datetime_updated", "datetime_updated", "-popular", "popular")
private val sortWay = listOf("datetime_updated", "-datetime_updated", "-popular", "popular")
private var theme = -1
private var region = -1
private var sortValue = 0
private var filter: FilterStructure? = null
@@ -25,7 +26,8 @@ class SortFragment : InfoCardLoader(R.layout.fragment_sort, R.id.action_nav_sort
CMApi.myHostApiUrl,
page * 21,
sortWay[sortValue],
if(theme >= 0) (filter?.results?.theme?.get(theme)?.path_word ?: "") else ""
if(theme >= 0) (filter?.results?.theme?.get(theme)?.path_word ?: "") else "",
if(region >= 0) (filter?.results?.top?.get(region)?.path_word ?: "") else "",
)
override fun setListeners() {
@@ -57,12 +59,57 @@ class SortFragment : InfoCardLoader(R.layout.fragment_sort, R.id.action_nav_sort
}
Thread{
sleep(400)
mh?.sendEmptyMessage(4)
mainWeakReference?.get()?.runOnUiThread {
reset()
addPage()
}
}.start()
}
}
private fun setClasses(){
filter?.results?.top?.let { items ->
if(ad?.exit == true) return@let
line_sort_region.apt.text = "全部"
line_sort_region.setOnClickListener {
val popupMenu = popupMenu {
style = R.style.Widget_MPM_Menu_Dark_CustomBackground
section {
item {
label = "全部"
labelColor = it.apt.currentTextColor
callback = {
region = -1
it.apt.text = "全部"
Thread{
sleep(400)
mainWeakReference?.get()?.runOnUiThread {
reset()
addPage()
}
}.start()
}
}
for(i in items.indices) item {
label = items[i].name
labelColor = it.apt.currentTextColor
callback = { //optional
it.apt.text = label
region = i
Thread{
sleep(400)
mainWeakReference?.get()?.runOnUiThread {
reset()
addPage()
}
}.start()
}
}
}
}
this.context?.let { it1 -> popupMenu.show(it1, it) }
}
}
filter?.results?.theme?.let { items ->
if(ad?.exit == true) return@let
line_sort_class.apt.text = "全部"
@@ -78,7 +125,10 @@ class SortFragment : InfoCardLoader(R.layout.fragment_sort, R.id.action_nav_sort
it.apt.text = "全部"
Thread{
sleep(400)
mh?.sendEmptyMessage(4)
mainWeakReference?.get()?.runOnUiThread {
reset()
addPage()
}
}.start()
}
}
@@ -90,7 +140,10 @@ class SortFragment : InfoCardLoader(R.layout.fragment_sort, R.id.action_nav_sort
theme = i
Thread{
sleep(400)
mh?.sendEmptyMessage(4)
mainWeakReference?.get()?.runOnUiThread {
reset()
addPage()
}
}.start()
}
}
@@ -114,7 +167,10 @@ class SortFragment : InfoCardLoader(R.layout.fragment_sort, R.id.action_nav_sort
}
Thread {
sleep(400)
mh?.sendEmptyMessage(4)
mainWeakReference?.get()?.runOnUiThread {
reset()
addPage()
}
}.start()
}
}

View File

@@ -210,14 +210,12 @@ class ComicDlHandler(looper: Looper, private val th: WeakReference<ComicDlFragme
if (downloading || checkedChapter == 0) {
mangaDlTools.wait = !mangaDlTools.wait!!
} else {
if(!downloading) {
downloading = true
Thread {
sendEmptyMessage(9)
finishMap = arrayOfNulls(tbtnlist.size)
downloadChapterPages()
}.start()
} else mangaDlTools.wait = false
downloading = true
Thread {
sendEmptyMessage(9)
finishMap = arrayOfNulls(tbtnlist.size)
downloadChapterPages()
}.start()
}
}
}
@@ -252,6 +250,11 @@ class ComicDlHandler(looper: Looper, private val th: WeakReference<ComicDlFragme
}
private fun showMultiSelectInfo() {
if(multiSelect) {
toolsBox.buildInfo("退出多选模式?", "退出后只能对单个漫画进行长按删除",
"确定", null, "取消", { multiSelect = false })
return
}
toolsBox.buildInfo("进入多选模式?", "之后可以对已下载漫画进行批量删除/重新下载",
"确定", null, "取消", { multiSelect = true })
}

View File

@@ -1,5 +1,6 @@
package top.fumiama.copymanga.ui.download
import android.app.Activity
import android.app.AlertDialog
import android.os.Bundle
import android.util.Log
@@ -9,105 +10,135 @@ import androidx.navigation.fragment.findNavController
import com.google.gson.Gson
import kotlinx.android.synthetic.main.line_lazybooklines.*
import top.fumiama.copymanga.MainActivity
import top.fumiama.copymanga.manga.Reader
import top.fumiama.copymanga.template.general.MangaPagesFragmentTemplate
import top.fumiama.copymanga.template.ui.CardList
import top.fumiama.copymanga.tools.api.Navigate
import top.fumiama.copymanga.tools.api.UITools
import top.fumiama.copymanga.tools.file.FileUtils
import top.fumiama.copymanga.ui.comicdl.ComicDlFragment
import top.fumiama.dmzj.copymanga.R
import java.io.File
import java.lang.Thread.sleep
import java.lang.ref.WeakReference
@OptIn(ExperimentalStdlibApi::class)
class NewDownloadFragment: MangaPagesFragmentTemplate(R.layout.fragment_newdownload) {
class NewDownloadFragment: MangaPagesFragmentTemplate(R.layout.fragment_newdownload, forceLoad = true) {
private var sortedBookList: List<File>? = null
private val oldDlCardName = MainActivity.mainWeakReference?.get()?.getString(R.string.old_download_card_name)!!
private val extDir = MainActivity.mainWeakReference?.get()?.getExternalFilesDir("")
init {
pageHandler = object : PageHandler {
override fun addPage() {
if(!isEnd) {
if(sortedBookList == null) {
Log.d("MyNDF", "Sorting books...")
sortedBookList = extDir?.listFiles()?.sorted()
}
Log.d("MyNDF", "Start drawing cards")
cardList?.addCard(oldDlCardName, path = oldDlCardName)
sortedBookList?.let {
for(i in it.listIterator(page)) {
private var isReverse = false
private var isContentChanged = false
private var exit = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
wn = WeakReference(this)
}
override fun onPause() {
super.onPause()
exit = true
}
override fun onResume() {
super.onResume()
exit = false
}
override fun onDestroy() {
super.onDestroy()
wn = null
exit = true
}
override fun addPage() {
super.addPage()
if(!isEnd) {
if(sortedBookList == null || isContentChanged) {
Log.d("MyNDF", "Sorting books...")
sortedBookList = extDir?.listFiles()?.sortedBy {
return@sortedBy Reader.getComicPathWordInFile(it)
}
if (isReverse) {
Log.d("MyNDF", "reversed...")
sortedBookList = sortedBookList?.asReversed()
}
isContentChanged = false
}
Log.d("MyNDF", "Start drawing cards")
cardList?.addCard(oldDlCardName, path = oldDlCardName)
sortedBookList?.let {
for(i in it.listIterator(page)) {
if(cardList?.exitCardList != false) return
page++ // page is actually count
val chosenJson = File(i, "info.bin")
val newJson = File(i, "info.json")
val bookSize = (FileUtils.sizeOf(i)/1048576).toInt()
when {
chosenJson.exists() -> continue // unsupported old folder
newJson.exists() -> {
if(cardList?.exitCardList != false) return
page++ // page is actually count
val chosenJson = File(i, "info.bin")
val newJson = File(i, "info.json")
val bookSize = (sizeOf(i)/1048576).toInt()
when{
chosenJson.exists() -> continue // unsupported old folder
newJson.exists() -> {
if(cardList?.exitCardList != false) return
cardList?.addCard(i.name, " ${bookSize}MB")
}
}
}
if(page >= it.size) {
isEnd = true
cardList?.addCard(i.name, "\n${bookSize}MB")
}
}
}
onLoadFinish()
}
override fun initCardList(weakReference: WeakReference<Fragment>) {
cardList = CardList(weakReference, cardWidth, cardHeight, cardPerRow)
cardList?.initClickListeners = object : CardList.InitClickListeners {
override fun prepareListeners(v: View, name: String, path: String?, chapterUUID: String?, pn: Int?) {
v.setOnClickListener {
if(name==oldDlCardName && path == oldDlCardName) {
Navigate.safeNavigateTo(findNavController(), R.id.action_nav_new_download_to_nav_download)
return@setOnClickListener
}
callDownloadFragment(name)
}
v.setOnLongClickListener {
if (name == oldDlCardName && path == oldDlCardName) {
return@setOnLongClickListener false
}
val chosenFile = File(extDir, name)
AlertDialog.Builder(context)
.setIcon(R.drawable.ic_launcher_foreground)
.setTitle(R.string.new_download_card_option_hint)
.setItems(arrayOf("删除", "前往")) { d, p ->
d.cancel()
when (p) {
0 -> {
AlertDialog.Builder(context)
.setIcon(R.drawable.ic_launcher_foreground).setMessage("删除下载的此漫画吗?")
.setTitle("提示").setPositiveButton(android.R.string.ok) { _, _ ->
if (chosenFile.exists()) Thread {
FileUtils.recursiveRemove(chosenFile)
MainActivity.mainWeakReference?.get()?.runOnUiThread {
it.visibility = View.INVISIBLE
}
}.start()
}.setNegativeButton(android.R.string.cancel) { _, _ -> }
.show()
}
1 -> {
val bundle = Bundle()
bundle.putBoolean("loadJson", true)
bundle.putString("name", name)
Navigate.safeNavigateTo(findNavController(), R.id.action_nav_new_download_to_nav_book, bundle)
}
}
}
.show()
true
}
}
if(page >= it.size) {
isEnd = true
}
}
}
onLoadFinish()
}
override fun setListeners() {}
override fun initCardList(weakReference: WeakReference<Fragment>) {
super.initCardList(weakReference)
cardList = CardList(weakReference, cardWidth, cardHeight, cardPerRow)
cardList?.initClickListeners = object : CardList.InitClickListeners {
override fun prepareListeners(v: View, name: String, path: String?, chapterUUID: String?, pn: Int?) {
v.setOnClickListener {
if(name==oldDlCardName && path == oldDlCardName) {
Navigate.safeNavigateTo(findNavController(), R.id.action_nav_new_download_to_nav_download)
return@setOnClickListener
}
callDownloadFragment(name)
}
v.setOnLongClickListener {
if (name == oldDlCardName && path == oldDlCardName) {
return@setOnLongClickListener false
}
val chosenFile = File(extDir, name)
AlertDialog.Builder(context)
.setIcon(R.drawable.ic_launcher_foreground)
.setTitle(R.string.new_download_card_option_hint)
.setItems(arrayOf("删除", "前往")) { d, p ->
d.cancel()
when (p) {
0 -> {
AlertDialog.Builder(context)
.setIcon(R.drawable.ic_launcher_foreground).setMessage("删除下载的此漫画吗?")
.setTitle("提示").setPositiveButton(android.R.string.ok) { _, _ ->
if (chosenFile.exists()) Thread {
FileUtils.recursiveRemove(chosenFile)
MainActivity.mainWeakReference?.get()?.runOnUiThread {
it.visibility = View.INVISIBLE
}
}.start()
}.setNegativeButton(android.R.string.cancel) { _, _ -> }
.show()
}
1 -> {
val bundle = Bundle()
bundle.putBoolean("loadJson", true)
bundle.putString("name", name)
Navigate.safeNavigateTo(findNavController(), R.id.action_nav_new_download_to_nav_book, bundle)
}
}
}
.show()
true
}
}
}
}
@@ -122,21 +153,29 @@ class NewDownloadFragment: MangaPagesFragmentTemplate(R.layout.fragment_newdownl
Navigate.safeNavigateTo(findNavController(), R.id.action_nav_new_download_to_nav_group, bundle)
}
private fun onLoadFinish() {
fun showReverseInfo(toolsBox: UITools) {
if (exit) return
toolsBox.buildInfo("反转排序", "将按当前顺序的倒序显示下载的漫画",
"确定", null, "取消", {
isReverse = !isReverse
isContentChanged = true
reset()
Thread {
sleep(600)
addPage()
}.start()
}
)
}
override fun onLoadFinish() {
super.onLoadFinish()
MainActivity.mainWeakReference?.get()?.runOnUiThread {
if(cardList?.exitCardList != false) return@runOnUiThread
mypl.visibility = View.GONE
}
}
companion object {
fun sizeOf(f: File):Long{
var size = 0L
if (f.isDirectory) f.listFiles()?.apply {
for (i in this)
size += if (i.isDirectory) sizeOf(i) else i.length()
}
return size
}
var wn: WeakReference<NewDownloadFragment>? = null
}
}

View File

@@ -22,6 +22,7 @@ import kotlinx.android.synthetic.main.card_book_plain.view.*
import kotlinx.android.synthetic.main.fragment_home.*
import kotlinx.android.synthetic.main.line_word.view.*
import kotlinx.android.synthetic.main.viewpage_horizonal.view.*
import top.fumiama.copymanga.MainActivity
import top.fumiama.copymanga.MainActivity.Companion.ime
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
import top.fumiama.copymanga.json.BookListStructure
@@ -40,10 +41,11 @@ class HomeFragment : NoBackRefreshFragment(R.layout.fragment_home) {
super.onViewCreated(view, savedInstanceState)
if(isFirstInflate) {
val theme = resources.newTheme()
swiperefresh.setColorSchemeColors(
swiperefresh?.setColorSchemeColors(
resources.getColor(R.color.colorAccent, theme),
resources.getColor(R.color.colorBlue2, theme),
resources.getColor(R.color.colorGreen, theme))
swiperefresh?.isEnabled = true
fhs.apply {
val recyclerView = findViewById<RecyclerView>(R.id.search_recycler_view)
@@ -133,6 +135,10 @@ class HomeFragment : NoBackRefreshFragment(R.layout.fragment_home) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val l = MainActivity.member?.refreshAvatar()
if (l?.code != 200) {
MainActivity.member?.logout()
}
homeHandler = HomeHandler(WeakReference(this))
}

View File

@@ -50,15 +50,12 @@ class HomeHandler(private val that: WeakReference<HomeFragment>) : AutoDownloadH
}
return field
}
var indexLines = arrayOf<View>()
private var indexLines = arrayOf<View>()
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
when (msg.what) {
-1 -> {
homeF?.swiperefresh?.isEnabled = msg.obj as Boolean
homeF?.swiperefresh?.isRefreshing = msg.obj as Boolean
}
-1 -> homeF?.swiperefresh?.isRefreshing = msg.obj as Boolean
//0 -> setLayouts()
1 -> inflateCardLines()

View File

@@ -439,18 +439,18 @@ class ViewMangaActivity : TitleActivityTemplate() {
else {
val zip = ZipFile(zipFile)
try {
if (q == 100) BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.jpg")))
if (q == 100) BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.webp")))
else {
val out = ByteArrayOutputStream()
BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.jpg")))?.compress(Bitmap.CompressFormat.JPEG, q, out)
BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.webp")))?.compress(Bitmap.CompressFormat.JPEG, q, out)
BitmapFactory.decodeStream(ByteArrayInputStream(out.toByteArray()))
}
} catch (e: Exception) {
try {
if (q == 100) BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.webp")))
if (q == 100) BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.jpg")))
else {
val out = ByteArrayOutputStream()
BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.webp")))?.compress(Bitmap.CompressFormat.JPEG, q, out)
BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.jpg")))?.compress(Bitmap.CompressFormat.JPEG, q, out)
BitmapFactory.decodeStream(ByteArrayInputStream(out.toByteArray()))
}
} catch (e: Exception) {

View File

@@ -10,8 +10,8 @@ import android.widget.Toast
import androidx.core.content.FileProvider
import androidx.core.content.edit
import kotlinx.android.synthetic.main.dialog_progress.view.*
import top.fumiama.copymanga.tools.file.PropertiesTools
import top.fumiama.copymanga.tools.api.UITools
import top.fumiama.dmzj.copymanga.BuildConfig
import top.fumiama.dmzj.copymanga.R
import java.io.File
import java.security.MessageDigest
@@ -27,7 +27,7 @@ object Update {
}
}
val kanban = SimpleKanban(client, "fumiama")
val msg = kanban[packageManager.getPackageInfo(packageName, 0).versionCode]
val msg = kanban[BuildConfig.VERSION_CODE]
if(msg != "null") {
val verNum = msg.substringBefore('\n').toIntOrNull()
val skipNum = activity.getPreferences(MODE_PRIVATE).getInt("skipVersion", 0)

View File

@@ -0,0 +1,69 @@
package top.fumiama.copymanga.user
import android.content.SharedPreferences
import android.widget.Toast
import com.google.gson.Gson
import top.fumiama.copymanga.MainActivity
import top.fumiama.copymanga.json.LoginInfoStructure
import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.copymanga.tools.http.DownloadTools
import top.fumiama.dmzj.copymanga.R
class Member(private val pref: SharedPreferences, private val getString: (Int) -> String) {
fun login(username: String, pwd: String, salt: Int): LoginInfoStructure {
try {
CMApi.getLoginConnection(username, pwd, salt)?.apply {
Gson().fromJson(inputStream.reader(), LoginInfoStructure::class.java)?.let { data ->
disconnect()
if(data.code == 200) {
pref.edit()?.apply {
putString("token", data.results?.token)
putString("user_id", data.results?.user_id)
putString("username", data.results?.username)
putString("nickname", data.results?.nickname)
apply()
return refreshAvatar()
}
}
return data
}
}
val l = LoginInfoStructure()
l.code = 400
l.message = getString(R.string.login_get_conn_failed)
return l
} catch (e: Exception) {
val l = LoginInfoStructure()
l.code = 400
l.message = e.localizedMessage
return l
}
}
fun refreshAvatar() : LoginInfoStructure {
DownloadTools.getHttpContent(getString(R.string.memberInfoApiUrl).format(
CMApi.myHostApiUrl))?.decodeToString()?.let {
val l = Gson().fromJson(it, LoginInfoStructure::class.java)
if(l.code == 200) pref.edit()?.apply {
putString("avatar", l.results.avatar)
apply()
}
return l
}
val l = LoginInfoStructure()
l.code = 400
l.message = getString(R.string.login_get_avatar_failed)
return l
}
fun logout() {
pref.edit()?.apply {
remove("token")
remove("user_id")
remove("username")
remove("nickname")
remove("avatar")
apply()
}
}
}

View File

@@ -16,6 +16,7 @@ class MangaCardView:CardView {
//var uuid: String? = null
var path: String? = null
var isFinish = false
var isNew = false
var index = 0
var chapterUUID: String? = null
var pageNumber: Int? = null

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">
@@ -86,7 +87,21 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" />
<include
android:id="@+id/sgnnew"
layout="@layout/widget_newmark"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/sgnic"
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>
</top.fumiama.copymanga.views.MangaCardView>

View File

@@ -19,10 +19,20 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/line_sort_time"
app:layout_constraintEnd_toStartOf="@+id/line_sort_region"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<include
android:id="@+id/line_sort_region"
layout="@layout/anchor_popular"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/line_sort_time"
app:layout_constraintStart_toEndOf="@+id/line_sort_class"
app:layout_constraintTop_toTopOf="parent" />
<include
android:id="@+id/line_sort_time"
layout="@layout/anchor_popular"
@@ -30,7 +40,7 @@
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/line_sort_hot"
app:layout_constraintStart_toEndOf="@+id/line_sort_class"
app:layout_constraintStart_toEndOf="@+id/line_sort_region"
app:layout_constraintTop_toTopOf="parent" />
<include

View File

@@ -0,0 +1,24 @@
<?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"
android:alpha="0.9"
android:background="@drawable/rndbg_error">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="2dp"
android:layout_marginEnd="48dp"
android:layout_marginBottom="2dp"
android:text="更新"
android:textColor="#000000"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -42,11 +42,12 @@
<string name="mainPageApiUrl">https://%1$s/api/v3/h5/homeIndex?platform=3</string>
<string name="referUrl">https://%1$s</string>
<string name="hostUrl">&hosturl;</string>
<string name="rankApiUrl">https://%1$s/api/v3/ranks?limit=21&amp;offset=%2$d&amp;date_type=%3$s&amp;platform=3</string>
<string name="rankApiUrl">https://%1$s/api/v3/ranks?limit=21&amp;offset=%2$d&amp;date_type=%3$s&amp;audience_type=%4$s&amp;platform=3</string>
<string name="searchApiUrl">https://%1$s/api/v3/search/comic?limit=21&amp;offset=%2$d&amp;q=%3$s&amp;q_type=%4$s&amp;platform=3</string>
<string name="filterApiUrl">https://%1$s/api/v3/h5/filterIndex/comic/tags?platform=3</string>
<string name="sortApiUrl">https://%1$s/api/v3/comics?limit=21&amp;offset=%2$d&amp;ordering=%3$s&amp;theme=%4$s&amp;platform=3</string>
<string name="filterApiUrl">https://%1$s/api/v3/h5/filter/comic/tags?platform=3</string>
<string name="sortApiUrl">https://%1$s/api/v3/comics?limit=21&amp;offset=%2$d&amp;ordering=%3$s&amp;theme=%4$s&amp;top=%5$s&amp;platform=3</string>
<string name="bookInfoApiUrl">https://%1$s/api/v3/comic2/%2$s?platform=3</string>
<string name="bookUserQueryApiUrl">https://%1$s/api/v3/comic2/%2$s/query?platform=3</string>
<string name="groupInfoApiUrl">https://%1$s/api/v3/comic/%2$s/group/%3$s/chapters?limit=100&amp;offset=%4$d&amp;platform=3</string>
<string name="chapterInfoApiUrl">https://%1$s/api/v3/comic/%2$s/chapter2/%3$s?platform=3</string>
<string name="topicApiUrl">https://%1$s/api/v3/topic/%2$s?platform=3</string>
@@ -78,6 +79,7 @@
<string name="TRANSPORT_ETHERNET">以太网</string>
<string name="TRANSPORT_LOWPAN">LOWPAN</string>
<string name="TRANSPORT_NULL">无网络</string>
<string name="TRANSPORT_ERROR">网络错误</string>
<string name="pc_ua">COPY/2.0.7</string>
<string name="app_ver">2.0.7</string>
@@ -89,10 +91,12 @@
<string name="menu_read_time">阅读时间</string>
<string name="button_sub">加入书架</string>
<string name="button_sub_subscribed">已加书架</string>
<string name="button_start">开始阅读</string>
<string name="text_format_hit">热度 %1$d</string>
<string name="text_format_stat">状态 %1$s</string>
<string name="text_format_cloud_read_to">云端读到 %1$s</string>
<string name="topics_series">专题系列</string>
<string name="manga_rec">漫画推荐</string>
@@ -135,7 +139,8 @@
<string name="login_null_username">用户名为空</string>
<string name="login_null_pwd">密码为空</string>
<string name="login_get_conn_failed">连接失败</string>
<string name="login_get_conn_failed">登录失败</string>
<string name="login_get_avatar_failed">刷新头像失败</string>
<string name="login_restart_to_apply">重启应用以彻底退出登录</string>
<string name="old_download_card_name">前往旧版下载</string>