1
0
mirror of https://github.com/fumiama/copymanga.git synced 2026-07-02 08:40:25 +08:00

2.0.beta8

1. 增加搜索
2. 升级sdk、api
3. 优化更新
This commit is contained in:
fumiama
2022-01-18 16:23:22 +08:00
parent d94675a1b7
commit babfcac664
27 changed files with 507 additions and 117 deletions

5
.idea/gradle.xml generated
View File

@@ -4,10 +4,10 @@
<component name="GradleSettings"> <component name="GradleSettings">
<option name="linkedExternalProjectsSettings"> <option name="linkedExternalProjectsSettings">
<GradleProjectSettings> <GradleProjectSettings>
<option name="testRunner" value="PLATFORM" /> <option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" /> <option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="1.8" /> <option name="gradleJvm" value="11" />
<option name="modules"> <option name="modules">
<set> <set>
<option value="$PROJECT_DIR$" /> <option value="$PROJECT_DIR$" />
@@ -15,7 +15,6 @@
</set> </set>
</option> </option>
<option name="resolveModulePerSourceSet" value="false" /> <option name="resolveModulePerSourceSet" value="false" />
<option name="useQualifiedModuleNames" value="true" />
</GradleProjectSettings> </GradleProjectSettings>
</option> </option>
</component> </component>

28
.idea/misc.xml generated
View File

@@ -1,6 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK"> <component name="DesignSurface">
<option name="filePathToZoomLevelMap">
<map>
<entry key="app/src/main/res/drawable-anydpi/ic_like.xml" value="0.5572916666666666" />
<entry key="app/src/main/res/drawable-anydpi/ic_setting_search.xml" value="0.5572916666666666" />
<entry key="app/src/main/res/layout/activity_login.xml" value="0.49592391304347827" />
<entry key="app/src/main/res/layout/activity_main.xml" value="0.5095108695652174" />
<entry key="app/src/main/res/layout/app_bar_main.xml" value="0.5095108695652174" />
<entry key="app/src/main/res/layout/card_book.xml" value="0.49592391304347827" />
<entry key="app/src/main/res/layout/card_book_plain.xml" value="0.49592391304347827" />
<entry key="app/src/main/res/layout/content_main.xml" value="0.49592391304347827" />
<entry key="app/src/main/res/layout/fragment_book.xml" value="0.49592391304347827" />
<entry key="app/src/main/res/layout/fragment_chapters.xml" value="0.49592391304347827" />
<entry key="app/src/main/res/layout/fragment_download.xml" value="0.49592391304347827" />
<entry key="app/src/main/res/layout/fragment_home.xml" value="0.5095108695652174" />
<entry key="app/src/main/res/layout/line_1bookline.xml" value="0.49592391304347827" />
<entry key="app/src/main/res/layout/line_bookinfo.xml" value="0.49592391304347827" />
<entry key="app/src/main/res/layout/line_choice_list.xml" value="0.49592391304347827" />
<entry key="app/src/main/res/layout/line_text_info.xml" value="0.49592391304347827" />
<entry key="app/src/main/res/layout/line_word.xml" value="0.49592391304347827" />
<entry key="app/src/main/res/layout/viewpage_banner.xml" value="0.49592391304347827" />
<entry key="app/src/main/res/layout/viewpage_horizonal.xml" value="0.49592391304347827" />
<entry key="app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml" value="0.5572916666666666" />
</map>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" /> <output url="file://$PROJECT_DIR$/build/classes" />
</component> </component>
<component name="ProjectType"> <component name="ProjectType">

View File

@@ -1,13 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="com.android.tools.idea.compose.preview.runconfiguration.ComposePreviewRunConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
</set>
</option>
</component>
</project>

View File

