├── .gitignore ├── .idea ├── .name ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── compiler.xml ├── deploymentTargetDropDown.xml ├── deploymentTargetSelector.xml ├── dictionaries │ ├── fumiama.xml │ └── rumia.xml ├── gradle.xml ├── jarRepositories.xml ├── kotlinc.xml ├── migrations.xml ├── misc.xml └── vcs.xml ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── libs │ └── com.lapism │ │ └── search-2.4.1.aar ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── top │ │ └── fumiama │ │ └── copymanga │ │ ├── LoginActivity.kt │ │ ├── MainActivity.kt │ │ ├── api │ │ ├── Config.kt │ │ ├── manga │ │ │ ├── Book.kt │ │ │ ├── Downloader.kt │ │ │ ├── Reader.kt │ │ │ ├── Shelf.kt │ │ │ └── Volume.kt │ │ ├── update │ │ │ ├── ByteArrayQueue.kt │ │ │ ├── SimpleKanban.kt │ │ │ └── Update.kt │ │ └── user │ │ │ └── Member.kt │ │ ├── json │ │ ├── BookInfoStructure.java │ │ ├── BookListStructure.java │ │ ├── BookQueryStructure.java │ │ ├── Chapter2Return.java │ │ ├── ChapterStructure.java │ │ ├── ChapterWithContent.java │ │ ├── ComandyCapsule.java │ │ ├── ComandyVersion.java │ │ ├── ComicStructure.java │ │ ├── ComicStructureOld.java │ │ ├── FilterStructure.java │ │ ├── HistoryBookListStructure.java │ │ ├── HistoryComicStructure.java │ │ ├── IndexStructure.java │ │ ├── InfoBase.java │ │ ├── InfoStructure.java │ │ ├── LastBrowseStructure.java │ │ ├── LoginInfoStructure.java │ │ ├── NetworkStructure.java │ │ ├── ResultsBase.java │ │ ├── ReturnBase.java │ │ ├── SeriesStructure.java │ │ ├── ShelfStructure.java │ │ ├── ThemeStructure.java │ │ ├── TopicStructure.java │ │ ├── TypeBookListStructure.java │ │ ├── TypeBookStructure.java │ │ ├── UUIDUrlPair.java │ │ ├── ValueDisplayPair.java │ │ └── VolumeStructure.java │ │ ├── lib │ │ ├── Comancry.kt │ │ ├── ComancryMethods.kt │ │ ├── Comandy.kt │ │ ├── ComandyMethods.kt │ │ └── template │ │ │ └── LazyLibrary.kt │ │ ├── net │ │ ├── Client.kt │ │ ├── ComandyGlideModule.kt │ │ ├── DownloadPool.kt │ │ ├── DownloadTools.kt │ │ ├── Proxy.kt │ │ ├── Resolution.kt │ │ └── template │ │ │ ├── AutoDownloadHandler.kt │ │ │ └── PausableDownloader.kt │ │ ├── storage │ │ ├── FileUtils.kt │ │ ├── PreferenceBoolean.kt │ │ ├── PreferenceInt.kt │ │ ├── PreferenceString.kt │ │ ├── PropertiesTools.kt │ │ ├── UserPreferenceInt.kt │ │ └── UserPreferenceString.kt │ │ ├── strings │ │ └── Chinese.kt │ │ ├── ui │ │ ├── book │ │ │ ├── BookFragment.kt │ │ │ └── BookHandler.kt │ │ ├── cardflow │ │ │ ├── author │ │ │ │ └── AuthorFragment.kt │ │ │ ├── caption │ │ │ │ └── CaptionFragment.kt │ │ │ ├── finish │ │ │ │ └── FinishFragment.kt │ │ │ ├── history │ │ │ │ └── HistoryFragment.kt │ │ │ ├── newest │ │ │ │ └── NewestFragment.kt │ │ │ ├── rank │ │ │ │ └── RankFragment.kt │ │ │ ├── recommend │ │ │ │ └── RecFragment.kt │ │ │ ├── search │ │ │ │ └── SearchFragment.kt │ │ │ ├── shelf │ │ │ │ └── ShelfFragment.kt │ │ │ ├── sort │ │ │ │ └── SortFragment.kt │ │ │ └── topic │ │ │ │ └── TopicFragment.kt │ │ ├── comicdl │ │ │ ├── ComicDlFragment.kt │ │ │ └── ComicDlHandler.kt │ │ ├── download │ │ │ ├── DownloadFragment.kt │ │ │ └── NewDownloadFragment.kt │ │ ├── home │ │ │ ├── HomeFragment.kt │ │ │ └── HomeHandler.kt │ │ ├── settings │ │ │ └── SettingsFragment.kt │ │ └── vm │ │ │ ├── PagesManager.kt │ │ │ ├── VMHandler.kt │ │ │ └── ViewMangaActivity.kt │ │ └── view │ │ ├── AutoHideEditTextPreferenceDialogFragmentCompat.kt │ │ ├── ChapterToggleButton.kt │ │ ├── Font.kt │ │ ├── LazyScrollView.kt │ │ ├── MangaCardView.kt │ │ ├── OverScrollView.kt │ │ ├── ScaleImageView.kt │ │ ├── ScrollRefreshView.kt │ │ ├── interaction │ │ ├── Navigate.kt │ │ ├── TimeThread.kt │ │ └── UITools.kt │ │ ├── operation │ │ ├── GlideBlurTransformation.kt │ │ └── GlideHideLottieViewListener.kt │ │ └── template │ │ ├── ActivityTemplate.kt │ │ ├── CardList.kt │ │ ├── InfoCardLoader.kt │ │ ├── MangaPagesFragmentTemplate.kt │ │ ├── NoBackRefreshFragment.kt │ │ ├── StatusCardFlow.kt │ │ ├── ThemeCardFlow.kt │ │ └── TitleActivityTemplate.kt │ └── res │ ├── anim │ ├── slide_in_right.xml │ ├── slide_in_right_exit.xml │ ├── slide_out_left.xml │ └── slide_out_left_exit.xml │ ├── drawable-anydpi │ ├── bg_rnd_green.xml │ ├── buttonshapewhitebg.xml │ ├── ic_anchor_down.xml │ ├── ic_author.xml │ ├── ic_circle.xml │ ├── ic_data.xml │ ├── ic_dere.xml │ ├── ic_email_white_24dp.xml │ ├── ic_hot.xml │ ├── ic_image.xml │ ├── ic_launcher_background.xml │ ├── ic_launcher_foreground.xml │ ├── ic_line_more.xml │ ├── ic_list.xml │ ├── ic_locate.xml │ ├── ic_lock_white_24dp.xml │ ├── ic_menu_del.xml │ ├── ic_menu_download.xml │ ├── ic_menu_history.xml │ ├── ic_menu_home.xml │ ├── ic_menu_rank.xml │ ├── ic_menu_sort.xml │ ├── ic_menu_sub.xml │ ├── ic_refresh.xml │ ├── ic_setting_search.xml │ ├── ic_settings.xml │ ├── ic_success.xml │ ├── ic_time.xml │ ├── mask_blackbottom.xml │ ├── mask_blacktop.xml │ ├── rndbg.xml │ ├── rndbg_checked.xml │ ├── rndbg_error.xml │ ├── rndbg_white.xml │ └── toggle_button.xml │ ├── drawable-nodpi │ ├── illust_57793944_20190427_134853.webp │ ├── img_defmask.webp │ ├── img_hot.webp │ ├── img_hot_serial.png │ ├── img_latest_pub.png │ ├── img_master_work.webp │ ├── img_novel_bill.png │ ├── img_novel_eye.webp │ ├── kohima.webp │ └── line_colorful.webp │ ├── font │ ├── calibri.ttf │ ├── gotham.ttf │ └── nisi.ttf │ ├── layout │ ├── activity_login.xml │ ├── activity_main.xml │ ├── activity_viewmanga.xml │ ├── anchor_popular.xml │ ├── app_bar_main.xml │ ├── button_tbutton.xml │ ├── card_book.xml │ ├── card_book_plain.xml │ ├── content_main.xml │ ├── dialog_progress.xml │ ├── dialog_unzipping.xml │ ├── div_h.xml │ ├── fragment_book.xml │ ├── fragment_dlcomic.xml │ ├── fragment_download.xml │ ├── fragment_history.xml │ ├── fragment_home.xml │ ├── fragment_newdownload.xml │ ├── fragment_newest.xml │ ├── fragment_rank.xml │ ├── fragment_recommend.xml │ ├── fragment_search.xml │ ├── fragment_settings.xml │ ├── fragment_shelf.xml │ ├── fragment_sort.xml │ ├── fragment_statuscardflow.xml │ ├── fragment_topic.xml │ ├── line_1bookline.xml │ ├── line_2bookline.xml │ ├── line_2chapters.xml │ ├── line_3bookline.xml │ ├── line_bookinfo.xml │ ├── line_bookinfo_text.xml │ ├── line_booktandb.xml │ ├── line_caption.xml │ ├── line_chapter.xml │ ├── line_choice_list.xml │ ├── line_finish.xml │ ├── line_header.xml │ ├── line_horizonal_empty.xml │ ├── line_lazybooklines.xml │ ├── line_rank.xml │ ├── line_shelf.xml │ ├── line_sort.xml │ ├── line_text_info.xml │ ├── line_word.xml │ ├── nav_header_main.xml │ ├── page_imgview.xml │ ├── page_nested_list.xml │ ├── page_scrollimgview.xml │ ├── viewpage_banner.xml │ ├── viewpage_horizonal.xml │ ├── widget_downloadbar.xml │ ├── widget_finalmark.xml │ ├── widget_infodrawer.xml │ ├── widget_newmark.xml │ ├── widget_titlebar.xml │ └── widget_viewmangainfo.xml │ ├── menu │ ├── activity_main_drawer.xml │ └── main.xml │ ├── mipmap-anydpi-v26 │ └── ic_launcher.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── navigation │ └── mobile_navigation.xml │ ├── raw │ └── lottie_loading.json │ ├── values-night │ └── colors.xml │ ├── values │ ├── arrays.xml │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── themes.xml │ └── xml │ ├── pref_setting.xml │ └── provider_paths.xml ├── build.gradle ├── fastlane └── metadata │ └── android │ ├── en-US │ ├── full_description.txt │ ├── images │ │ └── phoneScreenshots │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ ├── 3.png │ │ │ ├── 4.png │ │ │ ├── 5.png │ │ │ └── 6.png │ └── short_description.txt │ └── zh-CN │ ├── full_description.txt │ └── short_description.txt ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | 拷贝漫画 -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/deploymentTargetDropDown.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /.idea/deploymentTargetSelector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/dictionaries/fumiama.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | alphae 5 | azurewebsites 6 | comancry 7 | comandy 8 | downloaders 9 | grps 10 | hotmanga 11 | imgs 12 | kohima 13 | libcomancry 14 | libcomandy 15 | lowpan 16 | mangacopy 17 | mangafuna 18 | nisi 19 | pausable 20 | reclass 21 | reilia 22 | systembar 23 | 24 | 25 | -------------------------------------------------------------------------------- /.idea/dictionaries/rumia.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | copymanga 5 | fileprovider 6 | fumiama 7 | statuscardflow 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 34 | 35 | -------------------------------------------------------------------------------- /.idea/kotlinc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/migrations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /release 3 | /debug 4 | signing.properties 5 | -------------------------------------------------------------------------------- /app/libs/com.lapism/search-2.4.1.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fumiama/copymanga/d04e03132846f52498f40a7be680fce098f359c8/app/libs/com.lapism/search-2.4.1.aar -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -keep public class * implements com.bumptech.glide.module.GlideModule 23 | -keep class * extends com.bumptech.glide.module.AppGlideModule { 24 | (...); 25 | } 26 | -keep public enum com.bumptech.glide.load.ImageHeaderParser$** { 27 | **[] $VALUES; 28 | public *; 29 | } 30 | -keep class com.bumptech.glide.load.data.ParcelFileDescriptorRewinder.InternalRewinder$** { 31 | *** rewind(); 32 | } 33 | 34 | -assumenosideeffects class android.util.Log { 35 | public static *** d(...); 36 | public static *** e(...); 37 | public static *** i(...); 38 | public static *** v(...); 39 | public static *** println(...); 40 | public static *** w(...); 41 | public static *** wtf(...); 42 | } 43 | 44 | -keep class com.to.aboomy.pager2banner.* {*;} 45 | -keep class androidx.viewpager2.widget.* {*;} 46 | 47 | -dontwarn com.yalantis.ucrop** 48 | -keep class com.yalantis.ucrop** { *; } 49 | -keep interface com.yalantis.ucrop** { *; } 50 | 51 | ##---------------Begin: proguard configuration for Gson ---------- 52 | # Gson uses generic type information stored in a class file when working with fields. Proguard 53 | # removes such information by default, so configure it to keep all of it. 54 | -keepattributes Signature 55 | 56 | # For using GSON @Expose annotation 57 | -keepattributes *Annotation* 58 | 59 | # Gson specific classes 60 | -dontwarn sun.misc.** 61 | #-keep class com.google.gson.stream.** { *; } 62 | 63 | # Application classes that will be serialized/deserialized over Gson 64 | -keep class top.fumiama.copymanga.json.*{ *; } 65 | 66 | # Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory, 67 | # JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter) 68 | -keep class * extends com.google.gson.TypeAdapter 69 | -keep class * implements com.google.gson.TypeAdapterFactory 70 | -keep class * implements com.google.gson.JsonSerializer 71 | -keep class * implements com.google.gson.JsonDeserializer 72 | 73 | # Prevent R8 from leaving Data object members always null 74 | -keepclassmembers,allowobfuscation class * { 75 | @com.google.gson.annotations.SerializedName ; 76 | } 77 | 78 | ##---------------End: proguard configuration for Gson ---------- 79 | 80 | ## JNA Proguard rules 81 | -keep class com.sun.jna.** { *; } 82 | -keep class * implements com.sun.jna.** { *; } 83 | -dontwarn java.awt.Component 84 | -dontwarn java.awt.GraphicsEnvironment 85 | -dontwarn java.awt.HeadlessException 86 | -dontwarn java.awt.Window 87 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 15 | 20 | 23 | 24 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 38 | 41 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/LoginActivity.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga 2 | 3 | import android.os.Bundle 4 | import android.util.Log 5 | import android.view.WindowManager 6 | import android.widget.Toast 7 | import androidx.appcompat.app.AppCompatActivity 8 | import androidx.core.view.WindowCompat 9 | import androidx.lifecycle.lifecycleScope 10 | import kotlinx.android.synthetic.main.activity_login.* 11 | import kotlinx.coroutines.launch 12 | import top.fumiama.copymanga.api.Config 13 | import top.fumiama.dmzj.copymanga.R 14 | import kotlin.random.Random 15 | 16 | 17 | class LoginActivity : AppCompatActivity() { 18 | override fun onCreate(savedInstanceState: Bundle?) { 19 | super.onCreate(savedInstanceState) 20 | setContentView(R.layout.activity_login) 21 | val isLogout = !Config.token.value.isNullOrEmpty() 22 | if (isLogout) { 23 | alblogin.setText(R.string.logout) 24 | altusrnm.setText(Config.username.value) 25 | } 26 | alblogin.setOnClickListener { 27 | lifecycleScope.launch { 28 | val salt = Random.nextInt(10000) 29 | val username = altusrnm.text?.toString() ?: run { 30 | Toast.makeText( 31 | this@LoginActivity, 32 | R.string.login_null_username, 33 | Toast.LENGTH_SHORT 34 | ).show() 35 | return@launch 36 | } 37 | val pwd = altpwd.text?.toString() ?: run { 38 | Toast.makeText(this@LoginActivity, R.string.login_null_pwd, Toast.LENGTH_SHORT) 39 | .show() 40 | return@launch 41 | } 42 | if (isLogout) { 43 | MainActivity.member?.logout() 44 | MainActivity.mainWeakReference?.get()?.refreshUserInfo() 45 | Toast.makeText( 46 | this@LoginActivity, 47 | R.string.login_restart_to_apply, 48 | Toast.LENGTH_SHORT 49 | ).show() 50 | finish() 51 | return@launch 52 | } 53 | val l = MainActivity.member?.login(username, pwd, salt) 54 | Log.d("MyLA", "login return code: ${l?.code}") 55 | if (l?.code == 200) { 56 | MainActivity.mainWeakReference?.get()?.refreshUserInfo() 57 | finish() 58 | return@launch 59 | } 60 | Toast.makeText(this@LoginActivity, l?.message, Toast.LENGTH_LONG).show() 61 | } 62 | } 63 | if (Config.general_enable_transparent_system_bar.value) { 64 | WindowCompat.setDecorFitsSystemWindows(window, false) 65 | window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) 66 | window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) 67 | window.statusBarColor = 0 68 | window.navigationBarColor = 0 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/api/update/ByteArrayQueue.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.api.update 2 | //Fumiama 20210601 3 | //ByteArrayQueue.kt 4 | //FIFO队列 5 | class ByteArrayQueue { 6 | private var elements = byteArrayOf() 7 | val size get() = elements.size 8 | fun append(items: ByteArray) { 9 | elements += items 10 | } 11 | fun pop(num: Int = 1): ByteArray? { 12 | return if(num <= elements.size) { 13 | val re = elements.copyOfRange(0, num) 14 | elements = elements.copyOfRange(num, elements.size) 15 | re 16 | } else null 17 | } 18 | fun clear() { 19 | elements = byteArrayOf() 20 | } 21 | fun popAll(): ByteArray { 22 | val re = elements 23 | clear() 24 | return re 25 | } 26 | operator fun plusAssign(items: ByteArray) = append(items) 27 | } -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/api/update/SimpleKanban.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.api.update 2 | 3 | import android.util.Log 4 | import top.fumiama.copymanga.net.Client 5 | 6 | class SimpleKanban(private val client: Client, private val pwd: String) { //must run in thread 7 | private val raw: ByteArray? 8 | get() { 9 | var times = 3 10 | var re: ByteArray 11 | var firstReceived: ByteArray 12 | do { 13 | re = byteArrayOf() 14 | if(client.initConnect()) { 15 | client.sendMessage("${pwd}catquit") 16 | client.receiveRawMessage(33) //Welcome to simple kanban server. 17 | try { 18 | firstReceived = client.receiveRawMessage(4) //le 19 | val length = convert2Int(firstReceived) 20 | Log.d("MySK", "Msg len: $length") 21 | if(firstReceived.size > 4) re += firstReceived.copyOfRange(4, firstReceived.size) 22 | re += client.receiveRawMessage(length - re.size, setProgress = true) 23 | break 24 | } catch (e: Exception) { 25 | e.printStackTrace() 26 | } 27 | client.closeConnect() 28 | } 29 | } while (times-- > 0) 30 | return if(re.isEmpty()) null else re 31 | } 32 | 33 | private fun convert2Int(buffer: ByteArray) = 34 | (buffer[3].toInt() and 0xff shl 24) or 35 | (buffer[2].toInt() and 0xff shl 16) or 36 | (buffer[1].toInt() and 0xff shl 8) or 37 | (buffer[0].toInt() and 0xff) 38 | 39 | suspend fun fetchRaw(doOnLoadFailure: suspend ()->Unit = { 40 | Log.d("MySD", "Fetch dict failed") 41 | }, doOnLoadSuccess: suspend (data: ByteArray)->Unit = { 42 | Log.d("MySD", "Fetch dict success") 43 | }) { 44 | raw?.apply { 45 | doOnLoadSuccess(this) 46 | }?:doOnLoadFailure() 47 | } 48 | 49 | operator fun get(version: Int): String = 50 | if(client.initConnect()) { 51 | client.sendMessage("${pwd}get${version}quit") 52 | client.receiveRawMessage(36) //Welcome to simple kanban server. get 53 | val r = try { 54 | val firstRecv = client.receiveRawMessage(4) 55 | if(firstRecv.decodeToString() == "null") "null" 56 | else { 57 | val length = convert2Int(firstRecv) 58 | Log.d("MySK", "Msg len: $length") 59 | var re = byteArrayOf() 60 | if(firstRecv.size > 4) re += firstRecv.copyOfRange(4, firstRecv.size) 61 | re += client.receiveRawMessage(length - re.size) 62 | if(re.isNotEmpty()) re.decodeToString() else "null" 63 | } 64 | } catch (e: Exception){ 65 | e.printStackTrace() 66 | "null" 67 | } 68 | client.closeConnect() 69 | r 70 | } else "null" 71 | } -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/json/BookInfoStructure.java: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.json; 2 | 3 | import java.util.HashMap; 4 | 5 | public class BookInfoStructure extends ReturnBase { 6 | public Results results; 7 | public static class Results extends ResultsBase{ 8 | public ComicStructure comic; 9 | public HashMap groups; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/json/BookListStructure.java: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.json; 2 | 3 | public class BookListStructure extends ReturnBase { 4 | public Results results; 5 | public static class Results { 6 | public int total; 7 | public ComicStructure[] list; 8 | public int limit; 9 | public int offset; 10 | } 11 | } -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/json/BookQueryStructure.java: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.json; 2 | 3 | public class BookQueryStructure extends ReturnBase { 4 | public Results results; 5 | public static class Results{ 6 | public Browse browse; 7 | public int collect; 8 | public boolean is_lock; 9 | public boolean is_login; 10 | public boolean is_mobile_bind; 11 | public boolean is_vip; 12 | public static class Browse { 13 | public String comic_uuid; 14 | public String comic_id; 15 | public String path_word; 16 | public String chapter_uuid; 17 | public String chapter_id; 18 | public String chapter_name; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/json/Chapter2Return.java: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.json; 2 | 3 | public class Chapter2Return extends ReturnBase { 4 | public Results results; 5 | public static class Results extends ResultsBase{ 6 | public ComicStructure comic; 7 | public ChapterWithContent chapter; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/json/ChapterStructure.java: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.json; 2 | 3 | public class ChapterStructure { 4 | public int index; 5 | public String uuid; 6 | public int count; 7 | public int size; 8 | public String name; 9 | public String comic_id; 10 | public String comic_path_word; 11 | public String group_id; 12 | public String group_path_word; 13 | public int type; 14 | public int img_type; 15 | public String datetime_created; 16 | public String prev; 17 | public String next; 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/json/ChapterWithContent.java: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.json; 2 | 3 | public class ChapterWithContent extends ChapterStructure { 4 | public UUIDUrlPair[] contents; 5 | public int[] words; 6 | public Boolean is_long; 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/json/ComandyCapsule.java: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.json; 2 | 3 | import java.util.HashMap; 4 | 5 | public class ComandyCapsule { 6 | public int code; 7 | public String method; 8 | public String url; 9 | public HashMap headers; 10 | public String data; 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/json/ComandyVersion.java: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.json; 2 | 3 | public class ComandyVersion { 4 | public String body; 5 | } 6 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/json/ComicStructure.java: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.json; 2 | 3 | public class ComicStructure { 4 | public String uuid; 5 | public String name; 6 | //public String alias; 7 | public int img_type; 8 | public ValueDisplayPair region; 9 | public ValueDisplayPair status; 10 | public ValueDisplayPair reclass; // identify hotmanga 11 | public ThemeStructure[] theme; 12 | public String path_word; 13 | public ThemeStructure[] author; 14 | public String brief; 15 | public String datetime_updated; 16 | public String cover; 17 | public int popular; 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/json/ComicStructureOld.java: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.json; 2 | 3 | public class ComicStructureOld { 4 | public String name; 5 | public Chapters[] chapters; 6 | public static class Chapters{ 7 | public String name; 8 | public String url; 9 | } 10 | } -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/json/FilterStructure.java: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.json; 2 | 3 | public class FilterStructure extends ReturnBase { 4 | public Results results; 5 | public static class Results{ 6 | public ThemeStructure[] theme; 7 | public ThemeStructure[] top; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/json/HistoryBookListStructure.java: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.json; 2 | 3 | public class HistoryBookListStructure extends ReturnBase { 4 | public Results results; 5 | public static class Results { 6 | public ListItem[] list; 7 | public int total; 8 | public int limit; 9 | public int offset; 10 | } 11 | public static class ListItem { 12 | public String last_chapter_id; 13 | public String last_chapter_name; 14 | public HistoryComicStructure comic; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/json/HistoryComicStructure.java: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.json; 2 | 3 | public class HistoryComicStructure { 4 | public String uuid; 5 | public boolean b_display; 6 | public String name; 7 | public String path_word; 8 | public ThemeStructure[] author; 9 | public ThemeStructure[] theme; 10 | public String cover; 11 | public int status; 12 | public int popular; 13 | public String datetime_updated; 14 | public String last_chapter_id; 15 | public String last_chapter_name; 16 | public Browse browse; 17 | 18 | public static class Browse { 19 | public String comic_uuid; 20 | public String path_word; 21 | public String chapter_uuid; 22 | public String chapter_name; 23 | 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/json/IndexStructure.java: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.json; 2 | 3 | public class IndexStructure extends ReturnBase { 4 | public Results results; 5 | public static class Results{ 6 | public Banners[] banners; 7 | public Topics topics; 8 | public RecComics recComics; 9 | // copymanga 10 | public RankComics rankDayComics; 11 | public RankComics rankWeekComics; 12 | public RankComics rankMonthComics; 13 | public ComicWrap[] hotComics; 14 | public ComicWrap[] newComics; 15 | public FinishComics finishComics; 16 | // hotmanga 17 | public RankComics rankWeeklyFreeComics; 18 | public WeeklyComics updateWeeklyFreeComics; 19 | 20 | public static class Banners{ 21 | public int type; 22 | public String cover; 23 | public String brief; 24 | public String out_uuid; 25 | public ComicStructure comic; 26 | } 27 | public static class Topics extends InfoBase{ 28 | public List[] list; 29 | 30 | public static class List{ 31 | public String title; 32 | public SeriesStructure series; 33 | public String journal; 34 | public String cover; 35 | public String period; 36 | public int type; 37 | public String brief; 38 | public String path_word; 39 | public String datetime_created; 40 | } 41 | } 42 | public static class RecComics extends InfoBase{ 43 | public List[] list; 44 | 45 | public static class List{ 46 | public int type; 47 | public ComicStructure comic; 48 | } 49 | } 50 | public static class RankComics extends InfoBase{ 51 | public InfoStructure[] list; 52 | } 53 | public static class ComicWrap{ 54 | public ComicStructure comic; 55 | } 56 | public static class FinishComics extends InfoBase{ 57 | public ComicStructure[] list; 58 | public String path_word; 59 | public String name; 60 | public String type; 61 | } 62 | public static class WeeklyComics extends InfoBase { 63 | public TypeBookStructure[] list; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/json/InfoBase.java: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.json; 2 | 3 | public class InfoBase { 4 | public int total; 5 | public int limit; 6 | public int offset; 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/json/InfoStructure.java: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.json; 2 | 3 | public class InfoStructure { 4 | public int sort; 5 | public int sort_last; 6 | public int rise_sort; 7 | public int rise_num; 8 | public int date_type; 9 | public int popular; 10 | public ComicStructure comic; 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/json/LastBrowseStructure.java: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.json; 2 | 3 | public class LastBrowseStructure { 4 | public String last_browse_id; 5 | public String last_browse_name; 6 | } 7 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/json/LoginInfoStructure.java: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.json; 2 | 3 | public class LoginInfoStructure extends ReturnBase{ 4 | public Results results; 5 | public static class Results { 6 | public String token; 7 | public String user_id; 8 | public String username; 9 | public String nickname; 10 | public String avatar; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/json/NetworkStructure.java: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.json; 2 | 3 | public class NetworkStructure extends ReturnBase { 4 | public Results results; 5 | public static class Results { 6 | public String[] share; 7 | public String[][] api; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/json/ResultsBase.java: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.json; 2 | 3 | public class ResultsBase { 4 | public Boolean is_lock; 5 | public Boolean is_login; 6 | public Boolean is_mobile_bind; 7 | public Boolean is_vip; 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/json/ReturnBase.java: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.json; 2 | 3 | public class ReturnBase { 4 | public int code; 5 | public String message; 6 | } 7 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/json/SeriesStructure.java: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.json; 2 | 3 | public class SeriesStructure extends ThemeStructure { 4 | public String color; 5 | } 6 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/json/ShelfStructure.java: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.json; 2 | 3 | public class ShelfStructure extends ReturnBase { 4 | public Results results; 5 | public static class Results extends InfoBase { 6 | public List[] list; 7 | public static class List { 8 | public int uuid; 9 | public boolean b_folder; 10 | public LastBrowseStructure last_browse; 11 | public HistoryComicStructure comic; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/json/ThemeStructure.java: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.json; 2 | 3 | public class ThemeStructure { 4 | public String name; 5 | public String path_word; 6 | public int count; 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/json/TopicStructure.java: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.json; 2 | 3 | public class TopicStructure extends ReturnBase { 4 | public Results results; 5 | public static class Results { 6 | public String title; 7 | public String period; 8 | public String intro; 9 | public int type; 10 | public String datetime_created; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/json/TypeBookListStructure.java: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.json; 2 | 3 | public class TypeBookListStructure extends ReturnBase { 4 | public Results results; 5 | public static class Results extends InfoBase { 6 | public TypeBookStructure[] list; 7 | } 8 | } -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/json/TypeBookStructure.java: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.json; 2 | 3 | public class TypeBookStructure { 4 | public int type; 5 | public String name; 6 | public String datetime_created; 7 | public ComicStructure comic; 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/json/UUIDUrlPair.java: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.json; 2 | 3 | public class UUIDUrlPair { 4 | public String uuid; 5 | public String url; 6 | } 7 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/json/ValueDisplayPair.java: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.json; 2 | 3 | public class ValueDisplayPair { 4 | public int value; 5 | public String display; 6 | } 7 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/json/VolumeStructure.java: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.json; 2 | 3 | public class VolumeStructure extends ReturnBase { 4 | public Results results; 5 | public static class Results extends InfoBase{ 6 | public ChapterStructure[] list; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/lib/Comancry.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.lib 2 | 3 | import android.util.Log 4 | import com.sun.jna.Memory 5 | import top.fumiama.copymanga.api.Config 6 | import top.fumiama.copymanga.lib.template.LazyLibrary 7 | 8 | class Comancry: LazyLibrary( 9 | ComancryMethods::class.java, "libcomancry.so", "API代理", 10 | Config.net_use_api_proxy, Config.comancry_version 11 | ) { 12 | private val enabled: Boolean 13 | get() { 14 | if (isInInit.get()) { 15 | Log.d("MyComancry", "$name block enabled for isInInit") 16 | return false 17 | } 18 | return isInUse.value 19 | } 20 | val status: String get() = if(enabled) { 21 | if (isInUse.value) "生效(手动)" else "生效(自动)" 22 | } else "无效" 23 | 24 | suspend fun decrypt(sd: String, data: ByteArray): String? { 25 | // 将 ByteArray 转换为 char* 26 | val nativeMemory = Memory(data.size.toLong()) 27 | nativeMemory.write(0, data, 0, data.size) // 将 byteArray 写入内存 28 | Log.d("MyComancry", "get data len ${data.size}") 29 | return getInstance()?.decrypt(sd, nativeMemory, data.size) 30 | } 31 | companion object { 32 | val instance = Comancry() 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/lib/ComancryMethods.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.lib 2 | 3 | import com.sun.jna.Library 4 | import com.sun.jna.Pointer 5 | 6 | interface ComancryMethods : Library { 7 | fun decrypt(sd: String, data: Pointer, len: Int): String? 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/lib/Comandy.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.lib 2 | 3 | import android.util.Log 4 | import top.fumiama.copymanga.api.Config 5 | import top.fumiama.copymanga.lib.template.LazyLibrary 6 | import top.fumiama.copymanga.net.DownloadTools 7 | 8 | class Comandy: LazyLibrary( 9 | ComandyMethods::class.java, "libcomandy.so", "网络增强", 10 | Config.net_use_comandy, Config.comandy_version 11 | ) { 12 | private var mEnabled: Boolean? = null 13 | val enabled: Boolean 14 | get() { 15 | if (isInInit.get()) { 16 | Log.d("MyComandy", "$name block enabled for isInInit") 17 | return false 18 | } 19 | if (mEnabled != true && DownloadTools.failTimes.get() >= 16) { 20 | mEnabled = true 21 | return true 22 | } 23 | if (mEnabled != null) return mEnabled!! 24 | val v = isInUse.value 25 | mEnabled = v 26 | return v 27 | } 28 | val status: String get() = if(enabled) { 29 | if (isInUse.value) "生效(手动)" else "生效(自动)" 30 | } else "无效" 31 | 32 | companion object { 33 | val instance = Comandy() 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/lib/ComandyMethods.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.lib 2 | 3 | import com.sun.jna.Library 4 | 5 | interface ComandyMethods : Library { 6 | // fun add_dns(para: String?, is_ipv6: Int): String? 7 | 8 | fun request(para: String): String? 9 | 10 | fun progress(para: String): Int 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/net/Proxy.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.net 2 | 3 | import android.util.Log 4 | import kotlinx.coroutines.Dispatchers 5 | import kotlinx.coroutines.withContext 6 | import top.fumiama.copymanga.MainActivity 7 | import top.fumiama.copymanga.api.Config.proxy_key 8 | import top.fumiama.copymanga.lib.Comancry 9 | import java.net.URLEncoder 10 | import java.nio.charset.Charset 11 | 12 | class Proxy(id: Int, private val apiRegex: Regex) { 13 | private val code get() = proxy_key.value 14 | private val proxyApiUrl = MainActivity.mainWeakReference?.get()?.getString(id) 15 | private val sourceDir = MainActivity.mainWeakReference?.get()?.applicationInfo?.sourceDir?.substringBeforeLast("/")?:"" 16 | private val enabled: Boolean get() = code.isNotEmpty() and sourceDir.isNotEmpty() and !proxyApiUrl.isNullOrEmpty() 17 | 18 | fun wrap(u: String): String { 19 | if(!apiRegex.containsMatchIn(u)) { 20 | Log.d("MyP", "[N] wrap: $u") 21 | return u 22 | } 23 | if(enabled) { 24 | val wu = proxyApiUrl?.format(code, URLEncoder.encode(u, Charset.defaultCharset().name())) 25 | ?:u 26 | Log.d("MyP", "[M] wrap: $wu") 27 | return wu 28 | } 29 | Log.d("MyP", "[C] wrap: $u") 30 | //return proxyApiUrl?.format(URLEncoder.encode(u, Charset.defaultCharset().name()))?:u 31 | return u 32 | } 33 | 34 | suspend fun comancry(u: String, use: suspend (String) -> ByteArray?): ByteArray? { 35 | if(!apiRegex.containsMatchIn(u)) { 36 | Log.d("MyP", "[N] comancry: $u") 37 | return use(u) 38 | } 39 | if(enabled) { 40 | val wu = proxyApiUrl?.format(code, 41 | withContext(Dispatchers.IO) { 42 | URLEncoder.encode(u, Charset.defaultCharset().name()) 43 | }) 44 | ?:u 45 | Log.d("MyP", "[M] comancry: $wu, sd: $sourceDir") 46 | return use(wu)?.let { data -> 47 | Log.d("MyP", "[M] comancry: decrypt ${data.size} bytes data") 48 | Comancry.instance.decrypt(sourceDir, data)?.encodeToByteArray() 49 | } 50 | } 51 | Log.d("MyP", "[C] comancry: $u") 52 | return use(u) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/net/Resolution.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.net 2 | 3 | import top.fumiama.copymanga.api.Config 4 | 5 | class Resolution(private val original: Regex) { 6 | private val imageResolution: Int 7 | get() = Config.net_img_resolution.value.let { 8 | if (it.isNotEmpty()) it.toInt() else 1500 9 | } 10 | fun wrap(u: String) : String = u.replace(original, "c${imageResolution}x.") 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/net/template/PausableDownloader.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.net.template 2 | 3 | import android.util.Log 4 | import kotlinx.coroutines.Dispatchers 5 | import kotlinx.coroutines.delay 6 | import kotlinx.coroutines.withContext 7 | import top.fumiama.copymanga.api.Config 8 | import top.fumiama.copymanga.net.DownloadTools 9 | import kotlin.random.Random 10 | 11 | class PausableDownloader(private val url: String, private val waitMilliseconds: Long = 0, private val isApi: Boolean = true, private val whenFinish: (suspend (result: ByteArray)->Unit)? = null) { 12 | var exit = false 13 | suspend fun run(): Boolean = withContext(Dispatchers.IO) { 14 | var c = 0 15 | while (!exit && c++ < 3) { 16 | try { 17 | val data = (if (isApi) Config.apiProxy?.comancry(url) { 18 | DownloadTools.getHttpContent(it, Config.referer) 19 | } else null)?:DownloadTools.getHttpContent(url, Config.referer) 20 | whenFinish?.let { it(data) } 21 | return@withContext true 22 | } catch (e: Exception) { 23 | e.printStackTrace() 24 | if (waitMilliseconds > 0) delay(200+Random.nextLong(waitMilliseconds)) 25 | } 26 | } 27 | Log.d("MyPD", "found exit = $exit") 28 | return@withContext false 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/storage/FileUtils.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.storage 2 | 3 | import android.content.Context 4 | import android.net.Uri 5 | import androidx.activity.result.ActivityResultLauncher 6 | import androidx.activity.result.contract.ActivityResultContracts 7 | import androidx.fragment.app.Fragment 8 | import java.io.BufferedOutputStream 9 | import java.io.File 10 | import java.io.FileInputStream 11 | import java.util.zip.ZipEntry 12 | import java.util.zip.ZipOutputStream 13 | 14 | object FileUtils { 15 | fun recursiveRemove(f: File) { 16 | if (f.isDirectory) f.listFiles()?.let { 17 | for (i in it) 18 | if (i.isDirectory) recursiveRemove(i) 19 | else i.delete() 20 | } 21 | f.delete() 22 | } 23 | fun sizeOf(f: File): Long{ 24 | var size = 0L 25 | if (f.isDirectory) f.listFiles()?.apply { 26 | for (i in this) 27 | size += if (i.isDirectory) sizeOf(i) else i.length() 28 | } 29 | return size 30 | } 31 | fun registerZipExportLauncher( 32 | fragment: Fragment, 33 | callback: (Uri?) -> Unit 34 | ): ActivityResultLauncher { 35 | return fragment.registerForActivityResult(ActivityResultContracts.CreateDocument("application/zip"), callback) 36 | } 37 | fun compressToUserFile( 38 | context: Context, 39 | sourceDir: File, 40 | targetUri: Uri, 41 | setProgress: (Int) -> Unit = {} 42 | ) { 43 | val allFiles = collectAllFiles(sourceDir) 44 | val totalFiles = allFiles.size 45 | var filesDone = 0 46 | 47 | setProgress(0) // 确保初始进度为0% 48 | 49 | context.contentResolver.openOutputStream(targetUri)?.use { outputStream -> 50 | ZipOutputStream(BufferedOutputStream(outputStream)).use { zipOut -> 51 | for (file in allFiles) { 52 | val relativePath = sourceDir.toURI().relativize(file.toURI()).path 53 | val entry = ZipEntry(relativePath) 54 | zipOut.putNextEntry(entry) 55 | 56 | FileInputStream(file).use { input -> 57 | input.copyTo(zipOut) 58 | } 59 | 60 | zipOut.closeEntry() 61 | filesDone++ 62 | val progress = (filesDone * 100 / totalFiles).coerceIn(0, 100) 63 | setProgress(progress) 64 | } 65 | } 66 | } 67 | 68 | setProgress(100) // 确保最终进度为100% 69 | } 70 | 71 | private fun collectAllFiles(root: File): List { 72 | val files = mutableListOf() 73 | root.walkTopDown().forEach { 74 | if (it.isFile) files.add(it) 75 | } 76 | return files 77 | } 78 | 79 | } -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/storage/PreferenceBoolean.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.storage 2 | 3 | import android.util.Log 4 | import androidx.preference.PreferenceManager 5 | import top.fumiama.copymanga.MainActivity 6 | 7 | data class PreferenceBoolean(private val key: String, private var default: Boolean) { 8 | val value: Boolean 9 | get() { 10 | MainActivity.mainWeakReference?.get()?.let { 11 | PreferenceManager.getDefaultSharedPreferences(it).apply { 12 | getBoolean(key, default).let { v -> 13 | Log.d("MyPB", "get key $key value $v") 14 | return v 15 | } 16 | } 17 | } 18 | return default 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/storage/PreferenceInt.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.storage 2 | 3 | import android.util.Log 4 | import androidx.preference.PreferenceManager 5 | import top.fumiama.copymanga.MainActivity 6 | 7 | data class PreferenceInt(private val key: String, private var default: Int) { 8 | val value: Int 9 | get() { 10 | MainActivity.mainWeakReference?.get()?.let { 11 | PreferenceManager.getDefaultSharedPreferences(it).apply { 12 | getInt(key, default).let { v -> 13 | Log.d("MyPI", "get key $key value $v") 14 | return v 15 | } 16 | } 17 | } 18 | return default 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/storage/PreferenceString.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.storage 2 | 3 | import android.util.Log 4 | import androidx.preference.PreferenceManager 5 | import top.fumiama.copymanga.MainActivity 6 | 7 | data class PreferenceString(private val key: String, private var default: String?, private val defaultID: Int) { 8 | constructor(key: Int, default: String?, defaultID: Int): this( 9 | MainActivity.mainWeakReference?.get()?.getString(key) ?:"", default, defaultID) 10 | constructor(key: String, default: Int): this(key, null, default) 11 | constructor(key: Int): this(key, "", 0) 12 | 13 | private val defaultField: String 14 | get() { 15 | if (default != null) return default!! 16 | MainActivity.mainWeakReference?.get()?.let { 17 | default = it.getString(defaultID) 18 | } 19 | return default?:"" 20 | } 21 | val value: String 22 | get() { 23 | MainActivity.mainWeakReference?.get()?.let { 24 | PreferenceManager.getDefaultSharedPreferences(it).apply { 25 | getString(key, null)?.let { v -> 26 | if (v.isNotEmpty()) { 27 | Log.d("MyPS", "get key $key value $v") 28 | return v 29 | } 30 | } 31 | } 32 | } 33 | Log.d("MyPS", "get default key $key value $defaultField") 34 | return defaultField 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/storage/PropertiesTools.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.storage 2 | //PropertiesTools.kt 3 | //created by fumiama 20200724 4 | import android.util.Log 5 | import java.io.File 6 | import java.io.InputStream 7 | import java.util.* 8 | 9 | class PropertiesTools(private val f: File):Properties() { 10 | private var cache = hashMapOf() 11 | 12 | init { 13 | if(!f.exists()) { 14 | if(f.parentFile?.exists() != true) f.parentFile?.mkdirs() 15 | if(f.parentFile?.canWrite() != true) f.parentFile?.setWritable(true) 16 | createNew(f) 17 | } else if(f.isDirectory) { 18 | if(f.parentFile?.canWrite() != true) f.parentFile?.setWritable(true) 19 | f.delete() 20 | createNew(f) 21 | } 22 | if(f.parentFile?.canWrite() != true) f.parentFile?.setWritable(true) 23 | if(f.parentFile?.canRead() != true) f.parentFile?.setReadable(true) 24 | } 25 | 26 | private fun createNew(f: File) { 27 | f.createNewFile() 28 | f.outputStream().use { o -> 29 | this.storeToXML(o, "store") 30 | } 31 | Log.d("MyPT", "Generate new prop.") 32 | } 33 | 34 | private fun loadFromXml(`in`: InputStream?): PropertiesTools { 35 | this.loadFromXML(`in`) 36 | return this 37 | } 38 | 39 | private fun setProp(key: String?, value: String?): PropertiesTools { 40 | this.setProperty(key, value) 41 | return this 42 | } 43 | 44 | operator fun get(key: String): String{ 45 | return if(cache.containsKey(key)) cache[key]?:"null" 46 | else { 47 | f.inputStream().use { i -> 48 | val re = this.loadFromXml(i).getProperty(key)?:"null" 49 | Log.d("MyPT", "Read $key = $re") 50 | cache[key] = re 51 | re 52 | } 53 | } 54 | } 55 | 56 | operator fun set(key: String, value: String) { 57 | cache[key] = value 58 | f.outputStream().use { o -> 59 | this.setProp(key, value).storeToXML(o, "store") 60 | } 61 | Log.d("MyPT", "Set $key = $value") 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/storage/UserPreferenceInt.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.storage 2 | 3 | import android.util.Log 4 | import androidx.appcompat.app.AppCompatActivity.MODE_PRIVATE 5 | import androidx.core.content.edit 6 | import top.fumiama.copymanga.MainActivity 7 | 8 | data class UserPreferenceInt(private val key: String, private var default: Int) { 9 | var value: Int? = null 10 | get() { 11 | field?.let { 12 | Log.d("MyUPI", "get cached key $key value $it") 13 | return it 14 | } 15 | MainActivity.mainWeakReference?.get()?.let { 16 | it.getPreferences(MODE_PRIVATE).apply { 17 | getInt(key, default).let { v -> 18 | field = v 19 | Log.d("MyUPI", "get new key $key value $v") 20 | return v 21 | } 22 | } 23 | } 24 | Log.d("MyUPI", "get default key $key value $default") 25 | return default 26 | } 27 | set(value) { 28 | if (value == null) { 29 | Log.d("MyUPI", "remove key $key") 30 | MainActivity.mainWeakReference?.get()?.let { 31 | it.getPreferences(MODE_PRIVATE).apply { 32 | edit(commit = true) { remove(key) } 33 | } 34 | } 35 | field = default 36 | return 37 | } 38 | field = value 39 | Log.d("MyUPI", "set key $key value $value") 40 | MainActivity.mainWeakReference?.get()?.let { 41 | it.getPreferences(MODE_PRIVATE).apply { 42 | edit(commit = true) { putInt(key, value) } 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/storage/UserPreferenceString.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.storage 2 | 3 | import android.util.Log 4 | import androidx.appcompat.app.AppCompatActivity.MODE_PRIVATE 5 | import androidx.core.content.edit 6 | import top.fumiama.copymanga.MainActivity 7 | 8 | data class UserPreferenceString(private val key: String, private var default: String?, private val defaultID: Int?) { 9 | constructor(key: String): this(key, "", 0) 10 | constructor(key: String, default: Int): this(key, null, default) 11 | constructor(key: String, default: String): this(key, default, 0) 12 | private val defaultField: String? 13 | get() { 14 | default?.let { return it } 15 | defaultID?.let { id -> 16 | MainActivity.mainWeakReference?.get()?.let { 17 | default = it.getString(id) 18 | } 19 | } 20 | return default 21 | } 22 | var value: String? = null 23 | get() { 24 | field?.let { 25 | Log.d("MyUPS", "get cached key $key value $it") 26 | return it 27 | } 28 | MainActivity.mainWeakReference?.get()?.let { 29 | it.getPreferences(MODE_PRIVATE).apply { 30 | getString(key, null)?.let { v -> 31 | if (v.isNotEmpty()) { 32 | field = v 33 | Log.d("MyUPS", "get new key $key value $v") 34 | return v 35 | } 36 | } 37 | } 38 | } 39 | field = defaultField 40 | Log.d("MyUPS", "get default key $key value $field") 41 | return field 42 | } 43 | set(value) { 44 | if (value == null) { 45 | Log.d("MyUPS", "get remove key $key") 46 | MainActivity.mainWeakReference?.get()?.let { 47 | it.getPreferences(MODE_PRIVATE).apply { 48 | edit(commit = true) { remove(key) } 49 | } 50 | } 51 | field = defaultField 52 | return 53 | } 54 | field = value 55 | Log.d("MyUPS", "set key $key value $value") 56 | MainActivity.mainWeakReference?.get()?.let { 57 | it.getPreferences(MODE_PRIVATE).apply { 58 | edit(commit = true) { putString(key, value) } 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/strings/Chinese.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.strings 2 | 3 | object Chinese { 4 | /** 5 | * 如果输入字符串中已包含汉字,直接返回。 6 | * 否则尝试以 UTF8 重新解码。 7 | */ 8 | fun fixEncodingIfNeeded(input: String): String { 9 | // 如果本身包含汉字,直接返回 10 | if (containsChinese(input)) { 11 | return input 12 | } 13 | 14 | return try { 15 | val decoded = input.toByteArray(Charsets.ISO_8859_1).decodeToString() 16 | 17 | // 检测解码后的是否包含汉字 18 | if (containsChinese(decoded)) { 19 | decoded 20 | } else { 21 | input // 解码后也没有汉字,说明可能不是编码问题 22 | } 23 | } catch (e: Exception) { 24 | input 25 | } 26 | } 27 | 28 | /** 29 | * 简单检测字符串是否包含常见 CJK(中日韩)汉字。 30 | */ 31 | fun containsChinese(text: String): Boolean { 32 | val regex = Regex("[\u4E00-\u9FFF]") 33 | return regex.containsMatchIn(text) 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/ui/cardflow/author/AuthorFragment.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.ui.cardflow.author 2 | 3 | import top.fumiama.copymanga.view.template.ThemeCardFlow 4 | import top.fumiama.dmzj.copymanga.R 5 | 6 | @ExperimentalStdlibApi 7 | class AuthorFragment : ThemeCardFlow(R.string.authorApiUrl, R.id.action_nav_author_to_nav_book) -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/ui/cardflow/caption/CaptionFragment.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.ui.cardflow.caption 2 | 3 | import top.fumiama.copymanga.view.template.ThemeCardFlow 4 | import top.fumiama.dmzj.copymanga.R 5 | 6 | @ExperimentalStdlibApi 7 | class CaptionFragment : ThemeCardFlow(R.string.captionApiUrl, R.id.action_nav_caption_to_nav_book) -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/ui/cardflow/finish/FinishFragment.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.ui.cardflow.finish 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | import top.fumiama.copymanga.view.template.StatusCardFlow 6 | import top.fumiama.dmzj.copymanga.R 7 | import kotlinx.android.synthetic.main.line_finish.* 8 | 9 | @ExperimentalStdlibApi 10 | class FinishFragment : StatusCardFlow( 11 | R.string.finishApiUrl, R.id.action_nav_finish_to_nav_book, R.layout.fragment_statuscardflow) { 12 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 13 | super.onViewCreated(view, savedInstanceState) 14 | lineUpdate = line_finish_time 15 | lineHot = line_finish_pop 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/ui/cardflow/history/HistoryFragment.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.ui.cardflow.history 2 | 3 | import android.os.Bundle 4 | import android.widget.Toast 5 | import androidx.navigation.fragment.findNavController 6 | import top.fumiama.copymanga.MainActivity 7 | import top.fumiama.copymanga.view.template.InfoCardLoader 8 | import top.fumiama.copymanga.api.Config 9 | import top.fumiama.dmzj.copymanga.R 10 | 11 | @OptIn(ExperimentalStdlibApi::class) 12 | class HistoryFragment : InfoCardLoader(R.layout.fragment_history, R.id.action_nav_history_to_nav_book, isHistoryBook = true) { 13 | override fun getApiUrl() = 14 | getString(R.string.historyApiUrl).format(Config.myHostApiUrl.random(), page * 21, Config.platform.value) 15 | 16 | override fun onCreate(savedInstanceState: Bundle?) { 17 | if (MainActivity.member?.hasLogin != true) { 18 | Toast.makeText(context, R.string.noLogin, Toast.LENGTH_SHORT).show() 19 | findNavController().popBackStack() 20 | } 21 | super.onCreate(savedInstanceState) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/ui/cardflow/newest/NewestFragment.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.ui.cardflow.newest 2 | 3 | import top.fumiama.copymanga.view.template.InfoCardLoader 4 | import top.fumiama.copymanga.api.Config 5 | import top.fumiama.dmzj.copymanga.R 6 | 7 | @ExperimentalStdlibApi 8 | class NewestFragment : InfoCardLoader(R.layout.fragment_newest, R.id.action_nav_newest_to_nav_book, true) { 9 | override fun getApiUrl() = 10 | getString(R.string.newestApiUrl).format(Config.myHostApiUrl.random(), page * 21, Config.platform.value) 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/ui/cardflow/recommend/RecFragment.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.ui.cardflow.recommend 2 | 3 | import top.fumiama.copymanga.view.template.InfoCardLoader 4 | import top.fumiama.copymanga.api.Config 5 | import top.fumiama.dmzj.copymanga.R 6 | 7 | @ExperimentalStdlibApi 8 | class RecFragment : InfoCardLoader(R.layout.fragment_recommend, R.id.action_nav_recommend_to_nav_book, true) { 9 | override fun getApiUrl() = 10 | getString(R.string.recommendApiUrl).format(Config.myHostApiUrl.random(), page * 21, Config.platform.value) 11 | } -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/ui/cardflow/search/SearchFragment.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.ui.cardflow.search 2 | 3 | import android.os.Bundle 4 | import android.util.Log 5 | import top.fumiama.copymanga.view.template.InfoCardLoader 6 | import top.fumiama.copymanga.api.Config 7 | import top.fumiama.dmzj.copymanga.R 8 | import java.net.URLEncoder 9 | import java.nio.charset.Charset 10 | 11 | @ExperimentalStdlibApi 12 | class SearchFragment : InfoCardLoader(R.layout.fragment_search, R.id.action_nav_search_to_nav_book) { 13 | private var query: String? = null 14 | private var type: String? = null 15 | override fun getApiUrl() = 16 | getString(R.string.searchApiUrl).format(Config.myHostApiUrl.random(), page * 21, query, type, Config.platform.value) 17 | 18 | override fun onCreate(savedInstanceState: Bundle?) { 19 | super.onCreate(savedInstanceState) 20 | if (isFirstInflate) { 21 | query = arguments?.getCharSequence("query")?.toString()?.let { q -> URLEncoder.encode(q, Charset.defaultCharset().name()) } 22 | type = arguments?.getString("type") 23 | Log.d("MySF", "get query=$query, type=$type") 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/ui/cardflow/topic/TopicFragment.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.ui.cardflow.topic 2 | 3 | import android.os.Bundle 4 | import androidx.lifecycle.lifecycleScope 5 | import com.google.gson.Gson 6 | import kotlinx.android.synthetic.main.app_bar_main.* 7 | import kotlinx.android.synthetic.main.fragment_topic.* 8 | import kotlinx.coroutines.Dispatchers 9 | import kotlinx.coroutines.launch 10 | import kotlinx.coroutines.withContext 11 | import top.fumiama.copymanga.json.TopicStructure 12 | import top.fumiama.copymanga.net.template.PausableDownloader 13 | import top.fumiama.copymanga.view.template.InfoCardLoader 14 | import top.fumiama.copymanga.api.Config 15 | import top.fumiama.dmzj.copymanga.R 16 | 17 | @ExperimentalStdlibApi 18 | class TopicFragment : InfoCardLoader(R.layout.fragment_topic, R.id.action_nav_topic_to_nav_book) { 19 | private var type = 1 20 | override fun getApiUrl() = 21 | getString(R.string.topicContentApiUrl).format(Config.myHostApiUrl.random(), arguments?.getString("path"), type, offset, Config.platform.value) 22 | 23 | override fun onCreate(savedInstanceState: Bundle?) { 24 | super.onCreate(savedInstanceState) 25 | lifecycleScope.launch { 26 | setProgress(5) 27 | PausableDownloader(getString(R.string.topicApiUrl).format(Config.myHostApiUrl.random(), arguments?.getString("path"), Config.platform.value)) { data -> 28 | setProgress(10) 29 | withContext(Dispatchers.IO) { 30 | if(ad?.exit == true) return@withContext 31 | data.inputStream().use { i -> 32 | val r = i.reader() 33 | Gson().fromJson(r, TopicStructure::class.java)?.apply { 34 | if(ad?.exit == true) return@withContext 35 | withContext(Dispatchers.Main) withMain@ { 36 | setProgress(15) 37 | if(ad?.exit == true) return@withMain 38 | activity?.toolbar?.title = results.title 39 | ftttime.text = results.datetime_created 40 | fttintro.text = results.intro 41 | type = results.type 42 | } 43 | } 44 | } 45 | } 46 | }.run() 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/ui/vm/PagesManager.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.ui.vm 2 | 3 | import android.widget.Toast 4 | import top.fumiama.copymanga.api.manga.Reader 5 | import top.fumiama.dmzj.copymanga.R 6 | import java.lang.ref.WeakReference 7 | 8 | class PagesManager(private val w: WeakReference) { 9 | val v get() = w.get() 10 | private var isEndL = false 11 | private var isEndR = false 12 | private val canGoPrevious get() = (v?.pageNum ?: 0) > 1 13 | private val canGoNext get() = (v?.pageNum ?: 0) < (v?.realCount ?: 0) 14 | @ExperimentalStdlibApi 15 | fun toPreviousPage(){ 16 | toPage(v?.r2l==true) 17 | } 18 | @ExperimentalStdlibApi 19 | fun toNextPage(){ 20 | toPage(v?.r2l!=true) 21 | } 22 | @ExperimentalStdlibApi 23 | fun toPage(goNext:Boolean) { 24 | v?.let { v -> 25 | if (v.clicked == 1) { 26 | v.hideDrawer() 27 | return 28 | } 29 | if (if(goNext) canGoNext else canGoPrevious) { 30 | if(goNext) { 31 | v.scrollForward() 32 | isEndR = false 33 | } else { 34 | v.scrollBack() 35 | isEndL = false 36 | } 37 | return 38 | } 39 | val chapterPosition = v.position + if(goNext) 1 else -1 40 | if (v.urlArray.isEmpty()) return 41 | if(chapterPosition < 0 || chapterPosition >= v.urlArray.size) { 42 | Toast.makeText(v.applicationContext, R.string.end_of_chapter, Toast.LENGTH_SHORT).show() 43 | return 44 | } 45 | if (if(goNext) isEndR else isEndL) { 46 | //if(v.zipFirst) intent.putExtra("callFrom", "zipFirst") 47 | v.tt.canDo = false 48 | //ViewMangaActivity.dlhandler = null 49 | v.comicName?.let { Reader.start2viewManga(it, chapterPosition, v.urlArray, v.uuidArray, goNext) } 50 | v.finish() 51 | return 52 | } 53 | val hint = if(goNext) R.string.press_again_to_load_next_chapter else R.string.press_again_to_load_previous_chapter 54 | Toast.makeText(v.applicationContext, hint, Toast.LENGTH_SHORT).show() 55 | if(goNext) isEndR = true 56 | else isEndL = true 57 | } 58 | } 59 | fun toggleDrawer() { 60 | v?.apply { 61 | when(clicked) { 62 | 0 -> showDrawer() 63 | 1 -> hideDrawer() 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/view/ChapterToggleButton.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.view 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import android.widget.ToggleButton 6 | 7 | class ChapterToggleButton: ToggleButton { 8 | constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int): super(context, attrs, defStyleAttr) 9 | constructor(context: Context?, attrs: AttributeSet?): super(context, attrs) 10 | constructor(context: Context?): super(context, null) 11 | 12 | var url: CharSequence? = null 13 | var caption: CharSequence? = null 14 | var index: Int = 0 15 | var uuid: CharSequence? = null 16 | var chapterName: CharSequence = "null" 17 | set(value) { 18 | textOn = value 19 | textOff = value 20 | text = value 21 | field = value 22 | } 23 | } -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/view/Font.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.view 2 | 3 | import android.graphics.Typeface 4 | import androidx.core.content.res.ResourcesCompat 5 | import top.fumiama.copymanga.MainActivity 6 | import top.fumiama.dmzj.copymanga.R 7 | 8 | object Font { 9 | var nisiTypeFace: Typeface? = null 10 | get() { 11 | if (field != null) return field 12 | field = MainActivity.mainWeakReference?.get()?.let { 13 | ResourcesCompat.getFont(it.applicationContext, R.font.nisi) 14 | } 15 | return field 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/view/LazyScrollView.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.view 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Context 5 | import android.util.AttributeSet 6 | import android.view.MotionEvent 7 | import android.view.View 8 | import androidx.core.widget.NestedScrollView 9 | 10 | @SuppressLint("ClickableViewAccessibility") 11 | class LazyScrollView : NestedScrollView { 12 | private val view: View? 13 | get() = getChildAt(0) 14 | 15 | constructor(context: Context) : super(context) 16 | constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) 17 | constructor(context: Context, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle) 18 | 19 | init { 20 | setOnTouchListener { _, event -> 21 | when (event.action) { 22 | MotionEvent.ACTION_UP -> this.postDelayed({ 23 | if (view != null && onScrollListener != null) { 24 | if (onScrollListener != null) { 25 | //Log.d("MyS", "view?.measuredHeight: ${view?.measuredHeight}, scrollY: $scrollY, height: $height") 26 | when { 27 | view?.measuredHeight?:0 <= scrollY + height -> onScrollListener?.onBottom() 28 | scrollY == 0 -> onScrollListener?.onTop() 29 | else -> onScrollListener?.onScroll() 30 | } 31 | } 32 | } 33 | }, 233) 34 | } 35 | false 36 | } 37 | } 38 | /** 39 | * 定义接口 40 | * @author admin 41 | */ 42 | interface OnScrollListener { 43 | fun onBottom() 44 | fun onTop() 45 | fun onScroll() 46 | } 47 | var onScrollListener: OnScrollListener? = null 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/view/MangaCardView.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.view 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import androidx.cardview.widget.CardView 6 | 7 | class MangaCardView :CardView { 8 | constructor(context: Context): super(context) 9 | constructor(context: Context, attrs: AttributeSet?): super (context, attrs) 10 | constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int): super(context, attrs, defStyleAttr) 11 | 12 | var name = "" 13 | var append: String? = null 14 | var headImageUrl: String? = null 15 | //var uuid: String? = null 16 | var path: String? = null 17 | var isFinish = false 18 | var isNew = false 19 | var index = 0 20 | var chapterUUID: String? = null 21 | var pageNumber: Int? = null 22 | } -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/view/OverScrollView.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.view 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import com.akscorp.overscrollablescrollview.OverscrollableNestedScrollView 6 | import kotlinx.android.synthetic.main.app_bar_main.* 7 | import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference 8 | 9 | open class OverScrollView :OverscrollableNestedScrollView{ 10 | constructor(context: Context) : super(context) 11 | 12 | constructor(context: Context, attrs: AttributeSet) : super(context, attrs) 13 | 14 | constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) 15 | 16 | override fun isAchieveTop(): Boolean { 17 | val re = super.isAchieveTop() 18 | if(re) mainWeakReference?.get()?.appbar?.setExpanded(true) 19 | return re 20 | } 21 | } -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/view/ScrollRefreshView.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.view 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import androidx.core.widget.NestedScrollView 6 | import androidx.swiperefreshlayout.widget.SwipeRefreshLayout 7 | 8 | class ScrollRefreshView : NestedScrollView { 9 | constructor(context: Context) : super(context) 10 | 11 | constructor(context: Context, attrs: AttributeSet) : super(context, attrs) 12 | 13 | constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super( 14 | context, 15 | attrs, 16 | defStyle 17 | ) 18 | 19 | var swipeRefreshLayout: SwipeRefreshLayout? = null 20 | 21 | override fun onScrollChanged(l: Int, t: Int, oldl: Int, oldt: Int) { 22 | super.onScrollChanged(l, t, oldl, oldt) 23 | if(swipeRefreshLayout?.isRefreshing == false) { 24 | swipeRefreshLayout?.isEnabled = t == 0 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/view/interaction/Navigate.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.view.interaction 2 | 3 | import android.os.Bundle 4 | import androidx.navigation.NavController 5 | 6 | object Navigate { 7 | fun safeNavigateTo(navController: NavController, id: Int, bundle: Bundle? = null) { 8 | navController.currentDestination?.getAction(id)?.let { 9 | navController.navigate(id, bundle) 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/view/interaction/TimeThread.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.view.interaction 2 | 3 | import android.os.Handler 4 | 5 | class TimeThread(private val handler: Handler, private val msg: Int, private val interval: Long = 3000) : Thread() { 6 | var canDo = false 7 | override fun run() { 8 | while (canDo) { 9 | try { 10 | handler.sendEmptyMessage(msg) 11 | sleep(interval) 12 | } catch (e: InterruptedException) { 13 | e.printStackTrace() 14 | } 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/view/operation/GlideBlurTransformation.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.view.operation 2 | 3 | import android.content.Context 4 | import android.graphics.Bitmap 5 | import android.renderscript.Allocation 6 | import android.renderscript.Element 7 | import android.renderscript.RenderScript 8 | import android.renderscript.ScriptIntrinsicBlur 9 | import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool 10 | import com.bumptech.glide.load.resource.bitmap.CenterCrop 11 | 12 | class GlideBlurTransformation(private val context: Context) : CenterCrop() { 13 | override fun transform( 14 | pool: BitmapPool, 15 | toTransform: Bitmap, 16 | outWidth: Int, 17 | outHeight: Int 18 | ): Bitmap { 19 | val bitmap = super.transform(pool, toTransform, outWidth, outHeight) 20 | return blurBitmap(context, bitmap, 25f, outWidth / 2, outHeight / 2) 21 | } 22 | 23 | private fun blurBitmap( 24 | context: Context?, 25 | image: Bitmap?, 26 | blurRadius: Float, 27 | outWidth: Int, 28 | outHeight: Int 29 | ): Bitmap { 30 | // 将缩小后的图片做为预渲染的图片 31 | val inputBitmap = Bitmap.createScaledBitmap(image!!, outWidth, outHeight, false) 32 | // 创建一张渲染后的输出图片 33 | val outputBitmap = Bitmap.createBitmap(inputBitmap) 34 | // 创建RenderScript内核对象 35 | val rs = RenderScript.create(context) 36 | // 创建一个模糊效果的RenderScript的工具对象 37 | val blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)) 38 | // 由于RenderScript并没有使用VM来分配内存,所以需要使用Allocation类来创建和分配内存空间 39 | // 创建Allocation对象的时候其实内存是空的,需要使用copyTo()将数据填充进去 40 | val tmpIn = Allocation.createFromBitmap(rs, inputBitmap) 41 | val tmpOut = Allocation.createFromBitmap(rs, outputBitmap) 42 | // 设置渲染的模糊程度, 25f是最大模糊度 43 | blurScript.setRadius(blurRadius) 44 | // 设置blurScript对象的输入内存 45 | blurScript.setInput(tmpIn) 46 | // 将输出数据保存到输出内存中 47 | blurScript.forEach(tmpOut) 48 | // 将数据填充到Allocation中 49 | tmpOut.copyTo(outputBitmap) 50 | return outputBitmap 51 | } 52 | } -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/view/operation/GlideHideLottieViewListener.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.view.operation 2 | 3 | import android.graphics.drawable.Drawable 4 | import android.view.View 5 | import com.airbnb.lottie.LottieAnimationView 6 | import com.bumptech.glide.load.DataSource 7 | import com.bumptech.glide.load.engine.GlideException 8 | import com.bumptech.glide.request.RequestListener 9 | import com.bumptech.glide.request.target.Target 10 | import java.lang.ref.WeakReference 11 | 12 | class GlideHideLottieViewListener(private val wla: WeakReference, private val runAfterLoad: (() -> Unit)? = null): RequestListener { 13 | override fun onLoadFailed( 14 | e: GlideException?, 15 | model: Any?, 16 | target: Target, 17 | isFirstResource: Boolean 18 | ): Boolean { 19 | return false 20 | } 21 | 22 | override fun onResourceReady( 23 | resource: Drawable, 24 | model: Any, 25 | target: Target?, 26 | dataSource: DataSource, 27 | isFirstResource: Boolean 28 | ): Boolean { 29 | wla.get()?.apply { 30 | pauseAnimation() 31 | visibility = View.GONE 32 | runAfterLoad?.let { it() } 33 | } 34 | return false 35 | } 36 | } -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/view/template/ActivityTemplate.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.view.template 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | import androidx.appcompat.app.AppCompatActivity 6 | import androidx.core.content.edit 7 | import top.fumiama.copymanga.view.interaction.UITools 8 | 9 | open class ActivityTemplate: AppCompatActivity() { 10 | lateinit var toolsBox: UITools 11 | val pb = BoolPref() 12 | private val allFullScreen 13 | get() = getPreferences(MODE_PRIVATE).getBoolean("allFullScreen", false) 14 | 15 | override fun onCreate(savedInstanceState: Bundle?) { 16 | super.onCreate(savedInstanceState) 17 | toolsBox = UITools(this) 18 | } 19 | 20 | override fun onWindowFocusChanged(hasFocus: Boolean) { 21 | super.onWindowFocusChanged(hasFocus) 22 | if(allFullScreen) window.decorView.systemUiVisibility = 23 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY 24 | } 25 | 26 | inner class BoolPref { 27 | operator fun get(key: String) = getPreferences(MODE_PRIVATE).getBoolean(key, false) 28 | operator fun set(key: String, value: Boolean) = getPreferences(MODE_PRIVATE).edit { 29 | putBoolean(key, value) 30 | apply() 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/view/template/ThemeCardFlow.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.view.template 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | import kotlinx.android.synthetic.main.app_bar_main.* 6 | import kotlinx.android.synthetic.main.line_finish.* 7 | import top.fumiama.copymanga.api.Config 8 | import top.fumiama.dmzj.copymanga.R 9 | 10 | @ExperimentalStdlibApi 11 | open class ThemeCardFlow(private val api: Int, nav: Int) : StatusCardFlow(0, nav, R.layout.fragment_statuscardflow) { 12 | private var theme = "" 13 | override fun getApiUrl() = 14 | getString(api).format( 15 | Config.myHostApiUrl.random(), 16 | page * 21, 17 | sortWay[sortValue], 18 | theme, 19 | Config.platform.value, 20 | ) 21 | 22 | override fun onCreate(savedInstanceState: Bundle?) { 23 | super.onCreate(savedInstanceState) 24 | arguments?.apply { 25 | getString("path")?.apply { theme = this } 26 | getString("name")?.apply { 27 | activity?.toolbar?.title = this 28 | } 29 | } 30 | } 31 | 32 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 33 | super.onViewCreated(view, savedInstanceState) 34 | lineUpdate = line_finish_time 35 | lineHot = line_finish_pop 36 | } 37 | 38 | override fun onResume() { 39 | super.onResume() 40 | arguments?.getString("name")?.apply { 41 | activity?.toolbar?.title = this 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /app/src/main/java/top/fumiama/copymanga/view/template/TitleActivityTemplate.kt: -------------------------------------------------------------------------------- 1 | package top.fumiama.copymanga.view.template 2 | 3 | import android.os.Bundle 4 | import kotlinx.android.synthetic.main.widget_titlebar.* 5 | 6 | open class TitleActivityTemplate: ActivityTemplate() { 7 | override fun onCreate(savedInstanceState: Bundle?) { 8 | super.onCreate(savedInstanceState) 9 | ilogo.setOnClickListener { 10 | onBackPressed() 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_in_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_in_right_exit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_out_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_out_left_exit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/bg_rnd_green.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/buttonshapewhitebg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_anchor_down.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_author.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_circle.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_data.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_email_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_hot.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_image.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_line_more.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_locate.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_lock_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_menu_del.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_menu_download.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_menu_history.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_menu_home.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_menu_rank.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_menu_sort.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_menu_sub.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_refresh.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_setting_search.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_success.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_time.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/mask_blackbottom.xml: -------------------------------------------------------------------------------- 1 | 3 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/mask_blacktop.xml: -------------------------------------------------------------------------------- 1 | 3 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/rndbg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/rndbg_checked.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/rndbg_error.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/rndbg_white.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/toggle_button.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/illust_57793944_20190427_134853.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fumiama/copymanga/d04e03132846f52498f40a7be680fce098f359c8/app/src/main/res/drawable-nodpi/illust_57793944_20190427_134853.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/img_defmask.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fumiama/copymanga/d04e03132846f52498f40a7be680fce098f359c8/app/src/main/res/drawable-nodpi/img_defmask.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/img_hot.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fumiama/copymanga/d04e03132846f52498f40a7be680fce098f359c8/app/src/main/res/drawable-nodpi/img_hot.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/img_hot_serial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fumiama/copymanga/d04e03132846f52498f40a7be680fce098f359c8/app/src/main/res/drawable-nodpi/img_hot_serial.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/img_latest_pub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fumiama/copymanga/d04e03132846f52498f40a7be680fce098f359c8/app/src/main/res/drawable-nodpi/img_latest_pub.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/img_master_work.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fumiama/copymanga/d04e03132846f52498f40a7be680fce098f359c8/app/src/main/res/drawable-nodpi/img_master_work.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/img_novel_bill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fumiama/copymanga/d04e03132846f52498f40a7be680fce098f359c8/app/src/main/res/drawable-nodpi/img_novel_bill.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/img_novel_eye.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fumiama/copymanga/d04e03132846f52498f40a7be680fce098f359c8/app/src/main/res/drawable-nodpi/img_novel_eye.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/kohima.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fumiama/copymanga/d04e03132846f52498f40a7be680fce098f359c8/app/src/main/res/drawable-nodpi/kohima.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/line_colorful.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fumiama/copymanga/d04e03132846f52498f40a7be680fce098f359c8/app/src/main/res/drawable-nodpi/line_colorful.webp -------------------------------------------------------------------------------- /app/src/main/res/font/calibri.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fumiama/copymanga/d04e03132846f52498f40a7be680fce098f359c8/app/src/main/res/font/calibri.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/gotham.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fumiama/copymanga/d04e03132846f52498f40a7be680fce098f359c8/app/src/main/res/font/gotham.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/nisi.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fumiama/copymanga/d04e03132846f52498f40a7be680fce098f359c8/app/src/main/res/font/nisi.ttf -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 16 | 17 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_viewmanga.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 21 | 22 | 28 | 29 | 40 | 41 | 42 | 43 | 51 | 52 | 61 | 62 | 71 | 72 | -------------------------------------------------------------------------------- /app/src/main/res/layout/anchor_popular.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 23 | 24 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/layout/app_bar_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 20 | 21 | 27 | 28 | 29 | 30 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/res/layout/button_tbutton.xml: -------------------------------------------------------------------------------- 1 | 2 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/card_book_plain.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 24 | 25 | 28 | 29 | 38 | 39 | 51 | 52 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /app/src/main/res/layout/content_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 23 | 24 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_progress.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 19 | 20 | 26 | 27 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_unzipping.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 17 | 18 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/layout/div_h.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_book.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 24 | 25 | 33 | 34 | 35 | 46 | 47 | 52 | 53 | 60 | 61 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_dlcomic.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 18 | 19 | 20 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_download.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_history.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_home.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 17 | 18 | 27 | 28 | 33 | 34 | 35 | 36 | 37 | 38 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_newdownload.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_newest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_rank.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_recommend.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_search.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_shelf.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_sort.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_statuscardflow.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_topic.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 18 | 19 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/layout/line_2chapters.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 17 | 18 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/layout/line_bookinfo.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 19 | 20 | 24 | 25 | 35 | 36 | 45 | 46 | 57 | 58 | -------------------------------------------------------------------------------- /app/src/main/res/layout/line_booktandb.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 |