1
0
mirror of https://github.com/fumiama/copymanga.git synced 2026-06-05 07:20:23 +08:00
新增
1. 详情页标记已下载章节
2. 详情页以tab区分卷标
3. 以深浅标示当前选择的tab
修复
1. 详情页加载结束时卡顿
2. 某些漫画无法变更清晰度
3. 全新上架显示错误
4. 专题系列有时简介不显示
优化
1. 替换弃用API
2. 携程化: 检查更新, 菜单切换, 详情页
3. StatusCardFlow标签排序
4. CardList加载速度
升级
1. 支持库版本
This commit is contained in:
源文雨
2024-03-09 00:28:00 +09:00
parent 89e47b243c
commit 7f5f183d32
45 changed files with 3173 additions and 484 deletions

23
.idea/deploymentTargetDropDown.xml generated Normal file
View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetDropDown">
<value>
<entry key="app">
<State>
<targetSelectedWithDropDown>
<Target>
<type value="QUICK_BOOT_TARGET" />
<deviceKey>
<Key>
<type value="VIRTUAL_DEVICE_PATH" />
<value value="$USER_HOME$/.android/avd/Pixel_3a_API_33_arm64-v8a.avd" />
</Key>
</deviceKey>
</Target>
</targetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2024-03-08T06:58:21.703472Z" />
</State>
</entry>
</value>
</component>
</project>

View File

@@ -4,6 +4,7 @@
<w>imgs</w> <w>imgs</w>
<w>lowpan</w> <w>lowpan</w>
<w>nisi</w> <w>nisi</w>
<w>reilia</w>
</words> </words>
</dictionary> </dictionary>
</component> </component>

4
.idea/gradle.xml generated
View File

@@ -4,10 +4,8 @@
<component name="GradleSettings"> <component name="GradleSettings">
<option name="linkedExternalProjectsSettings"> <option name="linkedExternalProjectsSettings">
<GradleProjectSettings> <GradleProjectSettings>
<option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="jbr-17" /> <option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
<option name="modules"> <option name="modules">
<set> <set>
<option value="$PROJECT_DIR$" /> <option value="$PROJECT_DIR$" />

10
.idea/migrations.xml generated Normal file
View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectMigrations">
<option name="MigrateToGradleLocalJavaHome">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</component>
</project>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,4 @@
<changelist name="Uncommitted_changes_before_Update_at_2024_3_9,_12_23_AM_[Changes]" date="1709911381682" recycled="true" deleted="true">
<option name="PATH" value="$PROJECT_DIR$/.idea/shelf/Uncommitted_changes_before_Update_at_2024_3_9,_12_23_AM_[Changes]/shelved.patch" />
<option name="DESCRIPTION" value="Uncommitted changes before Update at 2024/3/9, 12:23 AM [Changes]" />
</changelist>

View File

@@ -8,16 +8,13 @@ android {
applicationId 'top.fumiama.copymanga' applicationId 'top.fumiama.copymanga'
minSdkVersion 23 minSdkVersion 23
targetSdkVersion 34 targetSdkVersion 34
versionCode 45 versionCode 46
versionName '2.1.2' versionName '2.1.3'
resConfigs 'zh', 'zh-rCN' resourceConfigurations += ['zh', 'zh-rCN']
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }
aaptOptions {
cruncherEnabled = false
}
buildTypes { buildTypes {
release { release {
@@ -60,20 +57,20 @@ dependencies {
implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'com.google.android.material:material:1.11.0' implementation 'com.google.android.material:material:1.11.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.navigation:navigation-fragment-ktx:2.7.6' implementation 'androidx.navigation:navigation-fragment-ktx:2.7.7'
implementation 'androidx.navigation:navigation-ui-ktx:2.7.6' implementation 'androidx.navigation:navigation-ui-ktx:2.7.7'
testImplementation 'junit:junit:4.13.2' testImplementation 'junit:junit:4.13.2'
implementation "androidx.preference:preference-ktx:1.2.1" implementation "androidx.preference:preference-ktx:1.2.1"
implementation 'com.afollestad.material-dialogs:input:3.3.0' implementation 'com.afollestad.material-dialogs:input:3.3.0'
implementation 'com.github.yalantis:ucrop:2.2.6' implementation 'com.github.yalantis:ucrop:2.2.6'
implementation 'com.to.aboomy:pager2banner:1.0.1' implementation 'com.to.aboomy:pager2banner:1.0.1'
implementation 'com.github.bumptech.glide:glide:4.14.2' implementation 'com.github.bumptech.glide:glide:4.16.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.14.2' annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0'
implementation 'com.google.code.gson:gson:2.10.1' implementation 'com.google.code.gson:gson:2.10.1'
implementation 'com.github.vovaksenov99:OverscrollableScrollView:1.0' implementation 'com.github.vovaksenov99:OverscrollableScrollView:1.0'
implementation 'com.liaoinstan.springview:library:1.7.0' implementation 'com.liaoinstan.springview:library:1.7.0'
implementation 'com.github.zawadz88.materialpopupmenu:material-popup-menu:4.0.1' implementation 'com.github.zawadz88.materialpopupmenu:material-popup-menu:4.0.1'
implementation 'com.lapism:search:2.4.1@aar' implementation 'com.lapism:search:2.4.1@aar'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.7.0' implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.7.0'
implementation 'com.airbnb.android:lottie:6.3.0' implementation 'com.airbnb.android:lottie:6.4.0'
} }

View File

@@ -19,6 +19,7 @@ class LoginActivity : AppCompatActivity() {
val isLogout = pref.getString("token", null) != null val isLogout = pref.getString("token", null) != null
if (isLogout) { if (isLogout) {
alblogin.setText(R.string.logout) alblogin.setText(R.string.logout)
altusrnm.setText(pref.getString("username", "N/A"))
} }
alblogin.setOnClickListener { alblogin.setOnClickListener {
lifecycleScope.launch { lifecycleScope.launch {

View File

@@ -2,6 +2,7 @@ package top.fumiama.copymanga
import android.Manifest import android.Manifest
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
@@ -18,6 +19,7 @@ import android.view.View
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import android.widget.TextView import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
@@ -25,6 +27,7 @@ import androidx.core.content.ContextCompat
import androidx.core.content.edit import androidx.core.content.edit
import androidx.core.net.toUri import androidx.core.net.toUri
import androidx.drawerlayout.widget.DrawerLayout import androidx.drawerlayout.widget.DrawerLayout
import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration import androidx.navigation.ui.AppBarConfiguration
@@ -40,6 +43,9 @@ import com.yalantis.ucrop.UCrop
import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.app_bar_main.* import kotlinx.android.synthetic.main.app_bar_main.*
import kotlinx.android.synthetic.main.nav_header_main.* import kotlinx.android.synthetic.main.nav_header_main.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import top.fumiama.copymanga.manga.Shelf import top.fumiama.copymanga.manga.Shelf
import top.fumiama.copymanga.tools.ui.UITools import top.fumiama.copymanga.tools.ui.UITools
import top.fumiama.copymanga.ui.book.BookFragment.Companion.bookHandler import top.fumiama.copymanga.ui.book.BookFragment.Companion.bookHandler
@@ -64,7 +70,6 @@ class MainActivity : AppCompatActivity() {
private lateinit var headPic: File private lateinit var headPic: File
lateinit var toolsBox: UITools lateinit var toolsBox: UITools
private var latestDestination = 0
private var isMenuWaiting = false private var isMenuWaiting = false
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@@ -114,6 +119,7 @@ class MainActivity : AppCompatActivity() {
ime = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager ime = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
var latestDestination: Int
navController!!.addOnDestinationChangedListener { _, destination, _ -> navController!!.addOnDestinationChangedListener { _, destination, _ ->
latestDestination = destination.id latestDestination = destination.id
Log.d("MyMA", "latestDestination: $latestDestination") Log.d("MyMA", "latestDestination: $latestDestination")
@@ -122,51 +128,16 @@ class MainActivity : AppCompatActivity() {
} }
isMenuWaiting = true isMenuWaiting = true
Log.d("MyMA", "start menu waiting") Log.d("MyMA", "start menu waiting")
Thread { lifecycleScope.launch {
sleep(1000) withContext(Dispatchers.IO) {
isMenuWaiting = false sleep(1000)
Log.d("MyMA", "finish menu waiting") withContext(Dispatchers.Main) {
runOnUiThread { isMenuWaiting = false
when (latestDestination) { Log.d("MyMA", "finish menu waiting")
R.id.nav_home -> { changeMenuList(latestDestination)
Log.d("MyMA", "enter home")
menuMain?.findItem(R.id.action_info)?.isVisible = true
menuMain?.findItem(R.id.action_download)?.isVisible = false
menuMain?.findItem(R.id.action_sort)?.isVisible = false
}
R.id.nav_book -> {
Log.d("MyMA", "enter book")
menuMain?.findItem(R.id.action_info)?.isVisible = false
menuMain?.findItem(R.id.action_download)?.isVisible = true
menuMain?.findItem(R.id.action_sort)?.isVisible = false
}
R.id.nav_group -> {
Log.d("MyMA", "enter group")
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_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
menuMain?.findItem(R.id.action_download)?.isVisible = false
menuMain?.findItem(R.id.action_sort)?.isVisible = false
}
} }
} }
}.start() }
} }
} }
@@ -218,24 +189,6 @@ class MainActivity : AppCompatActivity() {
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp() return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
} }
@Deprecated("Deprecated in Java")
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK) when (requestCode) {
UCrop.REQUEST_CROP -> {
val fi = headPic.inputStream()
navhbg.setImageBitmap(BitmapFactory.decodeStream(fi))
fi.close()
}
MSG_CROP_IMAGE -> {
data?.data?.let {
saveFile(it)
cropImageUri()
}
}
}
}
override fun onRequestPermissionsResult( override fun onRequestPermissionsResult(
requestCode: Int, requestCode: Int,
permissions: Array<String?>, permissions: Array<String?>,
@@ -263,6 +216,47 @@ class MainActivity : AppCompatActivity() {
} }
} }
private fun changeMenuList(latestDestination: Int) {
when (latestDestination) {
R.id.nav_home -> {
Log.d("MyMA", "enter home")
menuMain?.findItem(R.id.action_info)?.isVisible = true
menuMain?.findItem(R.id.action_download)?.isVisible = false
menuMain?.findItem(R.id.action_sort)?.isVisible = false
}
R.id.nav_book -> {
Log.d("MyMA", "enter book")
menuMain?.findItem(R.id.action_info)?.isVisible = false
menuMain?.findItem(R.id.action_download)?.isVisible = true
menuMain?.findItem(R.id.action_sort)?.isVisible = false
}
R.id.nav_group -> {
Log.d("MyMA", "enter group")
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_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
menuMain?.findItem(R.id.action_download)?.isVisible = false
menuMain?.findItem(R.id.action_sort)?.isVisible = false
}
}
}
private fun checkReadPermission(): Boolean { private fun checkReadPermission(): Boolean {
return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N && ContextCompat.checkSelfPermission( return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N && ContextCompat.checkSelfPermission(
this, this,
@@ -277,11 +271,18 @@ class MainActivity : AppCompatActivity() {
} else true } else true
} }
private var pickerLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) result.data?.data?.let {
saveFile(it)
cropImageUri()
} else Toast.makeText(this, R.string.err_pick_img, Toast.LENGTH_SHORT).show()
}
@SuppressLint("IntentReset") @SuppressLint("IntentReset")
private fun pickPicture() { private fun pickPicture() {
val i = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI) val i = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
i.type = "image/*" i.type = "image/*"
startActivityForResult(i, MSG_CROP_IMAGE) pickerLauncher.launch(i)
} }
private fun saveFile(uri: Uri) { private fun saveFile(uri: Uri) {
@@ -302,11 +303,18 @@ class MainActivity : AppCompatActivity() {
if (headPic.exists()) navhbg.setImageURI(headPic.toUri()) if (headPic.exists()) navhbg.setImageURI(headPic.toUri())
} }
private var cropLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
val fi = headPic.inputStream()
navhbg.setImageBitmap(BitmapFactory.decodeStream(fi))
fi.close()
} else Toast.makeText(this, R.string.err_crop_img, Toast.LENGTH_SHORT).show()
}
private fun cropImageUri() { private fun cropImageUri() {
val op = UCrop.Options() val op = UCrop.Options()
val r = navhbg.width.toFloat() / navhbg.height.toFloat() val r = navhbg.width.toFloat() / navhbg.height.toFloat()
Log.d("MyMain", "Img info: (${navhbg.width}, ${navhbg.height})") Log.d("MyMain", "Img info: (${navhbg.width}, ${navhbg.height})")
Log.d("MyMain", "Result code: ${UCrop.REQUEST_CROP}")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
op.setCompressionFormat(Bitmap.CompressFormat.WEBP_LOSSY) op.setCompressionFormat(Bitmap.CompressFormat.WEBP_LOSSY)
} else { } else {
@@ -315,17 +323,17 @@ class MainActivity : AppCompatActivity() {
op.setStatusBarColor(resources.getColor(R.color.colorPrimaryDark, theme)) op.setStatusBarColor(resources.getColor(R.color.colorPrimaryDark, theme))
op.setToolbarColor(resources.getColor(R.color.colorPrimary, theme)) op.setToolbarColor(resources.getColor(R.color.colorPrimary, theme))
op.setActiveControlsWidgetColor(resources.getColor(R.color.colorAccent, theme)) op.setActiveControlsWidgetColor(resources.getColor(R.color.colorAccent, theme))
UCrop.of(headPic.toUri(), headPic.toUri()) cropLauncher.launch(UCrop.of(headPic.toUri(), headPic.toUri())
.withAspectRatio(r, 1F) .withAspectRatio(r, 1F)
.withMaxResultSize(navhbg.width, navhbg.height) .withMaxResultSize(navhbg.width, navhbg.height)
.withOptions(op) .withOptions(op)
.start(this) .getIntent(this))
} }
private fun checkUpdate(ignoreSkip: Boolean) { private fun checkUpdate(ignoreSkip: Boolean) {
Thread{ lifecycleScope.launch {
Update.checkUpdate(this, toolsBox, ignoreSkip) Update.checkUpdate(this@MainActivity, toolsBox, ignoreSkip)
}.start() }
} }
private fun showAbout() { private fun showAbout() {

View File

@@ -3,12 +3,13 @@ package top.fumiama.copymanga.json;
public class ComicStructure { public class ComicStructure {
public String uuid; public String uuid;
public String name; public String name;
public String alias; //public String alias;
public int img_type;
public ValueDisplayPair region;
public ValueDisplayPair status; public ValueDisplayPair status;
public ThemeStructure[] theme; public ThemeStructure[] theme;
public String path_word; public String path_word;
public ThemeStructure[] author; public ThemeStructure[] author;
public int img_type;
public String brief; public String brief;
public String datetime_updated; public String datetime_updated;
public String cover; public String cover;

View File

@@ -1,6 +1,8 @@
package top.fumiama.copymanga.manga package top.fumiama.copymanga.manga
import com.google.gson.Gson import com.google.gson.Gson
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import top.fumiama.copymanga.json.BookQueryStructure import top.fumiama.copymanga.json.BookQueryStructure
import top.fumiama.copymanga.json.ReturnBase import top.fumiama.copymanga.json.ReturnBase
import top.fumiama.copymanga.tools.http.DownloadTools import top.fumiama.copymanga.tools.http.DownloadTools
@@ -12,9 +14,9 @@ class Shelf(private val token: String, getString: (Int) -> String) {
private val queryApiUrl = getString(R.string.bookUserQueryApiUrl) private val queryApiUrl = getString(R.string.bookUserQueryApiUrl)
private val referer: String = getString(R.string.referer) private val referer: String = getString(R.string.referer)
private val ua: String = getString(R.string.pc_ua) private val ua: String = getString(R.string.pc_ua)
fun add(comicId: String): String { suspend fun add(comicId: String): String = withContext(Dispatchers.IO) {
if (comicId.isEmpty()) { if (comicId.isEmpty()) {
return "空漫画ID" return@withContext "空漫画ID"
} }
val body = buildString { val body = buildString {
append("comic_id=") append("comic_id=")
@@ -25,13 +27,13 @@ class Shelf(private val token: String, getString: (Int) -> String) {
} }
val re = DownloadTools.requestWithBody( val re = DownloadTools.requestWithBody(
"$apiUrl?platform=3", "POST", body.encodeToByteArray(), referer, ua "$apiUrl?platform=3", "POST", body.encodeToByteArray(), referer, ua
)?.decodeToString() ?: return "空回应" )?.decodeToString() ?: return@withContext "空回应"
return Gson().fromJson(re, ReturnBase::class.java).message return@withContext Gson().fromJson(re, ReturnBase::class.java).message
} }
fun del(vararg bookIds: Int): String { suspend fun del(vararg bookIds: Int): String = withContext(Dispatchers.IO) {
if (bookIds.isEmpty()) { if (bookIds.isEmpty()) {
return "空ID列表" return@withContext "空ID列表"
} }
val body = buildString { val body = buildString {
bookIds.forEach { bookIds.forEach {
@@ -44,16 +46,13 @@ class Shelf(private val token: String, getString: (Int) -> String) {
} }
val re = DownloadTools.requestWithBody( val re = DownloadTools.requestWithBody(
"${apiUrl}s?platform=3", "DELETE", body.encodeToByteArray(), referer, ua "${apiUrl}s?platform=3", "DELETE", body.encodeToByteArray(), referer, ua
)?.decodeToString() ?: return "空回应" )?.decodeToString() ?: return@withContext "空回应"
return Gson().fromJson(re, ReturnBase::class.java).message return@withContext Gson().fromJson(re, ReturnBase::class.java).message
} }
fun query(pathWord: String): BookQueryStructure { suspend fun query(pathWord: String): BookQueryStructure? = withContext(Dispatchers.IO) {
DownloadTools.getHttpContent(queryApiUrl.format(hostUrl, pathWord), referer, ua)?.let { return@withContext DownloadTools.getHttpContent(queryApiUrl.format(hostUrl, pathWord), referer, ua)?.let {
return Gson().fromJson(it.decodeToString(), BookQueryStructure::class.java) Gson().fromJson(it.decodeToString(), BookQueryStructure::class.java)
} }
val b = BookQueryStructure()
b.code = 400
return b
} }
} }

View File

@@ -7,7 +7,6 @@ import android.view.View
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.load.model.GlideUrl import com.bumptech.glide.load.model.GlideUrl
import kotlinx.android.synthetic.main.card_book.*
import kotlinx.android.synthetic.main.card_book.view.* import kotlinx.android.synthetic.main.card_book.view.*
import kotlinx.android.synthetic.main.line_horizonal_empty.view.* import kotlinx.android.synthetic.main.line_horizonal_empty.view.*
import kotlinx.android.synthetic.main.line_lazybooklines.* import kotlinx.android.synthetic.main.line_lazybooklines.*
@@ -36,6 +35,7 @@ class CardList(
rows = arrayOfNulls(20) rows = arrayOfNulls(20)
index = 0 index = 0
count = 0 count = 0
cardLoadingWaits.set(0)
exitCardList = false exitCardList = false
} }

View File

@@ -7,7 +7,6 @@ import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import com.google.gson.Gson import com.google.gson.Gson
import kotlinx.android.synthetic.main.line_lazybooklines.* import kotlinx.android.synthetic.main.line_lazybooklines.*
import top.fumiama.copymanga.MainActivity
import top.fumiama.copymanga.json.BookListStructure import top.fumiama.copymanga.json.BookListStructure
import top.fumiama.copymanga.json.HistoryBookListStructure import top.fumiama.copymanga.json.HistoryBookListStructure
import top.fumiama.copymanga.json.ShelfStructure import top.fumiama.copymanga.json.ShelfStructure
@@ -25,8 +24,8 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT
override fun addPage(){ override fun addPage(){
super.addPage() super.addPage()
ad = AutoDownloadThread(subUrl) { ad = AutoDownloadThread(subUrl) { data ->
if (it == null) { if (data == null) {
activity?.runOnUiThread { activity?.runOnUiThread {
findNavController().popBackStack() findNavController().popBackStack()
} }
@@ -37,7 +36,7 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT
isRefresh = false isRefresh = false
} }
if(isTypeBook) { if(isTypeBook) {
val bookList = Gson().fromJson(it?.decodeToString(), TypeBookListStructure::class.java) val bookList = Gson().fromJson(data.decodeToString(), TypeBookListStructure::class.java)
bookList?.apply { bookList?.apply {
Log.d("MyICL", "offset:${results.offset}, total:${results.total}") Log.d("MyICL", "offset:${results.offset}, total:${results.total}")
if(results.offset < results.total) { if(results.offset < results.total) {
@@ -56,7 +55,7 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT
page++ page++
} }
} else if(isHistoryBook) { } else if(isHistoryBook) {
val bookList = Gson().fromJson(it?.decodeToString(), HistoryBookListStructure::class.java) val bookList = Gson().fromJson(data.decodeToString(), HistoryBookListStructure::class.java)
bookList?.apply { bookList?.apply {
Log.d("MyICL", "offset:${results?.offset}, total:${results?.total}") Log.d("MyICL", "offset:${results?.offset}, total:${results?.total}")
if(results.offset < results.total) { if(results.offset < results.total) {
@@ -75,7 +74,7 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT
page++ page++
} }
} else if (isShelfBook) { } else if (isShelfBook) {
val bookList = Gson().fromJson(it?.decodeToString(), ShelfStructure::class.java) val bookList = Gson().fromJson(data.decodeToString(), ShelfStructure::class.java)
bookList?.apply { bookList?.apply {
Log.d("MyICL", "offset:${results?.offset}, total:${results?.total}") Log.d("MyICL", "offset:${results?.offset}, total:${results?.total}")
if(results.offset < results.total) { if(results.offset < results.total) {
@@ -83,7 +82,7 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT
results?.list?.forEach{ book -> results?.list?.forEach{ book ->
if(ad?.exit == true) return@AutoDownloadThread if(ad?.exit == true) return@AutoDownloadThread
cardList?.addCard( cardList?.addCard(
book?.comic?.name?:"null", "\n读到${book?.last_browse?.last_browse_name}", book?.comic?.cover, book?.comic?.name?:"null", "\n${book?.last_browse?.last_browse_name?.let { "读到$it" }?:"未读"}", book?.comic?.cover,
book?.comic?.path_word, null, null, book?.comic?.path_word, null, null,
book?.comic?.status==1, book?.comic?.status==1,
book.comic?.browse?.chapter_uuid != book.comic?.last_chapter_id book.comic?.browse?.chapter_uuid != book.comic?.last_chapter_id
@@ -95,7 +94,7 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT
page++ page++
} }
} else { } else {
val bookList = Gson().fromJson(it?.decodeToString(), BookListStructure::class.java) val bookList = Gson().fromJson(data.decodeToString(), BookListStructure::class.java)
bookList?.apply { bookList?.apply {
Log.d("MyICL", "offset:${results?.offset}, total:${results?.total}") Log.d("MyICL", "offset:${results?.offset}, total:${results?.total}")
if(results.offset < results.total) { if(results.offset < results.total) {

View File

@@ -3,15 +3,18 @@ package top.fumiama.copymanga.template.ui
import android.animation.ObjectAnimator import android.animation.ObjectAnimator
import android.view.View import android.view.View
import kotlinx.android.synthetic.main.anchor_popular.view.* import kotlinx.android.synthetic.main.anchor_popular.view.*
import kotlinx.android.synthetic.main.line_finish.*
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
import top.fumiama.copymanga.tools.api.CMApi import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.dmzj.copymanga.R import top.fumiama.dmzj.copymanga.R
@ExperimentalStdlibApi @ExperimentalStdlibApi
open class StatusCardFlow(private val api: Int, nav: Int) : InfoCardLoader(R.layout.fragment_statuscardflow, nav) { open class StatusCardFlow(private val api: Int, nav: Int, inflateRes: Int,
val sortWay = listOf("-datetime_updated", "datetime_updated", "popular", "-popular") isTypeBook: Boolean = false,
isHistoryBook: Boolean = false,
isShelfBook: Boolean = false) : InfoCardLoader(inflateRes, nav, isTypeBook, isHistoryBook, isShelfBook) {
val sortWay = listOf("-datetime_updated", "datetime_updated", "-popular", "popular")
var sortValue = 0 var sortValue = 0
var lineUpdate: View? = null
var lineHot: View? = null
override fun getApiUrl() = override fun getApiUrl() =
getString(api).format( getString(api).format(
@@ -22,21 +25,17 @@ open class StatusCardFlow(private val api: Int, nav: Int) : InfoCardLoader(R.lay
override fun setListeners() { override fun setListeners() {
super.setListeners() super.setListeners()
setUpdate(line_finish_time) lineUpdate?.let { setUpdate(it) }
setHot(line_finish_pop) lineHot?.let { setHot(it) }
lineUpdate?.alpha = 1f
lineHot?.alpha = 0.5f
} }
open fun setUpdate(that: View) { open fun setUpdate(that: View) {
that.apply { that.apply {
apt.setText(R.string.menu_update_time) apt.setText(R.string.menu_update_time)
setOnClickListener { setOnClickListener {
sortValue = if(apim.rotation == 0f) { sortValue = triggerLine(false)
ObjectAnimator.ofFloat(apim, "rotation", 0f, 180f).setDuration(233).start()
1
}else{
ObjectAnimator.ofFloat(apim, "rotation", 180f, 0f).setDuration(233).start()
0
}
Thread{ Thread{
Thread.sleep(400) Thread.sleep(400)
activity?.runOnUiThread { activity?.runOnUiThread {
@@ -52,13 +51,7 @@ open class StatusCardFlow(private val api: Int, nav: Int) : InfoCardLoader(R.lay
that.apply { that.apply {
apt.setText(R.string.menu_hot) apt.setText(R.string.menu_hot)
setOnClickListener { setOnClickListener {
sortValue = if (apim.rotation == 0f) { sortValue = triggerLine(true)
ObjectAnimator.ofFloat(apim, "rotation", 0f, 180f).setDuration(233).start()
3
} else {
ObjectAnimator.ofFloat(apim, "rotation", 180f, 0f).setDuration(233).start()
2
}
Thread { Thread {
Thread.sleep(400) Thread.sleep(400)
activity?.runOnUiThread { activity?.runOnUiThread {
@@ -69,4 +62,46 @@ open class StatusCardFlow(private val api: Int, nav: Int) : InfoCardLoader(R.lay
} }
} }
} }
open fun triggerLine(isHot: Boolean): Int {
val hot = lineHot?:return 0
val update = lineUpdate?:return 0
if(sortValue >= 2) {
if (isHot) {
return if (hot.apim.rotation == 0f) {
ObjectAnimator.ofFloat(hot.apim, "rotation", 0f, 180f).setDuration(233).start()
3
} else {
ObjectAnimator.ofFloat(hot.apim, "rotation", 180f, 0f).setDuration(233).start()
2
}
} else {
update.alpha = 1f
hot.alpha = 0.5f
return if(update.apim.rotation == 0f) {
0
} else {
1
}
}
} else {
if (!isHot) {
return if(update.apim.rotation == 0f) {
ObjectAnimator.ofFloat(update.apim, "rotation", 0f, 180f).setDuration(233).start()
1
}else{
ObjectAnimator.ofFloat(update.apim, "rotation", 180f, 0f).setDuration(233).start()
0
}
} else {
hot.alpha = 1f
update.alpha = 0.5f
return if (hot.apim.rotation == 0f) {
2
} else {
3
}
}
}
}
} }

View File

@@ -1,12 +1,15 @@
package top.fumiama.copymanga.template.ui package top.fumiama.copymanga.template.ui
import android.os.Bundle import android.os.Bundle
import android.view.View
import kotlinx.android.synthetic.main.app_bar_main.* import kotlinx.android.synthetic.main.app_bar_main.*
import kotlinx.android.synthetic.main.line_finish.*
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
import top.fumiama.copymanga.tools.api.CMApi import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.dmzj.copymanga.R
@ExperimentalStdlibApi @ExperimentalStdlibApi
open class ThemeCardFlow(private val api: Int, nav: Int) : StatusCardFlow(0, nav) { open class ThemeCardFlow(private val api: Int, nav: Int) : StatusCardFlow(0, nav, R.layout.fragment_statuscardflow) {
private var theme = "" private var theme = ""
override fun getApiUrl() = override fun getApiUrl() =
getString(api).format( getString(api).format(
@@ -26,6 +29,12 @@ open class ThemeCardFlow(private val api: Int, nav: Int) : StatusCardFlow(0, nav
} }
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
lineUpdate = line_finish_time
lineHot = line_finish_pop
}
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
arguments?.getString("name")?.apply { arguments?.getString("name")?.apply {

View File

@@ -13,7 +13,7 @@ import java.net.URLEncoder
object CMApi { object CMApi {
var proxy = if(Proxy.useImageProxy) Proxy(R.string.imgProxyApiUrl, R.string.imgProxyApiPrefix, R.string.imgProxyKeyID) else null var proxy = if(Proxy.useImageProxy) Proxy(R.string.imgProxyApiUrl, R.string.imgProxyApiPrefix, R.string.imgProxyKeyID) else null
var resolution = Resolution(Regex("\\.c\\d+x\\.")) var resolution = Resolution(Regex("c\\d+x\\."))
var myGlideHeaders: LazyHeaders? = null var myGlideHeaders: LazyHeaders? = null
get() { get() {
MainActivity.mainWeakReference?.get()?.let { MainActivity.mainWeakReference?.get()?.let {

View File

@@ -16,5 +16,5 @@ class Resolution(private val original: Regex) {
} }
return 1500 return 1500
} }
fun wrap(u: String) : String = u.replace(original, ".c${imageResolution}x.") fun wrap(u: String) : String = u.replace(original, "c${imageResolution}x.")
} }

View File

@@ -13,17 +13,17 @@ class GlideHideLottieViewListener(private val wla: WeakReference<LottieAnimation
override fun onLoadFailed( override fun onLoadFailed(
e: GlideException?, e: GlideException?,
model: Any?, model: Any?,
target: Target<Drawable>?, target: Target<Drawable>,
isFirstResource: Boolean isFirstResource: Boolean
): Boolean { ): Boolean {
return false return false
} }
override fun onResourceReady( override fun onResourceReady(
resource: Drawable?, resource: Drawable,
model: Any?, model: Any,
target: Target<Drawable>?, target: Target<Drawable>?,
dataSource: DataSource?, dataSource: DataSource,
isFirstResource: Boolean isFirstResource: Boolean
): Boolean { ): Boolean {
wla.get()?.apply { wla.get()?.apply {

View File

@@ -6,14 +6,18 @@ import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.View import android.view.View
import android.widget.Toast import android.widget.Toast
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import com.google.gson.Gson import com.google.gson.Gson
import kotlinx.android.synthetic.main.app_bar_main.* import kotlinx.android.synthetic.main.app_bar_main.*
import kotlinx.android.synthetic.main.card_book.*
import kotlinx.android.synthetic.main.fragment_book.* import kotlinx.android.synthetic.main.fragment_book.*
import kotlinx.android.synthetic.main.line_bookinfo_text.* import kotlinx.android.synthetic.main.line_bookinfo_text.*
import kotlinx.android.synthetic.main.line_booktandb.* import kotlinx.android.synthetic.main.line_booktandb.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import top.fumiama.copymanga.MainActivity import top.fumiama.copymanga.MainActivity
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
import top.fumiama.copymanga.json.VolumeStructure import top.fumiama.copymanga.json.VolumeStructure
import top.fumiama.copymanga.manga.Reader import top.fumiama.copymanga.manga.Reader
import top.fumiama.copymanga.template.general.NoBackRefreshFragment import top.fumiama.copymanga.template.general.NoBackRefreshFragment
@@ -32,14 +36,14 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
ComicDlFragment.exit = false ComicDlFragment.exit = false
fbl?.setPadding(0, 0, 0, navBarHeight) fbvp?.setPadding(0, 0, 0, navBarHeight)
if(isFirstInflate) { if(isFirstInflate) {
var path = "" var path = ""
arguments?.apply { arguments?.apply {
if (getBoolean("loadJson")) { if (getBoolean("loadJson")) {
getString("name")?.let { name -> getString("name")?.let { name ->
mainWeakReference?.get()?.getExternalFilesDir("")?.let { activity?.getExternalFilesDir("")?.let {
Gson().fromJson(File(File(it, name), "info.json").readText(), Array<VolumeStructure>::class.java) Gson().fromJson(File(File(it, name), "info.json").readText(), Array<VolumeStructure>::class.java)
}?.apply { }?.apply {
if (isEmpty() || get(0).results.list.isEmpty()) { if (isEmpty() || get(0).results.list.isEmpty()) {
@@ -62,10 +66,12 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
mBookHandler = BookHandler(WeakReference(this), path) mBookHandler = BookHandler(WeakReference(this), path)
Log.d("MyBF", "read path: $path") Log.d("MyBF", "read path: $path")
bookHandler = mBookHandler bookHandler = mBookHandler
Thread { lifecycleScope.launch {
sleep(600) withContext(Dispatchers.IO) {
mBookHandler?.startLoad() sleep(600)
}.start() mBookHandler?.startLoad()
}
}
} else { } else {
bookHandler = mBookHandler bookHandler = mBookHandler
} }
@@ -75,7 +81,7 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
super.onResume() super.onResume()
isOnPause = false isOnPause = false
bookHandler = mBookHandler bookHandler = mBookHandler
mainWeakReference?.get()?.apply { activity?.apply {
toolbar.title = mBookHandler?.book?.results?.comic?.name toolbar.title = mBookHandler?.book?.results?.comic?.name
} }
setStartRead() setStartRead()
@@ -96,7 +102,7 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
} }
fun setStartRead() { fun setStartRead() {
if(mBookHandler?.chapterNames?.isNotEmpty() == true) mainWeakReference?.get()?.apply { if(mBookHandler?.chapterNames?.isNotEmpty() == true) activity?.apply {
mBookHandler?.book?.results?.comic?.let { comic -> mBookHandler?.book?.results?.comic?.let { comic ->
getPreferences(MODE_PRIVATE).getInt(comic.name, -1).let { p -> getPreferences(MODE_PRIVATE).getInt(comic.name, -1).let { p ->
this@BookFragment.lbbstart.apply { this@BookFragment.lbbstart.apply {
@@ -118,12 +124,13 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
fun setAddToShelf() { fun setAddToShelf() {
if(mBookHandler?.chapterNames?.isNotEmpty() == true) { if(mBookHandler?.chapterNames?.isNotEmpty() != true) return
lifecycleScope.launch {
val b = MainActivity.shelf?.query(mBookHandler?.path!!) val b = MainActivity.shelf?.query(mBookHandler?.path!!)
mBookHandler?.collect = b?.results?.collect?:-2 mBookHandler?.collect = b?.results?.collect?:-2
Log.d("MyBF", "get collect of ${mBookHandler?.path} = ${mBookHandler?.collect}") Log.d("MyBF", "get collect of ${mBookHandler?.path} = ${mBookHandler?.collect}")
b?.results?.browse?.chapter_name?.let { name -> tic.text = b?.results?.browse?.chapter_name?.let { name ->
btsub.text = "${btsub.text} ${getString(R.string.text_format_cloud_read_to).format(name)}" getString(R.string.text_format_cloud_read_to).format(name)
} }
mBookHandler?.collect?.let { collect -> mBookHandler?.collect?.let { collect ->
if (collect > 0) { if (collect > 0) {
@@ -132,30 +139,24 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
} }
mBookHandler?.book?.results?.comic?.let { comic -> mBookHandler?.book?.results?.comic?.let { comic ->
this@BookFragment.lbbsub.setOnClickListener { this@BookFragment.lbbsub.setOnClickListener {
if (this@BookFragment.lbbsub.text != getString(R.string.button_sub)) { lifecycleScope.launch clickLaunch@ {
mBookHandler?.collect?.let { collect -> if (this@BookFragment.lbbsub.text != getString(R.string.button_sub)) {
if (collect < 0) return@setOnClickListener mBookHandler?.collect?.let { collect ->
Thread{ if (collect < 0) return@clickLaunch
val re = MainActivity.shelf?.del(collect) val re = MainActivity.shelf?.del(collect)
activity?.runOnUiThread { Toast.makeText(context, re, Toast.LENGTH_SHORT).show()
Toast.makeText(context, re, Toast.LENGTH_SHORT).show() if (re == "请求成功") {
if (re == "请求成功") { this@BookFragment.lbbsub.setText(R.string.button_sub)
this@BookFragment.lbbsub.setText(R.string.button_sub)
}
} }
}.start()
}
return@setOnClickListener
}
Thread{
val re = MainActivity.shelf?.add(comic.uuid)
activity?.runOnUiThread {
Toast.makeText(context, re, Toast.LENGTH_SHORT).show()
if (re == "修改成功") {
this@BookFragment.lbbsub.setText(R.string.button_sub_subscribed)
} }
return@clickLaunch
} }
}.start() val re = MainActivity.shelf?.add(comic.uuid)
Toast.makeText(context, re, Toast.LENGTH_SHORT).show()
if (re == "修改成功") {
this@BookFragment.lbbsub.setText(R.string.button_sub_subscribed)
}
}
} }
} }
} }

View File

@@ -6,13 +6,18 @@ import android.os.Looper
import android.os.Message import android.os.Message
import android.util.Log import android.util.Log
import android.view.View import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TextView import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.core.graphics.drawable.toBitmap import androidx.core.graphics.drawable.toBitmap
import androidx.core.widget.NestedScrollView
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.load.model.GlideUrl import com.bumptech.glide.load.model.GlideUrl
import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.request.RequestOptions
import com.google.android.material.tabs.TabLayoutMediator
import com.google.gson.Gson import com.google.gson.Gson
import kotlinx.android.synthetic.main.app_bar_main.* import kotlinx.android.synthetic.main.app_bar_main.*
import kotlinx.android.synthetic.main.card_book.* import kotlinx.android.synthetic.main.card_book.*
@@ -22,6 +27,7 @@ import kotlinx.android.synthetic.main.line_bookinfo.*
import kotlinx.android.synthetic.main.line_bookinfo_text.* import kotlinx.android.synthetic.main.line_bookinfo_text.*
import kotlinx.android.synthetic.main.line_caption.view.* import kotlinx.android.synthetic.main.line_caption.view.*
import kotlinx.android.synthetic.main.line_chapter.view.* import kotlinx.android.synthetic.main.line_chapter.view.*
import kotlinx.android.synthetic.main.page_nested_list.view.*
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
import top.fumiama.copymanga.json.BookInfoStructure import top.fumiama.copymanga.json.BookInfoStructure
import top.fumiama.copymanga.json.ChapterStructure import top.fumiama.copymanga.json.ChapterStructure
@@ -62,7 +68,7 @@ class BookHandler(private val th: WeakReference<BookFragment>, val path: String)
var vols: Array<VolumeStructure>? = null var vols: Array<VolumeStructure>? = null
var chapterNames = arrayOf<String>() var chapterNames = arrayOf<String>()
var collect: Int = -1 var collect: Int = -1
private val divider get() = that?.layoutInflater?.inflate(R.layout.div_h, that?.fbl, false) private val divider get() = that?.layoutInflater?.inflate(R.layout.div_h, that?.lbl, false)
var urlArray = arrayOf<String>() var urlArray = arrayOf<String>()
@@ -73,10 +79,7 @@ class BookHandler(private val th: WeakReference<BookFragment>, val path: String)
1 -> setCover() 1 -> setCover()
2 -> setTexts() 2 -> setTexts()
3 -> setAuthorsAndTags() 3 -> setAuthorsAndTags()
//4 -> setOverScale()
6 -> if(complete) that?.navigate2dl() 6 -> if(complete) that?.navigate2dl()
7 -> setVolumes()
8 -> that?.apply { fbl?.addView(msg.obj as View) }
9 -> endSetLayouts() 9 -> endSetLayouts()
} }
} }
@@ -127,11 +130,6 @@ class BookHandler(private val th: WeakReference<BookFragment>, val path: String)
Log.d("MyBH", "Set complete: true") Log.d("MyBH", "Set complete: true")
} }
/*private fun setOverScale() {
if (exit) return
that?.fbov?.setScaleView(that!!.fbapp)
}*/
private fun setCover() { private fun setCover() {
if (exit) return if (exit) return
that?.apply { that?.apply {
@@ -144,63 +142,69 @@ class BookHandler(private val th: WeakReference<BookFragment>, val path: String)
?.let { it2 -> RequestOptions.bitmapTransform(it2) } ?.let { it2 -> RequestOptions.bitmapTransform(it2) }
?.let { it3 -> load.apply(it3).into(lbibg) } ?.let { it3 -> load.apply(it3).into(lbibg) }
} }
imf?.visibility = View.GONE //imf?.visibility = View.GONE
//fbl?.addView(divider) //fbl?.addView(divider)
} }
} }
private fun getThemeSeq(authors: Array<ThemeStructure>): CharSequence{ /*private fun getThemeSeq(authors: Array<ThemeStructure>): CharSequence{
var re = "" var re = ""
for(author in authors) re += author.name + ' ' for(author in authors) re += author.name + ' '
return re return re
} }*/
private fun setTexts(){ private fun setTexts() {
if (exit) return if (exit) return
//that?.tic?.text = book?.name //that?.tic?.text = book?.name
that?.tic?.visibility = View.GONE //that?.tic?.visibility = View.GONE
mainWeakReference?.get()?.toolbar?.title = book?.results?.comic?.name mainWeakReference?.get()?.toolbar?.title = book?.results?.comic?.name
that?.btauth?.text = book?.results?.comic?.author?.let { getThemeSeq(it) } that?.btauth?.text = that?.getString(R.string.text_format_region)?.format(
that?.bttag?.text = book?.results?.comic?.theme?.let { getThemeSeq(it) } book?.results?.comic?.region?.display
that?.bthit?.text = that?.getString(R.string.text_format_hit)?.let { String.format( )
it, that?.bttag?.text = that?.getString(R.string.text_format_img_type)?.format(when(book?.results?.comic?.img_type) {
1 -> "条漫"
2 -> "普通"
else -> "未知类型${book?.results?.comic?.img_type}"
})
that?.bthit?.text = that?.getString(R.string.text_format_hit)?.format(
book?.results?.comic?.popular book?.results?.comic?.popular
) }?:"" )
that?.btsub?.text = that?.getString(R.string.text_format_stat)?.let { String.format( that?.btsub?.text = that?.getString(R.string.text_format_stat)?.format(
it,
book?.results?.comic?.status?.display book?.results?.comic?.status?.display
) }?:"" )
that?.bttime?.text = book?.results?.comic?.datetime_updated that?.bttime?.text = book?.results?.comic?.datetime_updated
val v = that?.layoutInflater?.inflate(R.layout.line_text_info, that?.fbl, false) val v = that?.layoutInflater?.inflate(R.layout.line_text_info, that?.lbl, false)
(v as TextView).text = book?.results?.comic?.brief (v as TextView).text = book?.results?.comic?.brief
that?.fbl?.addView(v) that?.lbl?.addView(v)
that?.fbl?.addView(divider) that?.lbl?.addView(divider)
} }
private fun setTheme(caption: String, themeStructure: Array<ThemeStructure>, nav: Int) { private fun setTheme(caption: String, themeStructure: Array<ThemeStructure>, nav: Int) {
that?.apply { that?.apply {
val t = layoutInflater.inflate(R.layout.line_caption, fbl, false) val t = layoutInflater.inflate(R.layout.line_caption, lbl, false)
t.tcptn.text = caption t.tcptn.text = caption
fbl.addView(t) lbl.addView(t)
fbl.addView(layoutInflater.inflate(R.layout.div_h, fbl, false)) lbl.addView(layoutInflater.inflate(R.layout.div_h, lbl, false))
} }
var line: View? = null var line: View? = null
val last = themeStructure.size - 1 val last = themeStructure.size - 1
themeStructure.onEachIndexed { i, it -> themeStructure.onEachIndexed { i, it ->
if(line == null) { if(line == null) {
if(i == last) { if(i == last) {
line = that?.layoutInflater?.inflate(R.layout.line_chapter, that!!.fbl, false) line = that?.layoutInflater?.inflate(R.layout.line_chapter, that!!.lbl, false)
line?.lcc?.apply { line?.lcc?.apply {
lct.text = it.name lct.text = it.name
lci.setBackgroundResource(R.drawable.ic_list)
setOnClickListener { _ -> setOnClickListener { _ ->
loadVolume(it.name, it.path_word, nav) loadVolume(it.name, it.path_word, nav)
} }
} }
that?.fbl?.addView(line) that?.lbl?.addView(line)
} else { } else {
line = that?.layoutInflater?.inflate(R.layout.line_2chapters, that!!.fbl, false) line = that?.layoutInflater?.inflate(R.layout.line_2chapters, that!!.lbl, false)
line?.l2cl?.apply { line?.l2cl?.apply {
lct.text = it.name lct.text = it.name
lci.setBackgroundResource(R.drawable.ic_list)
setOnClickListener { _ -> setOnClickListener { _ ->
loadVolume(it.name, it.path_word, nav) loadVolume(it.name, it.path_word, nav)
} }
@@ -208,10 +212,11 @@ class BookHandler(private val th: WeakReference<BookFragment>, val path: String)
} }
} else line?.l2cr?.apply { } else line?.l2cr?.apply {
lct.text = it.name lct.text = it.name
lci.setBackgroundResource(R.drawable.ic_list)
setOnClickListener { _ -> setOnClickListener { _ ->
loadVolume(it.name, it.path_word, nav) loadVolume(it.name, it.path_word, nav)
} }
that?.fbl?.addView(line) that?.lbl?.addView(line)
line = null line = null
} }
} }
@@ -228,7 +233,7 @@ class BookHandler(private val th: WeakReference<BookFragment>, val path: String)
R.id.action_nav_book_to_nav_author R.id.action_nav_book_to_nav_author
) )
} }
fbl.addView(layoutInflater.inflate(R.layout.div_h, fbl, false)) lbl.addView(layoutInflater.inflate(R.layout.div_h, lbl, false))
theme?.let { theme?.let {
setTheme( setTheme(
getString(R.string.caption), getString(R.string.caption),
@@ -240,11 +245,68 @@ class BookHandler(private val th: WeakReference<BookFragment>, val path: String)
} }
} }
private fun addVolumesView(v: View) { private fun addVolumesView(l: LinearLayout, v: View) {
obtainMessage(8, v).sendToTarget() that?.activity?.runOnUiThread {
l.addView(v)
}
} }
private fun setVolumes() = Thread { private fun setVolume(fbl: LinearLayout, p: Int) = Thread {
if (exit) return@Thread
that?.apply {
book?.results?.apply {
var i = 0
for (j in 0 until p) {
i += vols?.get(j)?.results?.list?.size?:0
}
var last = i-1
vols?.get(p)?.let { v ->
if(exit) return@Thread
var line: View? = null
last += v.results.list.size
v.results.list.forEach {
val f = CMApi.getZipFile(context?.getExternalFilesDir(""), comic.name, keys[p], it.name)
Log.d("MyBH", "i = $i, last=$last, add chapter ${it.name}, line is null: ${line == null}")
that?.isOnPause?.let { isOnPause ->
while (isOnPause && !exit) sleep(1000)
if (exit) return@Thread
}?:return@Thread
if(line == null) {
if(i == last) {
line = layoutInflater.inflate(R.layout.line_chapter, fbl, false)
line?.lcc?.apply {
lct.text = it.name
if (f.exists()) lci.setBackgroundResource(R.drawable.ic_success)
Log.d("MyBH", "add last single chapter ${it.name}")
val index = i
setOnClickListener { Reader.viewMangaAt(comic.name, index, urlArray) }
}
line?.let { l -> addVolumesView(fbl, l) }
} else {
line = layoutInflater.inflate(R.layout.line_2chapters, fbl, false)
line?.l2cl?.apply {
lct.text = it.name
if (f.exists()) lci.setBackgroundResource(R.drawable.ic_success)
val index = i
setOnClickListener { Reader.viewMangaAt(comic.name, index, urlArray) }
}
}
} else line?.l2cr?.apply {
lct.text = it.name
if (f.exists()) lci.setBackgroundResource(R.drawable.ic_success)
val index = i
setOnClickListener { Reader.viewMangaAt(comic.name, index, urlArray) }
line?.let { l -> addVolumesView(fbl, l) }
line = null
}
i++
}
}
}
}
}.start()
private fun setViewManga() = Thread {
if (exit) return@Thread if (exit) return@Thread
that?.apply { that?.apply {
book?.results?.apply { book?.results?.apply {
@@ -255,58 +317,26 @@ class BookHandler(private val th: WeakReference<BookFragment>, val path: String)
var last = -1 var last = -1
vols?.forEachIndexed { groupIndex, v -> vols?.forEachIndexed { groupIndex, v ->
if(exit) return@Thread if(exit) return@Thread
addVolumesView(layoutInflater.inflate(R.layout.div_h, fbl, false))
val t = layoutInflater.inflate(R.layout.line_caption, fbl, false)
t.tcptn.text = keys[groupIndex]
addVolumesView(t)
addVolumesView(layoutInflater.inflate(R.layout.div_h, fbl, false))
var line: View? = null
last += v.results.list.size last += v.results.list.size
v.results.list.forEach { v.results.list.forEach {
urlArray += CMApi.getChapterInfoApiUrl( urlArray += CMApi.getChapterInfoApiUrl(
comic.path_word, comic.path_word,
it.uuid it.uuid
)?:"" )?:""
ViewMangaActivity.fileArray += CMApi.getZipFile(context?.getExternalFilesDir(""), comic.name, keys[groupIndex], it.name) val f = CMApi.getZipFile(context?.getExternalFilesDir(""), comic.name, keys[groupIndex], it.name)
ViewMangaActivity.fileArray += f
chapterNames += it.name chapterNames += it.name
ViewMangaActivity.uuidArray += it.uuid ViewMangaActivity.uuidArray += it.uuid
Log.d("MyBH", "i = $i, last=$last, add chapter ${it.name}, line is null: ${line == null}")
that?.isOnPause?.let { isOnPause -> that?.isOnPause?.let { isOnPause ->
while (isOnPause && !exit) sleep(1000) while (isOnPause && !exit) sleep(1000)
if (exit) return@Thread if (exit) return@Thread
}?:return@Thread }?:return@Thread
if(line == null) {
if(i == last) {
line = layoutInflater.inflate(R.layout.line_chapter, that!!.fbl, false)
line?.lcc?.apply {
lct.text = it.name
Log.d("MyBH", "add last single chapter ${it.name}")
val index = i
setOnClickListener { Reader.viewMangaAt(comic.name, index, urlArray) }
}
line?.let { l -> addVolumesView(l) }
} else {
line = layoutInflater.inflate(R.layout.line_2chapters, that!!.fbl, false)
line?.l2cl?.apply {
lct.text = it.name
val index = i
setOnClickListener { Reader.viewMangaAt(comic.name, index, urlArray) }
}
}
} else line?.l2cr?.apply {
lct.text = it.name
val index = i
setOnClickListener { Reader.viewMangaAt(comic.name, index, urlArray) }
line?.let { l -> addVolumesView(l) }
line = null
}
i++ i++
} }
} }
sendEmptyMessage(9) // end set layout
} }
} }
sendEmptyMessage(9) // end set layout
}.start() }.start()
private fun loadVolume(name: String, path: String, nav: Int){ private fun loadVolume(name: String, path: String, nav: Int){
@@ -375,10 +405,18 @@ class BookHandler(private val th: WeakReference<BookFragment>, val path: String)
c++ c++
} }
if (volumes.size == gpws.size) { if (volumes.size == gpws.size) {
that?.activity?.runOnUiThread { saveVolumes(volumes)
saveVolumes(volumes) that?.fbtab?.let { tab ->
sendEmptyMessage(7) that?.fbvp?.let { vp ->
that?.activity?.runOnUiThread {
vp.adapter = ViewData(vp).RecyclerViewAdapter()
TabLayoutMediator(tab, vp) { t, p ->
t.text = keys[p]
}.attach()
}
}
} }
setViewManga()
} }
}.start() }.start()
@@ -417,4 +455,18 @@ class BookHandler(private val th: WeakReference<BookFragment>, val path: String)
} }
vols = volumes vols = volumes
} }
inner class ViewData(itemView: View): RecyclerView.ViewHolder(itemView) {
inner class RecyclerViewAdapter: RecyclerView.Adapter<ViewData>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewData {
return ViewData(that?.layoutInflater?.inflate(R.layout.page_nested_list, parent, false) as NestedScrollView)
}
override fun onBindViewHolder(holder: ViewData, position: Int) {
setVolume(holder.itemView.fbl, position)
}
override fun getItemCount(): Int = keys.size
}
}
} }

View File

@@ -1,7 +1,17 @@
package top.fumiama.copymanga.ui.cardflow.finish package top.fumiama.copymanga.ui.cardflow.finish
import android.os.Bundle
import android.view.View
import top.fumiama.copymanga.template.ui.StatusCardFlow import top.fumiama.copymanga.template.ui.StatusCardFlow
import top.fumiama.dmzj.copymanga.R import top.fumiama.dmzj.copymanga.R
import kotlinx.android.synthetic.main.line_finish.*
@ExperimentalStdlibApi @ExperimentalStdlibApi
class FinishFragment : StatusCardFlow(R.string.finishApiUrl, R.id.action_nav_finish_to_nav_book) class FinishFragment : StatusCardFlow(
R.string.finishApiUrl, R.id.action_nav_finish_to_nav_book, R.layout.fragment_statuscardflow) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
lineUpdate = line_finish_time
lineHot = line_finish_pop
}
}

View File

@@ -1,8 +1,5 @@
package top.fumiama.copymanga.ui.cardflow.newest package top.fumiama.copymanga.ui.cardflow.newest
import android.view.View
import kotlinx.android.synthetic.main.line_lazybooklines.*
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
import top.fumiama.copymanga.template.ui.InfoCardLoader import top.fumiama.copymanga.template.ui.InfoCardLoader
import top.fumiama.copymanga.tools.api.CMApi import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.dmzj.copymanga.R import top.fumiama.dmzj.copymanga.R

View File

@@ -4,7 +4,6 @@ import android.os.Bundle
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import kotlinx.android.synthetic.main.fragment_rank.* import kotlinx.android.synthetic.main.fragment_rank.*
import kotlinx.android.synthetic.main.line_rank.view.* import kotlinx.android.synthetic.main.line_rank.view.*
import top.fumiama.copymanga.MainActivity
import top.fumiama.copymanga.template.ui.InfoCardLoader import top.fumiama.copymanga.template.ui.InfoCardLoader
import top.fumiama.copymanga.tools.api.CMApi import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.copymanga.tools.ui.UITools import top.fumiama.copymanga.tools.ui.UITools
@@ -13,7 +12,7 @@ import java.lang.Thread.sleep
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
@ExperimentalStdlibApi @ExperimentalStdlibApi
class RankFragment : InfoCardLoader(R.layout.fragment_rank, R.id.action_nav_rank_to_nav_book, true) { class RankFragment : InfoCardLoader(R.layout.fragment_rank, R.id.action_nav_rank_to_nav_book, isTypeBook = true) {
private val sortWay = listOf("day", "week", "month", "total") private val sortWay = listOf("day", "week", "month", "total")
private var sortValue = 0 private var sortValue = 0
private val audienceWay = listOf("", "male", "female") private val audienceWay = listOf("", "male", "female")

View File

@@ -2,9 +2,14 @@ package top.fumiama.copymanga.ui.cardflow.shelf
import android.animation.ObjectAnimator import android.animation.ObjectAnimator
import android.os.Bundle import android.os.Bundle
import android.view.View
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import kotlinx.android.synthetic.main.anchor_popular.view.* import kotlinx.android.synthetic.main.anchor_popular.view.*
import kotlinx.android.synthetic.main.line_shelf.* import kotlinx.android.synthetic.main.line_shelf.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import top.fumiama.copymanga.MainActivity import top.fumiama.copymanga.MainActivity
import top.fumiama.copymanga.template.ui.InfoCardLoader import top.fumiama.copymanga.template.ui.InfoCardLoader
import top.fumiama.copymanga.tools.api.CMApi import top.fumiama.copymanga.tools.api.CMApi
@@ -37,6 +42,7 @@ class ShelfFragment : InfoCardLoader(R.layout.fragment_shelf, R.id.action_nav_su
override fun setListeners() { override fun setListeners() {
super.setListeners() super.setListeners()
fade()
setUpdate() setUpdate()
setModify() setModify()
setBrowse() setBrowse()
@@ -46,20 +52,10 @@ class ShelfFragment : InfoCardLoader(R.layout.fragment_shelf, R.id.action_nav_su
if (ad?.exit == true) return if (ad?.exit == true) return
line_shelf_updated.apt.setText(R.string.menu_update_time) line_shelf_updated.apt.setText(R.string.menu_update_time)
line_shelf_updated.setOnClickListener { line_shelf_updated.setOnClickListener {
sortValue = if (it.apim.rotation == 0f) { val same = sortValue in 0..1
ObjectAnimator.ofFloat(it.apim, "rotation", 0f, 180f).setDuration(233).start() sortValue = rotate(it.apim, same, 0)
1 if (!same) fade()
} else { resetDelayed()
ObjectAnimator.ofFloat(it.apim, "rotation", 180f, 0f).setDuration(233).start()
0
}
Thread {
sleep(400)
activity?.runOnUiThread {
reset()
addPage()
}
}.start()
} }
} }
@@ -67,20 +63,10 @@ class ShelfFragment : InfoCardLoader(R.layout.fragment_shelf, R.id.action_nav_su
if (ad?.exit == true) return if (ad?.exit == true) return
line_shelf_modifier.apt.setText(R.string.menu_add_time) line_shelf_modifier.apt.setText(R.string.menu_add_time)
line_shelf_modifier.setOnClickListener { line_shelf_modifier.setOnClickListener {
sortValue = if (it.apim.rotation == 0f) { val same = sortValue in 2..3
ObjectAnimator.ofFloat(it.apim, "rotation", 0f, 180f).setDuration(233).start() sortValue = rotate(it.apim, same, 2)
3 if (!same) fade()
} else { resetDelayed()
ObjectAnimator.ofFloat(it.apim, "rotation", 180f, 0f).setDuration(233).start()
2
}
Thread {
sleep(400)
activity?.runOnUiThread {
reset()
addPage()
}
}.start()
} }
} }
@@ -88,20 +74,60 @@ class ShelfFragment : InfoCardLoader(R.layout.fragment_shelf, R.id.action_nav_su
if (ad?.exit == true) return if (ad?.exit == true) return
line_shelf_browse.apt.setText(R.string.menu_read_time) line_shelf_browse.apt.setText(R.string.menu_read_time)
line_shelf_browse.setOnClickListener { line_shelf_browse.setOnClickListener {
sortValue = if (it.apim.rotation == 0f) { val same = sortValue>=4
ObjectAnimator.ofFloat(it.apim, "rotation", 0f, 180f).setDuration(233).start() sortValue = rotate(it.apim, same, 4)
5 if (!same) fade()
resetDelayed()
}
}
private fun rotate(img: View, isSameSlot: Boolean, offset: Int): Int {
return if (isSameSlot) {
if (img.rotation == 0f) {
ObjectAnimator.ofFloat(img, "rotation", 0f, 180f).setDuration(233).start()
offset+1
} else { } else {
ObjectAnimator.ofFloat(it.apim, "rotation", 180f, 0f).setDuration(233).start() ObjectAnimator.ofFloat(img, "rotation", 180f, 0f).setDuration(233).start()
4 offset
} }
Thread { } else {
if (img.rotation == 0f) {
offset
} else {
offset+1
}
}
}
private fun fade() {
when(sortValue) {
0, 1 -> {
line_shelf_updated.alpha = 1f
line_shelf_modifier.alpha = 0.5f
line_shelf_browse.alpha = 0.5f
}
2, 3 -> {
line_shelf_updated.alpha = 0.5f
line_shelf_modifier.alpha = 1f
line_shelf_browse.alpha = 0.5f
}
4, 5 -> {
line_shelf_updated.alpha = 0.5f
line_shelf_modifier.alpha = 0.5f
line_shelf_browse.alpha = 1f
}
}
}
private fun resetDelayed() {
lifecycleScope.launch {
withContext(Dispatchers.IO) {
sleep(400) sleep(400)
activity?.runOnUiThread { withContext(Dispatchers.Main) {
reset() reset()
addPage() addPage()
} }
}.start() }
} }
} }
} }

View File

@@ -1,24 +1,22 @@
package top.fumiama.copymanga.ui.cardflow.sort package top.fumiama.copymanga.ui.cardflow.sort
import android.animation.ObjectAnimator import android.os.Bundle
import android.view.View
import com.github.zawadz88.materialpopupmenu.popupMenu import com.github.zawadz88.materialpopupmenu.popupMenu
import com.google.gson.Gson import com.google.gson.Gson
import kotlinx.android.synthetic.main.anchor_popular.view.* import kotlinx.android.synthetic.main.anchor_popular.view.*
import kotlinx.android.synthetic.main.line_sort.* import kotlinx.android.synthetic.main.line_sort.*
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
import top.fumiama.copymanga.json.FilterStructure import top.fumiama.copymanga.json.FilterStructure
import top.fumiama.copymanga.template.http.AutoDownloadThread import top.fumiama.copymanga.template.http.AutoDownloadThread
import top.fumiama.copymanga.template.ui.InfoCardLoader import top.fumiama.copymanga.template.ui.StatusCardFlow
import top.fumiama.copymanga.tools.api.CMApi import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.dmzj.copymanga.R import top.fumiama.dmzj.copymanga.R
import java.lang.Thread.sleep import java.lang.Thread.sleep
@ExperimentalStdlibApi @ExperimentalStdlibApi
class SortFragment : InfoCardLoader(R.layout.fragment_sort, R.id.action_nav_sort_to_nav_book) { class SortFragment : StatusCardFlow(0, R.id.action_nav_sort_to_nav_book, R.layout.fragment_sort) {
private val sortWay = listOf("-datetime_updated", "datetime_updated", "-popular", "popular")
private var theme = -1 private var theme = -1
private var region = -1 private var region = -1
private var sortValue = 0
private var filter: FilterStructure? = null private var filter: FilterStructure? = null
override fun getApiUrl() = override fun getApiUrl() =
@@ -30,10 +28,14 @@ class SortFragment : InfoCardLoader(R.layout.fragment_sort, R.id.action_nav_sort
if(region >= 0) (filter?.results?.top?.get(region)?.path_word ?: "") else "", if(region >= 0) (filter?.results?.top?.get(region)?.path_word ?: "") else "",
) )
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
lineUpdate = line_sort_time
lineHot = line_sort_hot
}
override fun setListeners() { override fun setListeners() {
super.setListeners() super.setListeners()
setUpdate()
setHot()
AutoDownloadThread(getString(R.string.filterApiUrl).format(CMApi.myHostApiUrl)) { AutoDownloadThread(getString(R.string.filterApiUrl).format(CMApi.myHostApiUrl)) {
if(ad?.exit == true) return@AutoDownloadThread if(ad?.exit == true) return@AutoDownloadThread
it?.let { it?.let {
@@ -46,27 +48,6 @@ class SortFragment : InfoCardLoader(R.layout.fragment_sort, R.id.action_nav_sort
}.start() }.start()
} }
private fun setUpdate(){
if(ad?.exit == true) return
line_sort_time.apt.setText(R.string.menu_update_time)
line_sort_time.setOnClickListener {
sortValue = if(it.apim.rotation == 0f) {
ObjectAnimator.ofFloat(it.apim, "rotation", 0f, 180f).setDuration(233).start()
1
}else{
ObjectAnimator.ofFloat(it.apim, "rotation", 180f, 0f).setDuration(233).start()
0
}
Thread{
sleep(400)
activity?.runOnUiThread {
reset()
addPage()
}
}.start()
}
}
private fun setClasses(){ private fun setClasses(){
filter?.results?.top?.let { items -> filter?.results?.top?.let { items ->
if(ad?.exit == true) return@let if(ad?.exit == true) return@let
@@ -153,25 +134,4 @@ class SortFragment : InfoCardLoader(R.layout.fragment_sort, R.id.action_nav_sort
} }
} }
} }
private fun setHot() {
if(ad?.exit == true) return
line_sort_hot.apt.setText(R.string.menu_hot)
line_sort_hot.setOnClickListener {
sortValue = if (it.apim.rotation == 0f) {
ObjectAnimator.ofFloat(it.apim, "rotation", 0f, 180f).setDuration(233).start()
3
} else {
ObjectAnimator.ofFloat(it.apim, "rotation", 180f, 0f).setDuration(233).start()
2
}
Thread {
sleep(400)
activity?.runOnUiThread {
reset()
addPage()
}
}.start()
}
}
} }

View File

@@ -4,7 +4,6 @@ import android.os.Bundle
import com.google.gson.Gson import com.google.gson.Gson
import kotlinx.android.synthetic.main.app_bar_main.* import kotlinx.android.synthetic.main.app_bar_main.*
import kotlinx.android.synthetic.main.fragment_topic.* import kotlinx.android.synthetic.main.fragment_topic.*
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
import top.fumiama.copymanga.json.TopicStructure import top.fumiama.copymanga.json.TopicStructure
import top.fumiama.copymanga.template.http.AutoDownloadThread import top.fumiama.copymanga.template.http.AutoDownloadThread
import top.fumiama.copymanga.template.ui.InfoCardLoader import top.fumiama.copymanga.template.ui.InfoCardLoader
@@ -23,12 +22,11 @@ class TopicFragment : InfoCardLoader(R.layout.fragment_topic, R.id.action_nav_to
if(ad?.exit == true) return@AutoDownloadThread if(ad?.exit == true) return@AutoDownloadThread
data?.apply { data?.apply {
val r = inputStream().reader() val r = inputStream().reader()
val topic = Gson().fromJson(r, TopicStructure::class.java) Gson().fromJson(r, TopicStructure::class.java)?.apply {
topic?.apply { if(ad?.exit == true) return@AutoDownloadThread
if(ad?.exit != false) return@AutoDownloadThread
activity?.let { activity?.let {
it.runOnUiThread { it.runOnUiThread {
if(ad?.exit != false) return@runOnUiThread if(ad?.exit == true) return@runOnUiThread
it.toolbar.title = results.title it.toolbar.title = results.title
ftttime.text = results.datetime_created ftttime.text = results.datetime_created
fttintro.text = results.intro fttintro.text = results.intro

View File

@@ -1,25 +1,24 @@
package top.fumiama.copymanga.ui.download package top.fumiama.copymanga.ui.download
import android.app.AlertDialog import android.app.AlertDialog
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.provider.DocumentsContract
import android.util.Log import android.util.Log
import android.view.View import android.view.View
import android.widget.Toast
import androidx.core.content.FileProvider
import androidx.core.net.toUri
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import kotlinx.android.synthetic.main.line_lazybooklines.* import kotlinx.android.synthetic.main.line_lazybooklines.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import top.fumiama.copymanga.MainActivity import top.fumiama.copymanga.MainActivity
import top.fumiama.copymanga.manga.Reader import top.fumiama.copymanga.manga.Reader
import top.fumiama.copymanga.template.general.MangaPagesFragmentTemplate import top.fumiama.copymanga.template.general.MangaPagesFragmentTemplate
import top.fumiama.copymanga.template.ui.CardList import top.fumiama.copymanga.template.ui.CardList
import top.fumiama.copymanga.tools.file.FileUtils
import top.fumiama.copymanga.tools.ui.Navigate import top.fumiama.copymanga.tools.ui.Navigate
import top.fumiama.copymanga.tools.ui.UITools import top.fumiama.copymanga.tools.ui.UITools
import top.fumiama.copymanga.tools.file.FileUtils
import top.fumiama.copymanga.ui.comicdl.ComicDlFragment import top.fumiama.copymanga.ui.comicdl.ComicDlFragment
import top.fumiama.dmzj.copymanga.R import top.fumiama.dmzj.copymanga.R
import java.io.File import java.io.File
@@ -64,49 +63,53 @@ class NewDownloadFragment: MangaPagesFragmentTemplate(R.layout.fragment_newdownl
page = 0 page = 0
isRefresh = false isRefresh = false
} }
if(!isEnd) { lifecycleScope.launch {
if(sortedBookList == null || isContentChanged) { withContext(Dispatchers.IO) {
Log.d("MyNDF", "Sorting books...") if(!isEnd) {
sortedBookList = extDir?.listFiles()?.sortedBy { if(sortedBookList == null || isContentChanged) {
return@sortedBy Reader.getComicPathWordInFile(it) Log.d("MyNDF", "Sorting books...")
} sortedBookList = extDir?.listFiles()?.sortedBy {
if (isReverse) { return@sortedBy Reader.getComicPathWordInFile(it)
Log.d("MyNDF", "reversed...") }
sortedBookList = sortedBookList?.asReversed() if (isReverse) {
} Log.d("MyNDF", "reversed...")
if (!showAll) { sortedBookList = sortedBookList?.asReversed()
sortedBookList = sortedBookList?.filter { }
return@filter FileUtils.sizeOf(it) / 1048576 > 0 if (!showAll) {
sortedBookList = sortedBookList?.filter {
return@filter FileUtils.sizeOf(it) / 1048576 > 0
}
}
isContentChanged = false
} }
} Log.d("MyNDF", "Start drawing cards")
isContentChanged = false cardList?.addCard(oldDlCardName, path = oldDlCardName)
} var cnt = 1
Log.d("MyNDF", "Start drawing cards") sortedBookList?.let {
cardList?.addCard(oldDlCardName, path = oldDlCardName) for(i in it.listIterator(page)) {
var cnt = 1 if(cardList?.exitCardList != false) return@withContext
sortedBookList?.let { page++ // page is actually count
for(i in it.listIterator(page)) { val chosenJson = File(i, "info.bin")
if(cardList?.exitCardList != false) return val newJson = File(i, "info.json")
page++ // page is actually count val bookSize = (FileUtils.sizeOf(i)/1048576).toInt()
val chosenJson = File(i, "info.bin") when {
val newJson = File(i, "info.json") chosenJson.exists() -> continue // unsupported old folder
val bookSize = (FileUtils.sizeOf(i)/1048576).toInt() newJson.exists() -> {
when { if(cardList?.exitCardList != false) return@withContext
chosenJson.exists() -> continue // unsupported old folder cardList?.addCard(i.name, "\n${bookSize}MB")
newJson.exists() -> { cnt++
if(cardList?.exitCardList != false) return }
cardList?.addCard(i.name, "\n${bookSize}MB") }
cnt++ if (cnt >= 21) break
}
if(page >= it.size) {
isEnd = true
} }
} }
if (cnt >= 21) break
}
if(page >= it.size) {
isEnd = true
} }
onLoadFinish()
} }
} }
onLoadFinish()
} }
override fun initCardList(weakReference: WeakReference<Fragment>) { override fun initCardList(weakReference: WeakReference<Fragment>) {
@@ -136,12 +139,14 @@ class NewDownloadFragment: MangaPagesFragmentTemplate(R.layout.fragment_newdownl
AlertDialog.Builder(context) AlertDialog.Builder(context)
.setIcon(R.drawable.ic_launcher_foreground).setMessage("删除下载的漫画${name}吗?") .setIcon(R.drawable.ic_launcher_foreground).setMessage("删除下载的漫画${name}吗?")
.setTitle("提示").setPositiveButton(android.R.string.ok) { _, _ -> .setTitle("提示").setPositiveButton(android.R.string.ok) { _, _ ->
if (chosenFile.exists()) Thread { if (chosenFile.exists()) lifecycleScope.launch {
FileUtils.recursiveRemove(chosenFile) withContext(Dispatchers.IO) {
activity?.runOnUiThread { FileUtils.recursiveRemove(chosenFile)
it.visibility = View.INVISIBLE withContext(Dispatchers.Main) {
it.visibility = View.INVISIBLE
}
} }
}.start() }
}.setNegativeButton(android.R.string.cancel) { _, _ -> } }.setNegativeButton(android.R.string.cancel) { _, _ -> }
.show() .show()
} }

View File

@@ -7,17 +7,17 @@ class SimpleKanban(private val client: Client, private val pwd: String) { //mu
get() { get() {
var times = 3 var times = 3
var re: ByteArray var re: ByteArray
var firstRecv: ByteArray var firstReceived: ByteArray
do { do {
re = byteArrayOf() re = byteArrayOf()
if(client.initConnect()) { if(client.initConnect()) {
client.sendMessage("${pwd}catquit") client.sendMessage("${pwd}catquit")
client.receiveRawMessage(33) //Welcome to simple kanban server. client.receiveRawMessage(33) //Welcome to simple kanban server.
try { try {
firstRecv = client.receiveRawMessage(4) //le firstReceived = client.receiveRawMessage(4) //le
val length = convert2Int(firstRecv) val length = convert2Int(firstReceived)
Log.d("MySK", "Msg len: $length") Log.d("MySK", "Msg len: $length")
if(firstRecv.size > 4) re += firstRecv.copyOfRange(4, firstRecv.size) if(firstReceived.size > 4) re += firstReceived.copyOfRange(4, firstReceived.size)
re += client.receiveRawMessage(length - re.size, setProgress = true) re += client.receiveRawMessage(length - re.size, setProgress = true)
break break
} catch (e: Exception) { } catch (e: Exception) {
@@ -35,9 +35,9 @@ class SimpleKanban(private val client: Client, private val pwd: String) { //mu
(buffer[1].toInt() and 0xff shl 8) or (buffer[1].toInt() and 0xff shl 8) or
(buffer[0].toInt() and 0xff) (buffer[0].toInt() and 0xff)
fun fetchRaw(doOnLoadFailure: ()->Unit = { suspend fun fetchRaw(doOnLoadFailure: suspend ()->Unit = {
Log.d("MySD", "Fetch dict failed") Log.d("MySD", "Fetch dict failed")
}, doOnLoadSuccess: (data: ByteArray)->Unit = { }, doOnLoadSuccess: suspend (data: ByteArray)->Unit = {
Log.d("MySD", "Fetch dict success") Log.d("MySD", "Fetch dict success")
}) { }) {
raw?.apply { raw?.apply {

View File

@@ -1,15 +1,21 @@
package top.fumiama.copymanga.update package top.fumiama.copymanga.update
import android.app.Activity import android.app.Activity
import android.content.Context
import android.content.Context.MODE_PRIVATE import android.content.Context.MODE_PRIVATE
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.util.Log import android.util.Log
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import androidx.core.content.edit import androidx.core.content.edit
import androidx.lifecycle.lifecycleScope
import kotlinx.android.synthetic.main.dialog_progress.view.* import kotlinx.android.synthetic.main.dialog_progress.view.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import top.fumiama.copymanga.tools.ui.UITools import top.fumiama.copymanga.tools.ui.UITools
import top.fumiama.dmzj.copymanga.BuildConfig import top.fumiama.dmzj.copymanga.BuildConfig
import top.fumiama.dmzj.copymanga.R import top.fumiama.dmzj.copymanga.R
@@ -17,8 +23,10 @@ import java.io.File
import java.security.MessageDigest import java.security.MessageDigest
object Update { object Update {
fun checkUpdate(activity: Activity, toolsBox: UITools, ignoreSkip: Boolean = false) = activity.apply{ suspend fun checkUpdate(activity: AppCompatActivity, toolsBox: UITools, ignoreSkip: Boolean = false) = activity.apply{
val client = Client("reilia.fumiama.top", 13212) val client = Client("reilia.fumiama.top", 13212)
val kanban = SimpleKanban(client, "fumiama")
val progressBar = layoutInflater.inflate(R.layout.dialog_progress, null, false) val progressBar = layoutInflater.inflate(R.layout.dialog_progress, null, false)
val progressHandler = object : Client.Progress{ val progressHandler = object : Client.Progress{
override fun notify(progressPercentage: Int) { override fun notify(progressPercentage: Int) {
@@ -26,69 +34,85 @@ object Update {
progressBar.dpp.progress = progressPercentage progressBar.dpp.progress = progressPercentage
} }
} }
val kanban = SimpleKanban(client, "fumiama")
val msg = kanban[BuildConfig.VERSION_CODE]
if(msg != "null") {
val verNum = msg.substringBefore('\n').toIntOrNull()
val skipNum = getPreferences(MODE_PRIVATE).getInt("skipVersion", 0)
Log.d("MyUP", "Ver:$verNum, skip: $skipNum") val msg = message(kanban)
if(verNum != null) { if (msg == "null") {
if(msg.contains("md5:")) { if(ignoreSkip) withContext(Dispatchers.Main) {
if(skipNum < verNum || ignoreSkip) runOnUiThread { Toast.makeText(this@apply, "无更新", Toast.LENGTH_SHORT).show()
toolsBox.buildInfo("看板", msg.substringAfter('\n').substringBeforeLast('\n'), "下载新版", "跳过该版", "取消", {
val info = toolsBox.buildAlertWithView("下载进度", progressBar, "隐藏")
client.progress = progressHandler
Thread {
kanban.fetchRaw({
runOnUiThread {
Toast.makeText(this, "下载失败", Toast.LENGTH_SHORT).show()
client.progress = null
}
}) {
val md5 = msg.substringAfterLast("md5:")
if (md5 == UITools.toHexStr(
MessageDigest.getInstance("MD5").digest(it)
)
) {
runOnUiThread {
Toast.makeText(this, "下载成功", Toast.LENGTH_SHORT).show()
info.dismiss()
}
val f = File(externalCacheDir, "new.apk")
f.writeBytes(it)
install(f, this)
} else runOnUiThread {
Toast.makeText(this, "文件损坏", Toast.LENGTH_SHORT).show()
info.dismiss()
}
client.progress = null
}
}.start()
}, {
getPreferences(MODE_PRIVATE).edit {
putInt("skipVersion", verNum)
apply()
}
})
}
} else runOnUiThread {
toolsBox.buildInfo("看板", msg.substringAfter('\n'), "知道了")
}
} }
} else if(ignoreSkip) runOnUiThread { return@apply
Toast.makeText(this, "无更新", Toast.LENGTH_SHORT).show() }
val verNum = msg.substringBefore('\n').toIntOrNull()
val skipNum = getPreferences(MODE_PRIVATE).getInt("skipVersion", 0)
Log.d("MyUP", "Ver:$verNum, skip: $skipNum")
if (verNum == null) return@apply
if(!msg.contains("md5:")) {
withContext(Dispatchers.Main) {
toolsBox.buildInfo("看板", msg.substringAfter('\n'), "知道了")
}
return@apply
}
if(skipNum < verNum || ignoreSkip) {
toolsBox.buildInfo("看板", msg.substringAfter('\n').substringBeforeLast('\n'), "下载新版", "跳过该版", "取消", {
val info = toolsBox.buildAlertWithView("下载进度", progressBar, "隐藏")
client.progress = progressHandler
lifecycleScope.launch {
fetch(client, kanban, this@apply) {
lifecycleScope.launch {
val md5 = msg.substringAfterLast("md5:")
if (md5 == UITools.toHexStr(
MessageDigest.getInstance("MD5").digest(it)
)
) {
Toast.makeText(this@apply, "下载成功", Toast.LENGTH_SHORT).show()
info.dismiss()
install(it, this@apply)
} else runOnUiThread {
Toast.makeText(this@apply, "文件损坏", Toast.LENGTH_SHORT).show()
info.dismiss()
}
client.progress = null
}
}
}
}, {
getPreferences(MODE_PRIVATE).edit {
putInt("skipVersion", verNum)
apply()
}
})
} }
} }
private fun install(apkFile: File, activity: Activity) = activity.apply{ private suspend fun message(kanban: SimpleKanban) = withContext(Dispatchers.IO) {
val intent = Intent(Intent.ACTION_VIEW) return@withContext kanban[BuildConfig.VERSION_CODE]
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
val contentUri: Uri = FileProvider.getUriForFile(this, "$packageName.fileprovider", apkFile)
intent.setDataAndType(contentUri, "application/vnd.android.package-archive")
} else intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive")
startActivity(intent)
} }
}
private suspend fun fetch(client: Client, kanban: SimpleKanban, context: Context, doOnLoadSuccess: (data: ByteArray) -> Unit) = withContext(Dispatchers.IO) {
return@withContext kanban.fetchRaw({ downloadFail(client, context) }, doOnLoadSuccess)
}
private suspend fun downloadFail(client: Client, context: Context) = withContext(Dispatchers.Main) {
Toast.makeText(context, R.string.download_apk_fail, Toast.LENGTH_SHORT).show()
client.progress = null
}
private suspend fun install(data: ByteArray, activity: Activity) = activity.apply{
withContext(Dispatchers.IO) {
val f = File(externalCacheDir, "new.apk")
f.writeBytes(data)
val intent = Intent(Intent.ACTION_VIEW)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
val contentUri: Uri = FileProvider.getUriForFile(this@apply, "$packageName.fileprovider", f)
intent.setDataAndType(contentUri, "application/vnd.android.package-archive")
} else intent.setDataAndType(Uri.fromFile(f), "application/vnd.android.package-archive")
withContext(Dispatchers.Main) {
startActivity(intent)
}
}
}
}

View File

@@ -11,7 +11,7 @@ import top.fumiama.dmzj.copymanga.R
class Member(private val pref: SharedPreferences, private val getString: (Int) -> String) { class Member(private val pref: SharedPreferences, private val getString: (Int) -> String) {
val hasLogin: Boolean get() = pref.getString("token", "")?.isNotEmpty()?:false val hasLogin: Boolean get() = pref.getString("token", "")?.isNotEmpty()?:false
suspend fun login(username: String, pwd: String, salt: Int): LoginInfoStructure = withContext(Dispatchers.IO) { suspend fun login(username: String, pwd: String, salt: Int): LoginInfoStructure = withContext(Dispatchers.IO) {
try { try {
CMApi.getLoginConnection(username, pwd, salt)?.apply { CMApi.getLoginConnection(username, pwd, salt)?.apply {
Gson().fromJson(inputStream.reader(), LoginInfoStructure::class.java)?.let { data -> Gson().fromJson(inputStream.reader(), LoginInfoStructure::class.java)?.let { data ->

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:fillColor="?attr/colorOnSurface"
android:pathData="M512 938.667c-235.637 0-426.667-191.03-426.667-426.667S276.363 85.333 512 85.333 938.667 276.363 938.667 512 747.637 938.667 512 938.667m0-64c200.299 0 362.667-162.368 362.667-362.667S712.299 149.333 512 149.333 149.333 311.701 149.333 512 311.701 874.667 512 874.667"/>
</vector>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:fillColor="?attr/colorOnSurface"
android:pathData="M512 938.667c-235.637 0-426.667-191.03-426.667-426.667S276.363 85.333 512 85.333 938.667 276.363 938.667 512 747.637 938.667 512 938.667m0-64c200.299 0 362.667-162.368 362.667-362.667S712.299 149.333 512 149.333 149.333 311.701 149.333 512 311.701 874.667 512 874.667m8.213-265.675-81.429-88.704-95.755 99.264a32 32 0 1 1-46.058-44.437L416.33 451.38a32 32 0 0 1 46.613.576l81.792 89.11 136.608-136.992a32 32 0 1 1 45.312 45.184L566.443 609.94a32 32 0 0 1-46.24-.96z"/>
</vector>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:fillColor="?attr/colorOnSurface"
android:pathData="M790.976 190.72a32 32 0 0 1 45.259-.021 457.25 457.25 0 0 1 134.432 324.416 457.25 457.25 0 0 1-134.294 324.277 32 32 0 1 1-45.258-45.248 393.26 393.26 0 0 0 115.552-279.03 393.26 393.26 0 0 0-115.68-279.146 32 32 0 0 1 0-45.259zm-603.36.128a32 32 0 0 1 45.27 45.248 393.26 393.26 0 0 0-115.553 279.019A393.26 393.26 0 0 0 232.8 794.059a32 32 0 0 1-45.28 45.237A457.25 457.25 0 0 1 53.333 515.115a457.25 457.25 0 0 1 134.294-324.267zm143.179 95.019a32 32 0 0 1 .032 45.248A255.04 255.04 0 0 0 256 512a255.05 255.05 0 0 0 75.147 181.184 32 32 0 1 1-45.216 45.301A319.04 319.04 0 0 1 192 512a319.04 319.04 0 0 1 93.547-226.09 32 32 0 0 1 45.248-.033zm407.36-.267A319.04 319.04 0 0 1 832 512a319.04 319.04 0 0 1-93.653 226.208 32 32 0 0 1-45.28-45.237A255.05 255.05 0 0 0 768 512a255.05 255.05 0 0 0-75.072-181.12 32 32 0 1 1 45.227-45.27zM566.752 384c70.656 0 115.915 57.173 115.915 130.923 0 58.005-47.947 116.789-140.096 181.237a53.33 53.33 0 0 1-61.142 0c-92.149-64.448-140.096-123.232-140.096-181.237 0-73.75 45.259-130.923 115.926-130.923 21.632 0 37.514 5.995 54.741 18.421C529.227 389.995 545.11 384 566.741 384zm0 64c-8.32 0-14.56 3.328-27.52 14.539l-6.336 5.504a32 32 0 0 1-41.77 0l-6.337-5.504c-12.96-11.2-19.2-14.539-27.52-14.539-31.616 0-51.936 25.675-51.936 66.923 0 29.941 34.411 72.938 106.667 124.48 72.256-51.542 106.667-94.539 106.667-124.48 0-41.248-20.32-66.923-51.926-66.923z"/>
</vector>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:fillColor="?attr/colorOnSurface"
android:pathData="M938.667 553.92V768c0 64.8-52.534 117.333-117.334 117.333H202.667c-64.8 0-117.334-52.533-117.334-117.333V256c0-64.8 52.534-117.333 117.334-117.333h618.666c64.8 0 117.334 52.533 117.334 117.333zm-64-74.624V256a53.333 53.333 0 0 0-53.334-53.333H202.667A53.333 53.333 0 0 0 149.333 256v344.48A290 290 0 0 1 192 597.333a286.88 286.88 0 0 1 183.296 65.846C427.029 528.384 556.906 437.333 704 437.333c65.707 0 126.997 16.779 170.667 41.963m0 82.24c-5.334-8.32-21.131-21.653-43.648-32.917-34.251-17.131-77.974-27.286-127.019-27.286-121.77 0-229.13 76.267-270.432 188.694-2.73 7.445-7.403 20.32-13.995 38.581-7.68 21.301-34.453 28.107-51.37 13.056-16.438-14.635-28.555-25.067-36.139-31.147A222.9 222.9 0 0 0 192 661.333a225 225 0 0 0-42.667 4.054V768a53.333 53.333 0 0 0 53.334 53.333h618.666A53.333 53.333 0 0 0 874.667 768V561.525zM320 480a96 96 0 1 1 0-192 96 96 0 0 1 0 192m0-64a32 32 0 1 0 0-64 32 32 0 0 0 0 64"/>
</vector>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:fillColor="?attr/colorOnSurface"
android:pathData="M878.08 731.275a32 32 0 0 1-54.88-32.939A360.8 360.8 0 0 0 874.667 512c0-200.299-162.368-362.667-362.667-362.667S149.333 311.701 149.333 512 311.701 874.667 512 874.667a360.8 360.8 0 0 0 186.315-51.446 32 32 0 0 1 32.928 54.88A424.8 424.8 0 0 1 512 938.667c-235.637 0-426.667-191.03-426.667-426.667S276.363 85.333 512 85.333 938.667 276.363 938.667 512c0 78.293-21.152 153.568-60.587 219.275M374.581 489.45l84.342 83.989 190.432-190.72a32 32 0 0 1 45.29 45.227L481.632 641.28a32 32 0 0 1-45.227.064L329.42 534.794a32 32 0 1 1 45.162-45.343"/>
</vector>

View File

@@ -78,7 +78,6 @@
android:layout_marginEnd="16dp" android:layout_marginEnd="16dp"
android:layout_marginBottom="4dp" android:layout_marginBottom="4dp"
android:gravity="center_horizontal" android:gravity="center_horizontal"
android:text="获取标题失败"
android:textAppearance="@style/TextAppearance.AppCompat.Body1" android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:textColor="@android:color/white" android:textColor="@android:color/white"
android:textSize="12sp" android:textSize="12sp"

View File

@@ -16,29 +16,30 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/nav_header_vertical_spacing" android:layout_margin="@dimen/nav_header_vertical_spacing"
app:layout_constraintBottom_toTopOf="@id/fbov" app:layout_constraintBottom_toTopOf="@id/fbvp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_scrollFlags="scroll|enterAlways" /> app:layout_scrollFlags="scroll|exitUntilCollapsed" />
<com.google.android.material.tabs.TabLayout
android:id="@+id/fbtab"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_scrollFlags="scroll"/>
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView <androidx.viewpager2.widget.ViewPager2
android:id="@+id/fbov" android:id="@+id/fbvp"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" android:isScrollContainer="true"
android:nestedScrollingEnabled="true"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/fbiinf"> app:layout_constraintTop_toBottomOf="@+id/fbiinf"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
<LinearLayout
android:id="@+id/fbl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</androidx.core.widget.NestedScrollView>
<com.airbnb.lottie.LottieAnimationView <com.airbnb.lottie.LottieAnimationView
android:id="@+id/fbloading" android:id="@+id/fbloading"

View File

@@ -27,22 +27,32 @@
layout="@layout/card_book" layout="@layout/card_book"
android:layout_width="@dimen/book_card_width" android:layout_width="@dimen/book_card_width"
android:layout_height="0dp" android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="@+id/lbitb"
app:layout_constraintEnd_toStartOf="@+id/lbitb" app:layout_constraintEnd_toStartOf="@+id/lbitb"
app:layout_constraintHorizontal_weight="1" app:layout_constraintHorizontal_weight="1"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintVertical_bias="0.499" />
<include <include
android:id="@+id/lbitb" android:id="@+id/lbitb"
layout="@layout/line_booktandb" layout="@layout/line_booktandb"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="@dimen/nav_header_height" android:layout_height="@dimen/nav_header_height"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_weight="2" app:layout_constraintHorizontal_weight="2"
app:layout_constraintStart_toEndOf="@+id/lbc" app:layout_constraintStart_toEndOf="@+id/lbc"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="@+id/lbl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/lbitb"></LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView> </androidx.cardview.widget.CardView>

View File

@@ -20,7 +20,7 @@
android:layout_width="@dimen/icon_size_small" android:layout_width="@dimen/icon_size_small"
android:layout_height="@dimen/icon_size_small" android:layout_height="@dimen/icon_size_small"
android:layout_marginBottom="@dimen/nav_header_vertical_spacing" android:layout_marginBottom="@dimen/nav_header_vertical_spacing"
android:background="@drawable/ic_list" android:background="@drawable/ic_data"
app:layout_constraintBottom_toTopOf="@+id/bitime" app:layout_constraintBottom_toTopOf="@+id/bitime"
app:layout_constraintEnd_toStartOf="@+id/btsub" app:layout_constraintEnd_toStartOf="@+id/btsub"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
@@ -61,7 +61,7 @@
android:layout_width="@dimen/icon_size_small" android:layout_width="@dimen/icon_size_small"
android:layout_height="@dimen/icon_size_small" android:layout_height="@dimen/icon_size_small"
android:layout_marginBottom="@dimen/nav_header_vertical_spacing" android:layout_marginBottom="@dimen/nav_header_vertical_spacing"
android:background="@drawable/ic_list" android:background="@drawable/ic_image"
app:layout_constraintBottom_toTopOf="@+id/bihit" app:layout_constraintBottom_toTopOf="@+id/bihit"
app:layout_constraintEnd_toStartOf="@+id/bttag" app:layout_constraintEnd_toStartOf="@+id/bttag"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
@@ -82,7 +82,7 @@
android:layout_width="@dimen/icon_size_small" android:layout_width="@dimen/icon_size_small"
android:layout_height="@dimen/icon_size_small" android:layout_height="@dimen/icon_size_small"
android:layout_marginBottom="@dimen/nav_header_vertical_spacing" android:layout_marginBottom="@dimen/nav_header_vertical_spacing"
android:background="@drawable/ic_list" android:background="@drawable/ic_hot"
app:layout_constraintBottom_toTopOf="@+id/bisub" app:layout_constraintBottom_toTopOf="@+id/bisub"
app:layout_constraintEnd_toStartOf="@+id/bthit" app:layout_constraintEnd_toStartOf="@+id/bthit"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
@@ -103,7 +103,7 @@
android:layout_width="@dimen/icon_size_small" android:layout_width="@dimen/icon_size_small"
android:layout_height="@dimen/icon_size_small" android:layout_height="@dimen/icon_size_small"
android:layout_marginBottom="@dimen/nav_header_vertical_spacing" android:layout_marginBottom="@dimen/nav_header_vertical_spacing"
android:background="@drawable/ic_author" android:background="@drawable/ic_locate"
app:layout_constraintBottom_toTopOf="@+id/bitag" app:layout_constraintBottom_toTopOf="@+id/bitag"
app:layout_constraintEnd_toStartOf="@+id/btauth" app:layout_constraintEnd_toStartOf="@+id/btauth"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"

View File

@@ -15,7 +15,7 @@
android:layout_marginStart="@dimen/nav_header_vertical_spacing" android:layout_marginStart="@dimen/nav_header_vertical_spacing"
android:layout_marginTop="@dimen/nav_header_vertical_spacing" android:layout_marginTop="@dimen/nav_header_vertical_spacing"
android:layout_marginBottom="@dimen/nav_header_vertical_spacing" android:layout_marginBottom="@dimen/nav_header_vertical_spacing"
android:background="@drawable/ic_list" android:background="@drawable/ic_circle"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0" app:layout_constraintHorizontal_bias="0.0"

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/fbl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</androidx.core.widget.NestedScrollView>

View File

@@ -224,7 +224,7 @@
<fragment <fragment
android:id="@+id/nav_newest" android:id="@+id/nav_newest"
android:name="top.fumiama.copymanga.ui.cardflow.search.SearchFragment" android:name="top.fumiama.copymanga.ui.cardflow.newest.NewestFragment"
android:label="@string/new_list" android:label="@string/new_list"
tools:layout="@layout/fragment_newest" > tools:layout="@layout/fragment_newest" >
<action <action

View File

@@ -13,7 +13,7 @@
<string name="menu_home">主页</string> <string name="menu_home">主页</string>
<string name="menu_sort">分类</string> <string name="menu_sort">分类</string>
<string name="menu_rank">排行</string> <string name="menu_rank">排行</string>
<string name="app_description">©20222023源文雨\n本应用为拷贝漫画的第三方客户端数据均来源于网络作者不对其中所呈现的任何内容负责。</string> <string name="app_description">©20222024源文雨\n本应用为拷贝漫画的第三方客户端数据均来源于网络作者不对其中所呈现的任何内容负责。</string>
<string name="menu_history">浏览历史</string> <string name="menu_history">浏览历史</string>
<string name="menu_sub">我的订阅</string> <string name="menu_sub">我的订阅</string>
<string name="menu_download">我的下载</string> <string name="menu_download">我的下载</string>
@@ -29,6 +29,9 @@
<string name="navTextInfo">illust: Hiten(490219)</string> <string name="navTextInfo">illust: Hiten(490219)</string>
<string name="navTextInfoInputHint">请设定提示文字内容</string> <string name="navTextInfoInputHint">请设定提示文字内容</string>
<string name="clearHeadImgMsg">清除设定的图片?</string> <string name="clearHeadImgMsg">清除设定的图片?</string>
<string name="err_pick_img">选取图片失败</string>
<string name="err_crop_img">裁剪图片失败</string>
<string name="download_apk_fail">下载更新失败</string>
<string name="login">登录</string> <string name="login">登录</string>
<string name="logout">注销</string> <string name="logout">注销</string>
@@ -112,7 +115,9 @@
<string name="text_format_hit">热度 %1$d</string> <string name="text_format_hit">热度 %1$d</string>
<string name="text_format_stat">状态 %1$s</string> <string name="text_format_stat">状态 %1$s</string>
<string name="text_format_cloud_read_to">云端读到 %1$s</string> <string name="text_format_region">区域 %1$s</string>
<string name="text_format_img_type">画幅 %1$s</string>
<string name="text_format_cloud_read_to">云读至%1$s</string>
<string name="topics_series">专题系列</string> <string name="topics_series">专题系列</string>
<string name="manga_rec">漫画推荐</string> <string name="manga_rec">漫画推荐</string>

View File

@@ -10,7 +10,7 @@ buildscript {
maven { url "https://jitpack.io" } maven { url "https://jitpack.io" }
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:8.1.1' classpath 'com.android.tools.build:gradle:8.2.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
@@ -27,6 +27,6 @@ allprojects {
} }
} }
task clean(type: Delete) { tasks.register('clean', Delete) {
delete rootProject.buildDir delete rootProject.buildDir
} }

View File

@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-all.zip