@@ -21,11 +21,14 @@
# 2. 新版(2.0+) # 2. 新版(2.0+)
1. 官方在某段时间关闭`H5`后(现已重新打开),从`2.0`版本开始,本应用进行了全新升级。 1. 官方在某段时间关闭`H5`后(现已重新打开),从`2.0`版本开始,本应用进行了全新升级。
2. 新版使用`Material Design`配合官方`APP``API` 2. 新版使用`Material Design`配合官方`APP``API`
3. 本应用默认使用海外线路。
### 功能 ### 功能
1. 浏览主页、分类、排行,查看漫画并阅读 1. 浏览主页、分类、排行、我的下载、标签、作者
2. 下载漫画。但是由于不可抗力,下载速度较慢且容易出错,这绝对不是优化的原因,绝对不是 2. 查看、搜索漫画并直接阅读
3. 阅读下载漫画。 3. 下载漫画。但是由于不可抗力,下载速度较慢且容易出错,这绝对不是优化的原因,绝对不是。
4. 阅读下载的漫画。
5. 检查更新。
### 未实现功能 ### 未实现功能
未在上表列出的官方`APP`的其他功能。 未在上表列出的官方`APP`的其他功能。

View File

@@ -22,14 +22,14 @@ android {
v2SigningEnabled true v2SigningEnabled true
}*/ }*/
} }
compileSdkVersion 30 compileSdkVersion 31
defaultConfig { defaultConfig {
applicationId 'top.fumiama.copymanga' applicationId 'top.fumiama.copymanga'
minSdkVersion 23 minSdkVersion 23
targetSdkVersion 30 targetSdkVersion 31
versionCode 18 versionCode 19
versionName '2.0.beta7' versionName '2.0.beta8'
resConfigs "zh", "zh-rCN" resConfigs "zh", "zh-rCN"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@@ -60,7 +60,7 @@ android {
targetCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8
} }
kotlinOptions { kotlinOptions {
jvmTarget = '1.8' jvmTarget = '11'
} }
bundle{ bundle{
density{ density{
@@ -75,18 +75,18 @@ android {
dependencies { dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"]) implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.2' implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'androidx.appcompat:appcompat:1.4.1'
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.3.0' implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4' implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5' implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5'
implementation 'androidx.navigation:navigation-ui-ktx:2.3.5' implementation 'androidx.navigation:navigation-ui-ktx:2.3.5'
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5' implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5'
implementation 'androidx.navigation:navigation-ui-ktx:2.3.5' implementation 'androidx.navigation:navigation-ui-ktx:2.3.5'
testImplementation 'junit:junit:4.13.2' testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
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'
@@ -96,6 +96,7 @@ dependencies {
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'
} }
andResGuard { andResGuard {

View File

@@ -26,7 +26,8 @@
<activity <activity
android:name="top.fumiama.copymanga.MainActivity" android:name="top.fumiama.copymanga.MainActivity"
android:label="@string/app_name" android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar"> android:theme="@style/AppTheme.NoActionBar"
android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
@@ -39,7 +40,7 @@
android:theme="@style/AppTheme.NoActionBar"/> android:theme="@style/AppTheme.NoActionBar"/>
<activity <activity
android:name="com.yalantis.ucrop.UCropActivity" android:name="com.yalantis.ucrop.UCropActivity"
android:screenOrientation="portrait" android:screenOrientation="fullSensor"
android:theme="@style/Theme.AppCompat.Light.NoActionBar"/> android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>
<activity <activity
android:name="top.fumiama.copymanga.ui.vm.ViewMangaActivity" android:name="top.fumiama.copymanga.ui.vm.ViewMangaActivity"

View File

@@ -1,6 +1,7 @@
package top.fumiama.copymanga package top.fumiama.copymanga
import android.Manifest import android.Manifest
import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.graphics.Bitmap import android.graphics.Bitmap
@@ -13,6 +14,7 @@ import android.util.Log
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.TextView import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
@@ -42,7 +44,6 @@ import java.io.File
import java.io.FileInputStream import java.io.FileInputStream
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
var isDrawerClosed = true var isDrawerClosed = true
var menuMain: Menu? = null var menuMain: Menu? = null
@@ -93,6 +94,8 @@ class MainActivity : AppCompatActivity() {
override fun onDrawerStateChanged(newState: Int) {} override fun onDrawerStateChanged(newState: Int) {}
}) })
checkUpdate(false) checkUpdate(false)
ime = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
} }
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
@@ -144,6 +147,7 @@ class MainActivity : AppCompatActivity() {
permissions: Array<String?>, permissions: Array<String?>,
grantResults: IntArray grantResults: IntArray
) { ) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when (requestCode) { when (requestCode) {
1 -> { 1 -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) pickPicture() if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) pickPicture()
@@ -272,5 +276,6 @@ class MainActivity : AppCompatActivity() {
companion object{ companion object{
var mainWeakReference: WeakReference<MainActivity>? = null var mainWeakReference: WeakReference<MainActivity>? = null
var ime: InputMethodManager? = null
} }
} }

View File

@@ -14,6 +14,7 @@ public class IndexStructure extends ReturnBase {
public FinishComics finishComics; public FinishComics finishComics;
public static class Banners{ public static class Banners{
public int type;
public String cover; public String cover;
public String brief; public String brief;
public String out_uuid; public String out_uuid;

View File

@@ -42,7 +42,7 @@ object DownloadTools {
refer?.let { setRequestProperty("referer", it) } refer?.let { setRequestProperty("referer", it) }
setRequestProperty("source", "copyApp") setRequestProperty("source", "copyApp")
setRequestProperty("webp", "1") setRequestProperty("webp", "1")
setRequestProperty("region", "1") setRequestProperty("region", "0")
setRequestProperty("platform", "3") setRequestProperty("platform", "3")
ua?.let { setRequestProperty("User-agent", it) } ua?.let { setRequestProperty("User-agent", it) }

View File

@@ -1,18 +1,35 @@
package top.fumiama.copymanga.ui.home package top.fumiama.copymanga.ui.home
import android.annotation.SuppressLint
import android.app.AlertDialog
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ArrayAdapter
import android.widget.ImageButton
import androidx.appcompat.view.ContextThemeWrapper
import androidx.navigation.Navigation import androidx.navigation.Navigation
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView 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.google.gson.Gson
import com.lapism.search.internal.SearchLayout
import kotlinx.android.synthetic.main.card_book_plain.view.*
import kotlinx.android.synthetic.main.fragment_home.* import kotlinx.android.synthetic.main.fragment_home.*
import kotlinx.android.synthetic.main.line_text_info.view.*
import kotlinx.android.synthetic.main.line_word.view.*
import kotlinx.android.synthetic.main.viewpage_horizonal.view.* import kotlinx.android.synthetic.main.viewpage_horizonal.view.*
import top.fumiama.dmzj.copymanga.R import top.fumiama.copymanga.MainActivity.Companion.ime
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
import top.fumiama.copymanga.json.BookListStructure
import top.fumiama.copymanga.template.general.NoBackRefreshFragment import top.fumiama.copymanga.template.general.NoBackRefreshFragment
import top.fumiama.copymanga.template.http.AutoDownloadThread
import top.fumiama.copymanga.tools.api.CMApi import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.dmzj.copymanga.R
import java.lang.Thread.sleep import java.lang.Thread.sleep
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
@@ -32,6 +49,78 @@ class HomeFragment : NoBackRefreshFragment(R.layout.fragment_home) {
homeHandler.obtainMessage(-1, true).sendToTarget() homeHandler.obtainMessage(-1, true).sendToTarget()
while(mainWeakReference?.get()?.isDrawerClosed != true) sleep(233) while(mainWeakReference?.get()?.isDrawerClosed != true) sleep(233)
//homeHandler.sendEmptyMessage(6) //removeAllViews //homeHandler.sendEmptyMessage(6) //removeAllViews
fhs.apply {
val recyclerView = findViewById<RecyclerView>(R.id.search_recycler_view)
setAdapterLayoutManager(LinearLayoutManager(context))
val adapter = ListViewHolder(recyclerView).RecyclerViewAdapter()
setAdapter(adapter)
navigationIconSupport = SearchLayout.NavigationIconSupport.SEARCH
setMicIconImageResource(R.drawable.ic_setting_search)
val micView = findViewById<ImageButton>(R.id.search_image_view_mic)
setClearFocusOnBackPressed(true)
setOnNavigationClickListener(object : SearchLayout.OnNavigationClickListener {
override fun onNavigationClick(hasFocus: Boolean) {
if (hasFocus()) {
clearFocus()
}
else requestFocus()
}
})
setTextHint(android.R.string.search_go)
setOnQueryTextListener(object : SearchLayout.OnQueryTextListener {
var lastChangeTime = 0L
override fun onQueryTextChange(newText: CharSequence): Boolean {
postDelayed({
val diff = System.currentTimeMillis() - lastChangeTime
if(diff > 500) {
if (newText.isNotEmpty()) adapter.refresh(newText)
}
}, 1024)
lastChangeTime = System.currentTimeMillis()
return true
}
override fun onQueryTextSubmit(query: CharSequence): Boolean {
/*if(query.isNotEmpty()) {
val key = query.toString()
Toast.makeText(context, key, Toast.LENGTH_SHORT).show()
}*/
return true
}
})
setOnMicClickListener(object : SearchLayout.OnMicClickListener {
val types = arrayOf("", "name", "author", "local")
var i = 0
override fun onMicClick() {
val typenames = resources.getStringArray(R.array.search_types)
AlertDialog.Builder(ContextThemeWrapper(context, R.style.AlertDialogTheme))
.setTitle(R.string.set_search_types)
.setIcon(R.mipmap.ic_launcher)
.setSingleChoiceItems(ArrayAdapter(context, R.layout.line_choice_list, typenames), i){ d, p ->
adapter.type = types[p]
i = p
d.cancel()
}.show()
}
})
setOnFocusChangeListener(object : SearchLayout.OnFocusChangeListener {
override fun onFocusChange(hasFocus: Boolean) {
navigationIconSupport = if (hasFocus) SearchLayout.NavigationIconSupport.ARROW
else {
micView.postDelayed({ micView.visibility = View.VISIBLE }, 233)
SearchLayout.NavigationIconSupport.SEARCH
}
}
})
fhns.setOnTouchListener { _, e ->
if (e.action == MotionEvent.ACTION_UP && mSearchEditText?.text?.isNotEmpty() == true) {
ime?.hideSoftInputFromWindow(mainWeakReference?.get()?.window?.decorView?.windowToken, 0)
}
false
}
}
homeHandler.fhib = null homeHandler.fhib = null
sleep(600) sleep(600)
homeHandler.startLoad() homeHandler.startLoad()
@@ -75,4 +164,53 @@ class HomeFragment : NoBackRefreshFragment(R.layout.fragment_home) {
override fun getItemCount(): Int = homeHandler.index?.results?.banners?.size?:0 override fun getItemCount(): Int = homeHandler.index?.results?.banners?.size?:0
} }
} }
inner class ListViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
inner class RecyclerViewAdapter :
RecyclerView.Adapter<ListViewHolder>() {
private var results: BookListStructure? = null
var type = ""
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListViewHolder {
return ListViewHolder(
LayoutInflater.from(parent.context)
.inflate(R.layout.line_word, parent, false)
)
}
@SuppressLint("ClickableViewAccessibility", "SetTextI18n")
override fun onBindViewHolder(holder: ListViewHolder, position: Int) {
Log.d("MyMain", "Bind open at $position")
results?.results?.list?.get(position)?.apply {
holder.itemView.tn.text = name
holder.itemView.ta.text = author.let {
var t = ""
it.forEach { ts ->
t += ts.name + " "
}
return@let t
}
holder.itemView.tb.text = popular.toString()
context?.let {
Glide.with(it).load(GlideUrl(cover, CMApi.myGlideHeaders)).into(holder.itemView.imic)
}
holder.itemView.lwc.setOnClickListener {
val bundle = Bundle()
bundle.putString("path", path_word)
rootView?.let { r -> Navigation.findNavController(r).navigate(R.id.action_nav_home_to_nav_book, bundle) }
}
}
}
override fun getItemCount() = results?.results?.list?.size?:0
fun refresh(query: CharSequence) {
mainWeakReference?.get()?.apply {
AutoDownloadThread(String.format(getString(R.string.searchApiUrl), 0, query, type)) {
results = Gson().fromJson(it?.decodeToString(), BookListStructure::class.java)
runOnUiThread { notifyDataSetChanged() }
}.start()
}
}
}
}
} }

View File

@@ -81,6 +81,13 @@ class HomeHandler(that: WeakReference<HomeFragment>) : AutoDownloadHandler(
override fun setGsonItem(gsonObj: Any) { override fun setGsonItem(gsonObj: Any) {
super.setGsonItem(gsonObj) super.setGsonItem(gsonObj)
index = gsonObj as IndexStructure index = gsonObj as IndexStructure
var banners = arrayOf<IndexStructure.Results.Banners>()
index?.results?.banners?.forEach {
if(it.type == 1) {
banners += it
}
}
index?.results?.banners = banners
} }
override fun onError() { override fun onError() {
super.onError() super.onError()

View File

@@ -0,0 +1,27 @@
package top.fumiama.copymanga.update
//Fumiama 20210601
//ByteArrayQueue.kt
//FIFO队列
class ByteArrayQueue {
private var elements = byteArrayOf()
val size get() = elements.size
fun append(items: ByteArray) {
elements += items
}
fun pop(num: Int = 1): ByteArray? {
return if(num <= elements.size) {
val re = elements.copyOfRange(0, num)
elements = elements.copyOfRange(num, elements.size)
re
} else null
}
fun clear() {
elements = byteArrayOf()
}
fun popAll(): ByteArray {
val re = elements
clear()
return re
}
operator fun plusAssign(items: ByteArray) = append(items)
}

View File

@@ -1,9 +1,9 @@
package top.fumiama.copymanga.update package top.fumiama.copymanga.update
//Fumiama 20210601
//Client.kt
import android.util.Log import android.util.Log
import java.io.IOException import java.io.*
import java.io.InputStream import java.lang.Thread.sleep
import java.io.OutputStream
import java.net.Socket import java.net.Socket
class Client(private val ip: String, private val port: Int) { class Client(private val ip: String, private val port: Int) {
@@ -26,7 +26,7 @@ class Client(private val ip: String, private val port: Int) {
sc = Socket(ip, port) //通过socket连接服务器 sc = Socket(ip, port) //通过socket连接服务器
din = sc?.getInputStream() //获取输入流并转换为StreamReader约定编码格式 din = sc?.getInputStream() //获取输入流并转换为StreamReader约定编码格式
dout = sc?.getOutputStream() //获取输出流 dout = sc?.getOutputStream() //获取输出流
sc?.soTimeout = 2333 //设置连接超时限制 sc?.soTimeout = 10000 //设置连接超时限制
return if (isConnect) { return if (isConnect) {
Log.d("MyC", "connect server successful") Log.d("MyC", "connect server successful")
true true
@@ -44,13 +44,15 @@ class Client(private val ip: String, private val port: Int) {
* 发送数据至服务器 * 发送数据至服务器
* @param message 要发送至服务器的字符串 * @param message 要发送至服务器的字符串
*/ */
fun sendMessage(message: CharSequence?): Boolean { fun sendMessage(message: String?): Boolean = sendMessage(message?.toByteArray())
fun sendMessage(message: ByteArray?): Boolean {
try { try {
if (isConnect) { if (isConnect) {
if (message != null) { //判断输出流或者消息是否为空为空的话会产生nullpoint错误 if (message != null) { //判断输出流或者消息是否为空为空的话会产生null pointer错误
dout?.write(message.toString().toByteArray()) dout?.write(message)
dout?.flush() dout?.flush()
Log.d("MyC", "Send msg: $message") Log.d("MyC", "Send msg: ${message.decodeToString()}")
return true return true
} else Log.d("MyC", "The message to be sent is empty") } else Log.d("MyC", "The message to be sent is empty")
Log.d("MyC", "send message succeed") Log.d("MyC", "send message succeed")
@@ -62,74 +64,51 @@ class Client(private val ip: String, private val port: Int) {
return false return false
} }
var buffer = byteArrayOf() fun read(): Char? = din?.read()?.toChar()
fun receiveRawMessage(totalSize: Int = -1, bufferSize: Int = 1048576, setProgress: Boolean = false) : ByteArray { private var buffer = ByteArrayQueue()
if(totalSize == buffer.size) { private val receiveBuffer = ByteArray(65536)
val re = buffer
buffer = byteArrayOf() fun receiveRawMessage(totalSize: Int, setProgress: Boolean = false) : ByteArray {
return re if(totalSize == buffer.size) return buffer.popAll()
} else { else {
var re = byteArrayOf()
try { try {
if (isConnect) { if (isConnect) {
Log.d("MyC", "开始接收服务端信息") Log.d("MyC", "开始接收服务端信息")
val inMessage = ByteArray(bufferSize) //设置接受缓冲,避免接受数据过长占用过多内存 while(totalSize > buffer.size) {
var a: Int val count = din?.read(receiveBuffer)?:0
do { if(count > 0) {
a = din?.read(inMessage)?:0 //a存储返回消息的长度 buffer += receiveBuffer.copyOfRange(0, count)
if(a > 0) { Log.d("MyC", "reply length:$count")
re += inMessage.copyOf(a) if(setProgress && totalSize > 0) progress?.notify(100 * buffer.size / totalSize)
Log.d("MyC", "reply length:$a") } else sleep(10)
if(totalSize < 0 && a < bufferSize) break }
else if(setProgress && totalSize > 0) progress?.notify(100 * re.size / totalSize)
} else break
} while (totalSize > re.size)
} else Log.d("MyC", "no connect to receive message") } else Log.d("MyC", "no connect to receive message")
} catch (e: IOException) { } catch (e: IOException) {
Log.d("MyC", "receive message failed") Log.d("MyC", "receive message failed")
e.printStackTrace() e.printStackTrace()
} }
if(totalSize > 0 && re.size > totalSize) { return if(totalSize > 0) buffer.pop(totalSize)?:byteArrayOf() else buffer.popAll()
Log.d("MyC", "Reduce re size from ${re.size} to $totalSize")
buffer += re.copyOfRange(totalSize, re.size)
re = re.copyOf(totalSize)
} else if(totalSize > 0 && buffer.isNotEmpty()) {
Log.d("MyC", "Increase re size.")
buffer += re
if(buffer.size > totalSize) {
re = buffer.copyOf(totalSize)
buffer = buffer.copyOfRange(totalSize, buffer.size)
} else {
re = buffer
buffer = byteArrayOf()
}
} else if(totalSize < 0 && buffer.isNotEmpty()) {
re = buffer
buffer = byteArrayOf()
Log.d("MyC", "clear buffer")
}
return re
} }
} }
//fun receiveMessage() = receiveRawMessage().decodeToString() fun receiveMessage(totalSize: Int) = receiveRawMessage(totalSize).decodeToString()
/** /**
* 关闭连接 * 关闭连接
*/ */
fun closeConnect() = try { fun closeConnect() = try {
din?.close() din?.close()
dout?.close() dout?.close()
sc?.close() sc?.close()
sc = null sc = null
din = null din = null
dout = null dout = null
true true
} catch (e: IOException) { } catch (e: IOException) {
e.printStackTrace() e.printStackTrace()
false false
} }
var progress: Progress? = null var progress: Progress? = null

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:viewportHeight="1024"
android:viewportWidth="1024">
<path
android:fillColor="@android:color/holo_red_light"
android:pathData="M668 117C833 117 939 250 939 428c0 138-125 291-372 462a97 97 0 0 1-110 0C210 718 85 566 85 428 85 250 191 117 356 117c60 0 100 21 156 68C568 138 608 117 668 117z m0 63c-41 0-70 15-117 55-2 2-14 12-18 15a32 32 0 0 1-42 0c-4-3-16-14-18-15-47-40-76-55-117-55C230 180 149 281 149 427 149 538 263 675 494 835a32 32 0 0 0 37 0C761 675 875 538 875 427c0-145-81-246-207-246z"/>
</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:viewportHeight="1024"
android:viewportWidth="1024">
<path
android:fillColor="@android:color/holo_red_light"
android:pathData="M668 117C833 117 939 250 939 428c0 138-125 291-372 462a97 97 0 0 1-110 0C210 718 85 566 85 428 85 250 191 117 356 117c60 0 100 21 156 68C568 138 608 117 668 117z"/>
</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="24dp"
android:height="24dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:fillColor="?android:textColorSecondary"
android:pathData="M944 552l-182 331a74 74 0 0 1-65 38h-362a74 74 0 0 1-65-38l-182-331a75 75 0 0 1 0-73l182-331a74 74 0 0 1 65-38h362a74 74 0 0 1 65 38l182 331a75 75 0 0 1 0 73z m-56-31a11 11 0 0 0 0-10l-182-331a11 11 0 0 0-9-5H336a11 11 0 0 0-9 5l-182 331a11 11 0 0 0 0 10l182 331a11 11 0 0 0 9 5h362a11 11 0 0 0 9-5l182-331zM514 683c-94 0-171-76-171-171s76-171 171-171c94 0 171 76 171 171s-76 171-171 171z m0-64c59 0 107-48 107-107s-48-107-107-107-107 48-107 107 48 107 107 107z"/>
</vector>

View File

@@ -79,7 +79,7 @@
android:layout_marginTop="4dp" android:layout_marginTop="4dp"
android:fontFamily="@font/calibri" android:fontFamily="@font/calibri"
android:gravity="center" android:gravity="center"
android:text="This is the third-party app for ranobe reading" android:text="This is the third-party app for manga reading"
android:textColor="#9affffff" android:textColor="#9affffff"
android:textSize="10sp" /> android:textSize="10sp" />

View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<top.fumiama.copymanga.views.MangaCardView
android:id="@+id/cic"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="@dimen/nav_header_vertical_spacing"
android:layout_marginTop="@dimen/nav_header_vertical_spacing"
android:layout_marginEnd="@dimen/nav_header_vertical_spacing"
android:layout_marginBottom="@dimen/nav_header_vertical_spacing"
android:clickable="true"
android:focusable="true"
android:foreground="?android:attr/selectableItemBackground"
app:cardCornerRadius="@dimen/global_radius"
app:cardElevation="@dimen/global_card_elevation"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imic"
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleType="centerCrop"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<include
android:id="@+id/sgnic"
layout="@layout/widget_finalmark"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</top.fumiama.copymanga.views.MangaCardView>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -6,29 +6,50 @@
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context="top.fumiama.copymanga.ui.home.HomeFragment"> tools:context="top.fumiama.copymanga.ui.home.HomeFragment">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout <androidx.core.widget.NestedScrollView
android:id="@+id/swiperefresh" android:id="@+id/fhns"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
android:fillViewport="true">
<top.fumiama.copymanga.views.ScrollRefreshView <LinearLayout
android:id="@+id/fhov"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent" android:orientation="vertical">
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0">
<LinearLayout <com.lapism.search.widget.MaterialSearchView
android:id="@+id/fhl" android:id="@+id/fhs"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" /> app:layout_behavior="com.lapism.search.widget.SearchBehavior">
</top.fumiama.copymanga.views.ScrollRefreshView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</com.lapism.search.widget.MaterialSearchView>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swiperefresh"
android:layout_width="match_parent"
android:layout_height="match_parent">
<top.fumiama.copymanga.views.ScrollRefreshView
android:id="@+id/fhov"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<LinearLayout
android:id="@+id/fhl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
</LinearLayout>
</top.fumiama.copymanga.views.ScrollRefreshView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="?android:attr/listPreferredItemHeightSmall"
android:checkMark="?android:attr/listChoiceIndicatorSingle"
android:gravity="center_vertical"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:textAppearance="?android:attr/textAppearanceListItemSmall" />

View File

@@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/lwc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:foreground="?android:attr/selectableItemBackground">
<include
android:id="@+id/lwi"
layout="@layout/card_book_plain"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/lwl"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="@+id/lwl"
android:layout_width="0dp"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_weight="4"
app:layout_constraintStart_toEndOf="@+id/lwi"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/tn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginEnd="16dp"
android:textColor="?attr/colorOnSurface"
android:textSize="24sp"
android:textStyle="bold" />
<TextView
android:id="@+id/ta"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:fontFamily="@font/gotham"
android:textColor="?attr/colorOnSurface"
android:textSize="18sp" />
<TextView
android:id="@+id/tb"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginBottom="10dp" />
</LinearLayout>
<View
android:id="@+id/vl"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginEnd="16dp"
android:clickable="true"
android:focusable="true"
android:foreground="?android:attr/selectableItemBackground"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -11,4 +11,5 @@
<color name="colorGreen">#BFEA88</color> <color name="colorGreen">#BFEA88</color>
<color name="textInputLayout">#ffffff</color> <color name="textInputLayout">#ffffff</color>
<color name="colorRed">#F6837A</color> <color name="colorRed">#F6837A</color>
<color name="searchBarPrimaryColor">#E1E1E1</color>
</resources> </resources>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="search_types">
<item>全部</item>
<item>名称</item>
<item>作者</item>
<item>汉化组</item>
</string-array>
</resources>

View File

@@ -7,7 +7,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">©2021源文雨@CoolApk\n本应用为拷贝漫画的第三方客户端数据均来源于网络作者不对其中所呈现的任何内容负责。</string> <string name="app_description">©2022源文雨@CoolApk\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>
@@ -17,6 +17,7 @@
<string name="page_group">漫画下载</string> <string name="page_group">漫画下载</string>
<string name="page_topic">专题系列</string> <string name="page_topic">专题系列</string>
<string name="check_update">检查更新</string> <string name="check_update">检查更新</string>
<string name="set_search_types">设置搜索类别</string>
<string name="navTextInfo">illust: Hiten(490219)</string> <string name="navTextInfo">illust: Hiten(490219)</string>
<string name="navTextInfoInputHint">请设定提示文字内容</string> <string name="navTextInfoInputHint">请设定提示文字内容</string>
@@ -33,6 +34,7 @@
<string name="referUrl">"https://api.copymanga.com"</string> <string name="referUrl">"https://api.copymanga.com"</string>
<string name="recentUpdateApiUrl">https://nnv3api.dmzj1.com/novel/recentUpdate/%1$d.json</string> <string name="recentUpdateApiUrl">https://nnv3api.dmzj1.com/novel/recentUpdate/%1$d.json</string>
<string name="rankApiUrl">https://api.copymanga.com/api/v3/ranks?limit=21&amp;offset=%1$d&amp;date_type=%2$s&amp;platform=3</string> <string name="rankApiUrl">https://api.copymanga.com/api/v3/ranks?limit=21&amp;offset=%1$d&amp;date_type=%2$s&amp;platform=3</string>
<string name="searchApiUrl">https://api.copymanga.com/api/v3/search/comic?limit=21&amp;offset=%1$d&amp;q=%2$s&amp;q_type=%3$s&amp;platform=3</string>
<string name="filterApiUrl">https://api.copymanga.com/api/v3/h5/filterIndex/comic/tags?platform=3</string> <string name="filterApiUrl">https://api.copymanga.com/api/v3/h5/filterIndex/comic/tags?platform=3</string>
<string name="sortApiUrl">https://api.copymanga.com/api/v3/comics?limit=21&amp;offset=%1$d&amp;ordering=%2$s&amp;theme=%3$s&amp;platform=3</string> <string name="sortApiUrl">https://api.copymanga.com/api/v3/comics?limit=21&amp;offset=%1$d&amp;ordering=%2$s&amp;theme=%3$s&amp;platform=3</string>
<string name="bookInfoApiUrl">https://api.copymanga.com/api/v3/comic2/%1$s?platform=3</string> <string name="bookInfoApiUrl">https://api.copymanga.com/api/v3/comic2/%1$s?platform=3</string>

View File

@@ -21,4 +21,6 @@
<style name="Widget.MPM.Menu.Dark.CustomBackground"> <style name="Widget.MPM.Menu.Dark.CustomBackground">
<item name="android:colorBackground">?attr/colorSurface</item> <item name="android:colorBackground">?attr/colorSurface</item>
</style> </style>
<style name="AlertDialogTheme" parent="Theme.MaterialComponents.Dialog.Alert"/>
</resources> </resources>

View File

@@ -1,14 +1,15 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
ext.kotlin_version = '1.5.0' ext.kotlin_version = '1.5.31'
repositories { repositories {
google() google()
jcenter() jcenter()
mavenCentral() mavenCentral()
maven { url 'https://maven.google.com' } maven { url 'https://maven.google.com' }
maven { url "https://jitpack.io" }
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:4.2.1' classpath 'com.android.tools.build:gradle:7.0.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.tencent.mm:AndResGuard-gradle-plugin:1.2.21' classpath 'com.tencent.mm:AndResGuard-gradle-plugin:1.2.21'

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-6.8-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip