mirror of
https://github.com/fumiama/copymanga.git
synced 2026-06-05 07:20:23 +08:00
v2.0.beta
This commit is contained in:
5
.idea/dictionaries/rumia.xml
generated
5
.idea/dictionaries/rumia.xml
generated
@@ -1,9 +1,8 @@
|
||||
<component name="ProjectDictionaryState">
|
||||
<dictionary name="rumia">
|
||||
<words>
|
||||
<w>cdwn</w>
|
||||
<w>manga</w>
|
||||
<w>rmrf</w>
|
||||
<w>copymanga</w>
|
||||
<w>fumiama</w>
|
||||
</words>
|
||||
</dictionary>
|
||||
</component>
|
||||
5
.idea/jarRepositories.xml
generated
5
.idea/jarRepositories.xml
generated
@@ -21,5 +21,10 @@
|
||||
<option name="name" value="Google" />
|
||||
<option name="url" value="https://dl.google.com/dl/android/maven2/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven" />
|
||||
<option name="name" value="maven" />
|
||||
<option name="url" value="https://jitpack.io" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
||||
12
.idea/runConfigurations.xml
generated
Normal file
12
.idea/runConfigurations.xml
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RunConfigurationProducerService">
|
||||
<option name="ignoredProducers">
|
||||
<set>
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
|
||||
</set>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
16
README.md
16
README.md
@@ -1,8 +1,16 @@
|
||||
# copymanga 拷贝漫画
|
||||
拷贝漫画的第三方APP,优化阅读/下载体验
|
||||
|
||||
# 说明
|
||||
本应用基于官方的`HLML5`手机版本网页端,作者不对其中呈现的任何内容负责
|
||||
1. 本应用原基于官方的`HTML5`手机版本网页端,官方关闭`H5`后,从`2.0`版本开始使用官方`APP`的`API`,作者不对其中呈现的任何内容负责
|
||||
2. 下载文件为`webp`格式图片,按章节打包为`zip`,可使用本应用或其他漫画阅读应用打开
|
||||
3. 若想查看下载的漫画是否有错误,可以长按该漫画目录执行查错
|
||||
4. 下载文件位于`./Android/data/top.fumiama.copymanga/files`目录
|
||||
|
||||
# 功能
|
||||
1. 阅读漫画更改为横屏模式,适于墨水屏阅读
|
||||
2. 增加下载漫画功能,但是由于不可抗力,下载速度较慢且容易出错,这绝对不是优化的原因,绝对不是
|
||||
3. 增加阅读下载的漫画的功能,但是无法切换章节,需要手动点选
|
||||
1. 浏览主页、分类,查看漫画并阅读
|
||||
2. 下载漫画。但是由于不可抗力,下载速度较慢且容易出错,这绝对不是优化的原因,绝对不是
|
||||
3. 阅读下载的漫画
|
||||
|
||||
# 未实现功能
|
||||
未在上表列出的官方`APP`的其他功能
|
||||
103
app/build.gradle
103
app/build.gradle
@@ -4,20 +4,6 @@ apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'AndResGuard'
|
||||
|
||||
android {
|
||||
compileSdkVersion 30
|
||||
buildToolsVersion "30.0.2"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "top.fumiama.copymanga"
|
||||
minSdkVersion 23
|
||||
targetSdkVersion 30
|
||||
versionCode 10
|
||||
versionName '1.3.2'
|
||||
resConfigs "zh", "zh-rCN"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
release {
|
||||
storeFile file('../../../OneDrive/swc/developer/android_key/open_key')
|
||||
@@ -27,6 +13,26 @@ android {
|
||||
v1SigningEnabled true
|
||||
v2SigningEnabled true
|
||||
}
|
||||
/*winrelease {
|
||||
storeFile file('C:/Users/spayi/OneDrive/swc/developer/android_key/open_key')
|
||||
storePassword 'fumiama'
|
||||
keyAlias 'default'
|
||||
keyPassword 'fumiama'
|
||||
v1SigningEnabled true
|
||||
v2SigningEnabled true
|
||||
}*/
|
||||
}
|
||||
compileSdkVersion 30
|
||||
|
||||
defaultConfig {
|
||||
applicationId 'top.fumiama.copymanga'
|
||||
minSdkVersion 23
|
||||
targetSdkVersion 30
|
||||
versionCode 12
|
||||
versionName '2.0.beta'
|
||||
resConfigs "zh", "zh-rCN"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
@@ -36,30 +42,60 @@ android {
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
/*debug{
|
||||
/*winrelease {
|
||||
minifyEnabled true
|
||||
shrinkResources true
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
signingConfig signingConfigs.winrelease
|
||||
}
|
||||
debug{
|
||||
minifyEnabled false
|
||||
shrinkResources false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
signingConfig signingConfigs.winrelease
|
||||
}*/
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
}
|
||||
bundle{
|
||||
density{
|
||||
enableSplit = true
|
||||
}
|
||||
language{
|
||||
enableSplit = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
implementation 'androidx.core:core-ktx:1.3.2'
|
||||
//implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||
implementation 'com.google.android.material:material:1.3.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
||||
implementation 'androidx.cardview:cardview:1.0.0'
|
||||
implementation 'androidx.viewpager2:viewpager2:1.0.0'
|
||||
//implementation 'com.google.android.material:material:1.2.1'
|
||||
testImplementation 'junit:junit:4.13.1'
|
||||
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.3'
|
||||
implementation 'androidx.navigation:navigation-ui-ktx:2.3.3'
|
||||
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.3'
|
||||
implementation 'androidx.navigation:navigation-ui-ktx:2.3.3'
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
|
||||
implementation 'com.github.bumptech.glide:glide:4.11.0'
|
||||
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
|
||||
implementation 'com.afollestad.material-dialogs:input:3.3.0'
|
||||
implementation 'com.github.yalantis:ucrop:2.2.6'
|
||||
implementation 'com.to.aboomy:pager2banner:1.0.1'
|
||||
implementation 'com.github.bumptech.glide:glide:4.12.0'
|
||||
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
|
||||
implementation 'com.google.code.gson:gson:2.8.6'
|
||||
//implementation 'com.liaoinstan.springview:library:1.7.0'
|
||||
implementation 'com.github.vovaksenov99:OverscrollableScrollView:1.0'
|
||||
implementation 'com.liaoinstan.springview:library:1.7.0'
|
||||
implementation 'com.github.zawadz88.materialpopupmenu:material-popup-menu:4.0.1'
|
||||
}
|
||||
|
||||
andResGuard {
|
||||
@@ -67,14 +103,15 @@ andResGuard {
|
||||
mappingFile = null
|
||||
use7zip = true
|
||||
useSign = true
|
||||
// 打开这个开关,会keep住所有资源的原始路径,只混淆资源的名字
|
||||
// It will keep the origin path of your resources when it's true
|
||||
keepRoot = false
|
||||
// 设置这个值,会把arsc name列混淆成相同的名字,减少string常量池的大小
|
||||
// If set, name column in arsc those need to proguard will be kept to this value
|
||||
fixedResName = "arg"
|
||||
// 打开这个开关会合并所有哈希值相同的资源,但请不要过度依赖这个功能去除去冗余资源
|
||||
// It will merge the duplicated resources, but don't rely on this feature too much.
|
||||
// it's always better to remove duplicated resource from repo
|
||||
mergeDuplicatedRes = true
|
||||
whiteList = [
|
||||
// for your icon
|
||||
// your icon
|
||||
"R.drawable.icon",
|
||||
// for fabric
|
||||
"R.string.com.crashlytics.*",
|
||||
@@ -92,20 +129,10 @@ andResGuard {
|
||||
"*.jpg",
|
||||
"*.jpeg",
|
||||
"*.gif",
|
||||
"resources.arsc"
|
||||
]
|
||||
sevenzip {
|
||||
artifact = 'com.tencent.mm:SevenZip:1.2.20'
|
||||
//path = "/usr/local/bin/7za"
|
||||
}
|
||||
|
||||
/**
|
||||
* 可选: 如果不设置则会默认覆盖assemble输出的apk
|
||||
**/
|
||||
// finalApkBackupPath = "${project.rootDir}/final.apk"
|
||||
|
||||
/**
|
||||
* 可选: 指定v1签名时生成jar文件的摘要算法
|
||||
* 默认值为“SHA-1”
|
||||
**/
|
||||
// digestalg = "SHA-256"
|
||||
}
|
||||
31
app/proguard-rules.pro
vendored
31
app/proguard-rules.pro
vendored
@@ -27,10 +27,27 @@
|
||||
**[] $VALUES;
|
||||
public *;
|
||||
}
|
||||
-keep class com.bumptech.glide.load.data.ParcelFileDescriptorRewinder$InternalRewinder {
|
||||
-keep class com.bumptech.glide.load.data.ParcelFileDescriptorRewinder.InternalRewinder$** {
|
||||
*** rewind();
|
||||
}
|
||||
|
||||
-assumenosideeffects class android.util.Log {
|
||||
public static *** d(...);
|
||||
public static *** e(...);
|
||||
public static *** i(...);
|
||||
public static *** v(...);
|
||||
public static *** println(...);
|
||||
public static *** w(...);
|
||||
public static *** wtf(...);
|
||||
}
|
||||
|
||||
-keep class com.to.aboomy.pager2banner.* {*;}
|
||||
-keep class androidx.viewpager2.widget.* {*;}
|
||||
|
||||
-dontwarn com.yalantis.ucrop**
|
||||
-keep class com.yalantis.ucrop** { *; }
|
||||
-keep interface com.yalantis.ucrop** { *; }
|
||||
|
||||
##---------------Begin: proguard configuration for Gson ----------
|
||||
# Gson uses generic type information stored in a class file when working with fields. Proguard
|
||||
# removes such information by default, so configure it to keep all of it.
|
||||
@@ -44,7 +61,7 @@
|
||||
#-keep class com.google.gson.stream.** { *; }
|
||||
|
||||
# Application classes that will be serialized/deserialized over Gson
|
||||
-keep public class top.fumiama.copymanga.data.* { *; }
|
||||
-keep class top.fumiama.dmzjxs.json.*{ *; }
|
||||
|
||||
# Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
|
||||
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
|
||||
@@ -59,13 +76,3 @@
|
||||
}
|
||||
|
||||
##---------------End: proguard configuration for Gson ----------
|
||||
|
||||
-assumenosideeffects class android.util.Log {
|
||||
public static *** d(...);
|
||||
public static *** e(...);
|
||||
public static *** i(...);
|
||||
public static *** v(...);
|
||||
public static *** println(...);
|
||||
public static *** w(...);
|
||||
public static *** wtf(...);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package top.fumiama.copymanga
|
||||
package top.fumiama.dmzj.dmzjxs
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
@@ -19,6 +19,6 @@ class ExampleInstrumentedTest {
|
||||
fun useAppContext() {
|
||||
// Context of the app under test.
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
assertEquals("top.fumiama.copymanga", appContext.packageName)
|
||||
assertEquals("top.fumiama.dmzj.dmzjxs", appContext.packageName)
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="top.fumiama.copymanga">
|
||||
package="top.fumiama.dmzj.copymanga">
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme" >
|
||||
<activity android:name=".activity.MainActivity">
|
||||
android:theme="@style/AppTheme"
|
||||
android:usesCleartextTraffic="true">
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="top.fumiama.copymanga.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/provider_paths" />
|
||||
</provider>
|
||||
<activity
|
||||
android:name="top.fumiama.copymanga.MainActivity"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme.NoActionBar">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<action android:name="top.fumiama.copymanga.SHARE"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".activity.ViewMangaActivity"/>
|
||||
<activity android:name=".activity.DlActivity"/>
|
||||
<activity android:name=".activity.DlListActivity"/>
|
||||
<activity
|
||||
android:name="top.fumiama.copymanga.LoginActivity"
|
||||
android:theme="@style/AppTheme.NoActionBar"/>
|
||||
<activity
|
||||
android:name="com.yalantis.ucrop.UCropActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>
|
||||
<activity
|
||||
android:name="top.fumiama.copymanga.ui.vm.ViewMangaActivity"
|
||||
android:theme="@style/AppTheme.NoActionBar"/>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -1,45 +0,0 @@
|
||||
javascript:
|
||||
if (typeof (loaded) == "undefined"){
|
||||
var loaded = true;
|
||||
function scanChapters(chapter){
|
||||
var chapterList = chapter.getElementsByClassName("table-all")[0].getElementsByTagName("a");
|
||||
var chapterArr = Array();
|
||||
for(var i = 0; i < chapterList.length; i++){
|
||||
chapterArr.push(JSON.constructor());
|
||||
chapterArr[i]["name"] = chapterList[i].title;
|
||||
chapterArr[i]["url"] = chapterList[i].href;
|
||||
}
|
||||
return chapterArr;
|
||||
}
|
||||
function modify(){
|
||||
var url = location.href;
|
||||
if(url.indexOf("/chapter/")>0){
|
||||
var imglist = document.getElementsByClassName("container-fluid comicContent")[0].getElementsByTagName("li");
|
||||
var nextChapter = document.getElementsByClassName("comicContent-next")[0].getElementsByTagName("a")[0].href;
|
||||
var prevChapter = document.getElementsByClassName("comicContent-prev")[1].getElementsByTagName("a")[0].href;
|
||||
if(nextChapter == location.href) nextChapter = "null";
|
||||
if(prevChapter == location.href) prevChapter = "null";
|
||||
var liststr = document.title.split(" - ")[1] + " " + location.href.substring(location.href.lastIndexOf("/")+1) + "\n" + nextChapter + "\n" + prevChapter;
|
||||
for(var i = 0; i < imglist.length; i++) liststr += "\n" + imglist[i].getElementsByTagName("img")[0].dataset.src;
|
||||
GM.loadChapter(liststr);
|
||||
}else {
|
||||
var json = Array();
|
||||
var chapters = document.getElementsByClassName("upLoop")[0].children;
|
||||
var newObj = null;
|
||||
for(var i = 0; i < chapters.length; i++) {
|
||||
if(i % 2) {
|
||||
newObj["chapters"] = scanChapters(chapters[i]);
|
||||
json.push(newObj);
|
||||
newObj = null;
|
||||
}
|
||||
else {
|
||||
newObj = JSON.constructor();
|
||||
newObj["name"] = chapters[i].innerText;
|
||||
}
|
||||
}
|
||||
GM.setTitle(document.getElementsByTagName("h6")[0].title);
|
||||
GM.setFab(JSON.stringify(json));
|
||||
}
|
||||
}
|
||||
modify();
|
||||
}else modify();
|
||||
@@ -1,47 +0,0 @@
|
||||
javascript:
|
||||
if (typeof (loaded) == "undefined") {
|
||||
var loaded = true;
|
||||
var invoke = {
|
||||
preUrl: "",
|
||||
pinTitle: function () {
|
||||
/*document.getElementsByClassName("van-button__content")[2].click();*/
|
||||
document.getElementsByClassName("indexTitle")[0].style.position = "fixed";
|
||||
document.getElementsByClassName("indexTitle")[0].style.zIndex = 999;
|
||||
document.getElementsByClassName("indexTitle")[0].style.width = document.body.clientWidth - 18 + "px";
|
||||
document.getElementsByClassName("copySwiper")[0].style.marginTop = "56px";
|
||||
document.getElementsByClassName("indexTitle")[0].style.marginTop = "-56px";
|
||||
},
|
||||
notCallGM: function (url) {
|
||||
if (this.preUrl == url) return false;
|
||||
else {
|
||||
this.preUrl = url;
|
||||
return true;
|
||||
}
|
||||
},
|
||||
clickClass: function (name, index) { document.getElementsByClassName(name)[index].click(); },
|
||||
clickClassCenter: function (name, index) {
|
||||
var ev = document.createEvent('HTMLEvents');
|
||||
ev.clientX = innerWidth / 2;
|
||||
ev.clientY = innerHeight / 2;
|
||||
ev.initEvent('click', false, true);
|
||||
document.getElementsByClassName(name)[index].dispatchEvent(ev);
|
||||
},
|
||||
resetPreUrl: function () { this.preUrl = ""; },
|
||||
loadChapter: function () { this.clickClassCenter("comicContentPopupImageItem", 0); GM.loadComic(location.href); },
|
||||
urlChangeListener: function (todo) {
|
||||
setInterval(function () { if (invoke.notCallGM(location.href)) { todo(); } }, 1000);
|
||||
}
|
||||
};
|
||||
function modify() {
|
||||
var url = location.href;
|
||||
GM.hideFab();
|
||||
if (url.endsWith("/index")) invoke.pinTitle();
|
||||
else if (url.indexOf("/comicContent/") > 0) setTimeout(function () { invoke.loadChapter() }, 1000);
|
||||
else if (url.indexOf("/details/comic/") > 0) GM.loadComic(url);
|
||||
else if (url.indexOf("/personal") > 0) GM.enterProfile();
|
||||
}
|
||||
modify();
|
||||
invoke.urlChangeListener(modify);
|
||||
} else {
|
||||
setTimeout(modify, 1280);
|
||||
}
|
||||
12
app/src/main/java/top/fumiama/copymanga/LoginActivity.kt
Normal file
12
app/src/main/java/top/fumiama/copymanga/LoginActivity.kt
Normal file
@@ -0,0 +1,12 @@
|
||||
package top.fumiama.copymanga
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import top.fumiama.dmzj.copymanga.R
|
||||
|
||||
class LoginActivity:Activity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_login)
|
||||
}
|
||||
}
|
||||
263
app/src/main/java/top/fumiama/copymanga/MainActivity.kt
Normal file
263
app/src/main/java/top/fumiama/copymanga/MainActivity.kt
Normal file
@@ -0,0 +1,263 @@
|
||||
package top.fumiama.copymanga
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.provider.MediaStore
|
||||
import android.util.Log
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.net.toUri
|
||||
import androidx.drawerlayout.widget.DrawerLayout
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.navigation.ui.AppBarConfiguration
|
||||
import androidx.navigation.ui.navigateUp
|
||||
import androidx.navigation.ui.setupActionBarWithNavController
|
||||
import androidx.navigation.ui.setupWithNavController
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.input.input
|
||||
import com.yalantis.ucrop.UCrop
|
||||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
import kotlinx.android.synthetic.main.app_bar_main.*
|
||||
import kotlinx.android.synthetic.main.nav_header_main.*
|
||||
import top.fumiama.dmzj.copymanga.R
|
||||
import top.fumiama.copymanga.tools.PropertiesTools
|
||||
import top.fumiama.copymanga.ui.download.DownloadFragment
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
var isDrawerClosed = true
|
||||
var menuMain: Menu? = null
|
||||
|
||||
private lateinit var appBarConfiguration: AppBarConfiguration
|
||||
private lateinit var p: PropertiesTools
|
||||
private lateinit var headPic: File
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main)
|
||||
setSupportActionBar(toolbar)
|
||||
//translucentStatusBar()
|
||||
coordiv.layoutParams.height = getStatusBarHeight()
|
||||
|
||||
val navController = findNavController(R.id.nav_host_fragment)
|
||||
appBarConfiguration = AppBarConfiguration(
|
||||
setOf(
|
||||
R.id.nav_home,
|
||||
R.id.nav_sort,
|
||||
R.id.nav_rank,
|
||||
R.id.nav_sub,
|
||||
R.id.nav_history,
|
||||
R.id.nav_download,
|
||||
R.id.nav_settings
|
||||
), drawer_layout
|
||||
)
|
||||
setupActionBarWithNavController(navController, appBarConfiguration)
|
||||
nav_view.setupWithNavController(navController)
|
||||
|
||||
p = PropertiesTools(File(filesDir, "database.prop"))
|
||||
headPic = File(getExternalFilesDir(""), "headPic")
|
||||
mainWeakReference = WeakReference(this)
|
||||
drawer_layout.addDrawerListener(object : DrawerLayout.DrawerListener {
|
||||
override fun onDrawerClosed(drawerView: View) {
|
||||
Log.d("MyMain", "onDrawerClosed")
|
||||
isDrawerClosed = true
|
||||
}
|
||||
|
||||
override fun onDrawerOpened(drawerView: View) {
|
||||
Log.d("MyMain", "onDrawerOpened")
|
||||
isDrawerClosed = false
|
||||
DownloadFragment.currentDir = getExternalFilesDir("")
|
||||
}
|
||||
|
||||
override fun onDrawerSlide(drawerView: View, slideOffset: Float) {}
|
||||
override fun onDrawerStateChanged(newState: Int) {}
|
||||
})
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
// Inflate the menu; this adds items to the action bar if it is present.
|
||||
menuInflater.inflate(R.menu.main, menu)
|
||||
menuMain = menu
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onSupportNavigateUp(): Boolean {
|
||||
val navController = findNavController(R.id.nav_host_fragment)
|
||||
|
||||
checkHeadPicture()
|
||||
if (headPic.exists()) navhbg.setOnLongClickListener {
|
||||
if (headPic.exists()) {
|
||||
val dl = AlertDialog.Builder(this)
|
||||
dl.setMessage(R.string.clearHeadImgMsg)
|
||||
dl.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
if (headPic.exists()) headPic.delete()
|
||||
navhbg.setImageResource(R.drawable.illust_57793944_20190427_134853)
|
||||
}
|
||||
dl.show()
|
||||
}
|
||||
true
|
||||
}
|
||||
p["navTextInfo"].let { if (it != "null") navtinfo.text = it }
|
||||
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (resultCode == RESULT_OK) when (requestCode) {
|
||||
UCrop.REQUEST_CROP -> {
|
||||
val fi = headPic.inputStream()
|
||||
navhbg.setImageBitmap(BitmapFactory.decodeStream(fi))
|
||||
fi.close()
|
||||
}
|
||||
1 -> {
|
||||
data?.data?.let {
|
||||
saveFile(it)
|
||||
cropImageUri()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int,
|
||||
permissions: Array<String?>,
|
||||
grantResults: IntArray
|
||||
) {
|
||||
when (requestCode) {
|
||||
1 -> {
|
||||
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) pickPicture()
|
||||
else Toast.makeText(this, R.string.permissionDenied, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkReadPermission(): Boolean {
|
||||
return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N && ContextCompat.checkSelfPermission(
|
||||
this,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
) != PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
ActivityCompat.requestPermissions(
|
||||
this,
|
||||
arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), 1
|
||||
)
|
||||
false
|
||||
} else true
|
||||
}
|
||||
|
||||
private fun pickPicture() {
|
||||
val i = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
|
||||
i.type = "image/*"
|
||||
startActivityForResult(i, 1)
|
||||
}
|
||||
|
||||
private fun saveFile(uri: Uri) {
|
||||
//val f = File(getExternalFilesDir(""), "headPic")
|
||||
val fd = contentResolver.openFileDescriptor(uri, "r")
|
||||
fd?.fileDescriptor?.let {
|
||||
val fi = FileInputStream(it)
|
||||
val fo = headPic.outputStream()
|
||||
fi.copyTo(fo)
|
||||
fi.close()
|
||||
fo.close()
|
||||
}
|
||||
fd?.close()
|
||||
}
|
||||
|
||||
private fun checkHeadPicture() {
|
||||
//val hp = File(getExternalFilesDir(""), "headPic")
|
||||
if (headPic.exists()) navhbg.setImageURI(headPic.toUri())
|
||||
}
|
||||
|
||||
private fun cropImageUri() {
|
||||
val op = UCrop.Options()
|
||||
val r = navhbg.width.toFloat() / navhbg.height.toFloat()
|
||||
Log.d("MyMain", "Img info: (${navhbg.width}, ${navhbg.height})")
|
||||
Log.d("MyMain", "Result code: ${UCrop.REQUEST_CROP}")
|
||||
op.setCompressionFormat(Bitmap.CompressFormat.WEBP)
|
||||
op.setStatusBarColor(resources.getColor(R.color.colorPrimaryDark, theme))
|
||||
op.setToolbarColor(resources.getColor(R.color.colorPrimary, theme))
|
||||
op.setActiveControlsWidgetColor(resources.getColor(R.color.colorAccent, theme))
|
||||
UCrop.of(headPic.toUri(), headPic.toUri())
|
||||
.withAspectRatio(r, 1F)
|
||||
.withMaxResultSize(navhbg.width, navhbg.height)
|
||||
.withOptions(op)
|
||||
.start(this)
|
||||
}
|
||||
|
||||
/*private fun translucentStatusBar() {
|
||||
//添加Flag把状态栏设为可绘制模式
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
|
||||
//如果为全透明模式,取消设置Window半透明的Flag
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
|
||||
//设置状态栏为透明
|
||||
window.statusBarColor = Color.TRANSPARENT
|
||||
//设置window的状态栏不可见
|
||||
window.decorView.systemUiVisibility =
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
//view不根据系统窗口来调整自己的布局
|
||||
val mContentView: ViewGroup = window.findViewById(Window.ID_ANDROID_CONTENT) as ViewGroup
|
||||
val mChildView: View = mContentView.getChildAt(0)
|
||||
ViewCompat.requestApplyInsets(mChildView)
|
||||
|
||||
coordiv.layoutParams.height = getStatusBarHeight()
|
||||
}*/
|
||||
|
||||
private fun getStatusBarHeight() =
|
||||
resources.getDimensionPixelOffset(
|
||||
resources.getIdentifier(
|
||||
"status_bar_height",
|
||||
"dimen",
|
||||
"android"
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
fun showAbout(item: MenuItem) {
|
||||
val dl = android.app.AlertDialog.Builder(this)
|
||||
dl.setMessage(R.string.app_description)
|
||||
dl.setTitle(R.string.action_info)
|
||||
dl.setIcon(R.mipmap.ic_launcher)
|
||||
dl.setPositiveButton(android.R.string.ok) { _, _ -> }
|
||||
dl.show()
|
||||
}
|
||||
|
||||
fun onNavTInfoClicked(it: View) {
|
||||
MaterialDialog(this).show {
|
||||
input(prefill = (it as TextView).text) { _, charSequence ->
|
||||
it.text = charSequence
|
||||
p["navTextInfo"] = charSequence.toString()
|
||||
}
|
||||
positiveButton(android.R.string.ok)
|
||||
title(R.string.navTextInfoInputHint)
|
||||
}
|
||||
}
|
||||
|
||||
fun onNavHBgClicked(v: View) {
|
||||
if (checkReadPermission()) pickPicture()
|
||||
}
|
||||
|
||||
fun startLoginActivity(v: View){
|
||||
startActivity(Intent(this, LoginActivity::class.java))
|
||||
}
|
||||
|
||||
companion object{
|
||||
var mainWeakReference: WeakReference<MainActivity>? = null
|
||||
}
|
||||
}
|
||||
@@ -1,332 +0,0 @@
|
||||
package top.fumiama.copymanga.activity
|
||||
|
||||
import android.animation.ObjectAnimator
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.Looper
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewTreeObserver
|
||||
import android.widget.Toast
|
||||
import android.widget.ToggleButton
|
||||
import com.google.gson.Gson
|
||||
import kotlinx.android.synthetic.main.activity_dl.*
|
||||
import kotlinx.android.synthetic.main.button_tbutton.view.*
|
||||
import kotlinx.android.synthetic.main.line_caption.view.*
|
||||
import kotlinx.android.synthetic.main.line_horizonal.view.*
|
||||
import kotlinx.android.synthetic.main.widget_downloadbar.*
|
||||
import kotlinx.android.synthetic.main.widget_titlebar.*
|
||||
import top.fumiama.copymanga.R
|
||||
import top.fumiama.copymanga.activity.MainActivity.Companion.mh
|
||||
import top.fumiama.copymanga.data.ComicStructure
|
||||
import top.fumiama.copymanga.handler.DlHandler
|
||||
import top.fumiama.copymanga.tool.MangaDlTools
|
||||
import top.fumiama.copymanga.tool.MangaDlTools.Companion.wmdlt
|
||||
import top.fumiama.copymanga.tool.ToolsBox
|
||||
import top.fumiama.copymanga.view.ChapterToggleButton
|
||||
import top.fumiama.copymanga.view.LazyScrollView
|
||||
import java.io.File
|
||||
import java.lang.Thread.sleep
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.zip.ZipFile
|
||||
|
||||
|
||||
class DlActivity : Activity() {
|
||||
private var tbtncnt = 0
|
||||
private var isNewTitle = false
|
||||
var haveSElectAll = false
|
||||
var checkedChapter = 0
|
||||
var dldChapter = 0
|
||||
var haveDlStarted = false
|
||||
private var btnNumPerRow = 4
|
||||
private lateinit var ltbtn: View
|
||||
var tbtnlist: Array<ChapterToggleButton> = arrayOf()
|
||||
private val handler = DlHandler(this, Looper.myLooper()!!)
|
||||
private var btnw = 0
|
||||
private var cdwnWidth = 0
|
||||
private var canDl = false
|
||||
private lateinit var toolsBox: ToolsBox
|
||||
private lateinit var mangaDlTools: MangaDlTools
|
||||
var multiSelect = false
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_dl)
|
||||
mh?.saveUrlsOnly = true
|
||||
mangaDlTools = MangaDlTools(this)
|
||||
handler.sendEmptyMessage(-2) //setLayouts
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
mh?.saveUrlsOnly = false
|
||||
wmdlt?.get()?.exit = true
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
private fun showDlCard(){
|
||||
//ObjectAnimator.ofFloat(csdwn, "alpha", 0.3f, 0.9f).setDuration(233).start()
|
||||
ObjectAnimator.ofFloat(csdwn, "translationX", cdwnWidth.toFloat() * 0.9f, 0f).setDuration(
|
||||
233
|
||||
).start()
|
||||
}
|
||||
|
||||
private fun hideDlCard(){
|
||||
//ObjectAnimator.ofFloat(csdwn, "alpha", 0.9f, 0.3f).setDuration(233).start()
|
||||
ObjectAnimator.ofFloat(csdwn, "translationX", 0f, cdwnWidth.toFloat() * 0.9f).setDuration(
|
||||
233
|
||||
).start()
|
||||
}
|
||||
|
||||
private fun fillChapters() {
|
||||
mangaDlTools.allocateChapterUrls(checkedChapter)
|
||||
for (i in tbtnlist) {
|
||||
if (i.isChecked) mangaDlTools.dlChapterUrl(i.url.toString())
|
||||
}
|
||||
}
|
||||
|
||||
private fun dlThread(dlMethod: (i: ChapterToggleButton) -> Unit) {
|
||||
sleep(10000)
|
||||
for (i in tbtnlist) {
|
||||
if (i.isChecked) dlMethod(i)
|
||||
if (!canDl) {
|
||||
checkedChapter -= dldChapter
|
||||
dldChapter = 0
|
||||
break
|
||||
}
|
||||
}
|
||||
if (canDl) {
|
||||
haveDlStarted = false
|
||||
canDl = false
|
||||
}
|
||||
handler.sendEmptyMessage(8) //set dl card color to blue
|
||||
}
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
@SuppressLint("SetTextI18n")
|
||||
fun setLayouts() {
|
||||
ttitle.text = comicName
|
||||
toolsBox = ToolsBox(WeakReference(this))
|
||||
val widthData = toolsBox.calcWidthFromDp(8, 64)
|
||||
btnNumPerRow = widthData[0]
|
||||
btnw = widthData[1]
|
||||
csdwn.viewTreeObserver.addOnGlobalLayoutListener(object :
|
||||
ViewTreeObserver.OnGlobalLayoutListener {
|
||||
override fun onGlobalLayout() {
|
||||
cdwnWidth = csdwn.width
|
||||
csdwn.viewTreeObserver.removeOnGlobalLayoutListener(this)
|
||||
}
|
||||
})
|
||||
dllazys.onScrollListener = object : LazyScrollView.OnScrollListener {
|
||||
override fun onBottom() {}
|
||||
override fun onScroll() { if (csdwn.translationX == 0f) hideDlCard() }
|
||||
override fun onTop() {}
|
||||
}
|
||||
cdwn.setOnClickListener {
|
||||
if (csdwn.translationX != 0f) showDlCard()
|
||||
else if (checkedChapter == 0) hideDlCard()
|
||||
else {
|
||||
pdwn.progress = 0
|
||||
if (canDl || checkedChapter == 0) canDl = false
|
||||
else {
|
||||
haveDlStarted = true
|
||||
canDl = true
|
||||
handler.sendEmptyMessage(9) //set dl card color to red
|
||||
Toast.makeText(this, "十秒后开始下载...", Toast.LENGTH_SHORT).show()
|
||||
fillChapters()
|
||||
Thread { dlThread { downloadChapterPages(it) } }.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
cdwn.setOnLongClickListener {
|
||||
handler.sendEmptyMessage(4)
|
||||
return@setOnLongClickListener true
|
||||
}
|
||||
isearch.setOnClickListener { showMultiSelectInfo() }
|
||||
analyzeStructure()
|
||||
}
|
||||
|
||||
private fun showMultiSelectInfo() {
|
||||
toolsBox.buildInfo("进入多选模式?", "确定后,长按下载条可选中全部漫画,而不仅限于未下载者;点击已下载漫画可进行选择。",
|
||||
"确定", null, "取消", { multiSelect = true })
|
||||
}
|
||||
|
||||
private fun analyzeStructure() {
|
||||
ViewMangaActivity.zipList = arrayOf()
|
||||
Gson().fromJson(json?.reader(), Array<ComicStructure>::class.java)?.let {
|
||||
for (group in it) {
|
||||
val tc = layoutInflater.inflate(R.layout.line_caption, ldwn, false)
|
||||
tc.tcptn.text = group.name
|
||||
ldwn.addView(
|
||||
tc,
|
||||
ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
)
|
||||
ldwn.addView(
|
||||
layoutInflater.inflate(R.layout.div_h, ldwn, false),
|
||||
ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
)
|
||||
isNewTitle = true
|
||||
for (chapter in group.chapters) addTbtn(chapter.name, chapter.url, group.name)
|
||||
}
|
||||
}
|
||||
val mangaHome = File("${getExternalFilesDir("")}/$comicName")
|
||||
val jsonFile = File(mangaHome, "info.bin")
|
||||
if(!mangaHome.exists()) mangaHome.mkdirs()
|
||||
if(!(jsonFile.exists() && intent.getBooleanExtra("callFromDlList", false))) json?.let { jsonFile.writeText(it) }
|
||||
}
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
private fun downloadChapterPages(i: ChapterToggleButton) {
|
||||
mangaDlTools.onDownloadedListener =
|
||||
object : MangaDlTools.OnDownloadedListener {
|
||||
override fun handleMessage(succeed: Boolean) {
|
||||
handler.obtainMessage(if (succeed) 1 else -1, i.index, 0)
|
||||
.sendToTarget()
|
||||
}
|
||||
override fun handleMessage(succeed: Boolean, pageNow: Int) {
|
||||
handler.obtainMessage(
|
||||
5,
|
||||
i.index,
|
||||
pageNow,
|
||||
succeed
|
||||
).sendToTarget()
|
||||
}
|
||||
override fun handleMessage(pageNow: Int){
|
||||
handler.obtainMessage(
|
||||
10,
|
||||
i.index,
|
||||
pageNow
|
||||
).sendToTarget()
|
||||
}
|
||||
}
|
||||
i.hash?.let {
|
||||
mangaDlTools.dlChapterAndPackIntoZip(
|
||||
File("${getExternalFilesDir("")}/$comicName/${i.hint}/${i.textOn}.zip"),
|
||||
it
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
fun addTbtn(title: String, url: String, caption: String) {
|
||||
if ((tbtncnt % btnNumPerRow == 0) || isNewTitle) {
|
||||
ltbtn = layoutInflater.inflate(R.layout.line_horizonal, ldwn, false)
|
||||
ldwn.addView(ltbtn)
|
||||
tbtncnt = 0
|
||||
isNewTitle = false
|
||||
}
|
||||
val tbv = layoutInflater.inflate(R.layout.button_tbutton, ltbtn.ltbtn, false)
|
||||
tbv.tbtn.index = tbtnlist.size
|
||||
tbtnlist += tbv.tbtn
|
||||
tbv.tbtn.url = url
|
||||
tbtncnt++
|
||||
val zipPosition = ViewMangaActivity.zipList?.size
|
||||
ViewMangaActivity.zipList = ViewMangaActivity.zipList?.plus("$title.zip")
|
||||
tbv.tbtn.textOff = title
|
||||
tbv.tbtn.textOn = title
|
||||
tbv.tbtn.text = title
|
||||
tbv.tbtn.hint = caption
|
||||
tbv.tbtn.layoutParams.width = btnw
|
||||
val zipf = File("${getExternalFilesDir("")}/$comicName/$caption/$title.zip")
|
||||
if (zipf.exists()) {
|
||||
tbv.tbtn.setBackgroundResource(R.drawable.rndbg_checked)
|
||||
tbv.tbtn.isChecked = false
|
||||
tbv.tbtn.freezesText = true
|
||||
}
|
||||
ltbtn.ltbtn.addView(tbv)
|
||||
ltbtn.invalidate()
|
||||
tbv.tbtn.setOnClickListener {
|
||||
val normalAct = (multiSelect && zipf.exists()) || !zipf.exists()
|
||||
if (zipf.exists() && !it.tbtn.isChecked) it.tbtn.setBackgroundResource(R.drawable.rndbg_checked)
|
||||
else if(normalAct) it.tbtn.setBackgroundResource(R.drawable.toggle_button)
|
||||
if(normalAct){
|
||||
if (it.tbtn.isChecked) tdwn.text = "$dldChapter/${++checkedChapter}"
|
||||
else tdwn.text = "$dldChapter/${--checkedChapter}"
|
||||
}else if(it.tbtn.isChecked){
|
||||
it.tbtn.isChecked = false
|
||||
zipPosition?.let { callVM(title, zipf, it) }
|
||||
}
|
||||
}
|
||||
tbv.tbtn.setOnLongClickListener {
|
||||
if (zipf.exists()) {
|
||||
toolsBox.buildInfo("确认删除这些章节?",
|
||||
"该操作将不可撤销",
|
||||
"确定",
|
||||
null,
|
||||
"取消",
|
||||
{
|
||||
if (checkedChapter == 0) {
|
||||
it.tbtn.isChecked = true
|
||||
tdwn.text = "$dldChapter/${++checkedChapter}"
|
||||
}
|
||||
handler.sendEmptyMessage(7)
|
||||
})
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteChapters() {
|
||||
for (i in tbtnlist) {
|
||||
if (i.isChecked) {
|
||||
val f = File("${getExternalFilesDir("")}/$comicName/${i.hint}/${i.textOn}.zip")
|
||||
if (f.exists()) {
|
||||
deleteChapter(f, i)
|
||||
checkedChapter--
|
||||
}
|
||||
}
|
||||
}
|
||||
handler.sendEmptyMessage(6)
|
||||
}
|
||||
|
||||
private fun callVM(titleText: String, zipFile: File, zipPosition:Int){
|
||||
ViewMangaActivity.titleText = titleText
|
||||
ViewMangaActivity.zipFile = zipFile
|
||||
//ViewMangaActivity.zipList = zipArrayList
|
||||
ViewMangaActivity.zipPosition = zipPosition
|
||||
ViewMangaActivity.cd = zipFile.parentFile
|
||||
startActivity(Intent(this, ViewMangaActivity::class.java))
|
||||
}
|
||||
|
||||
private fun deleteChapter(f: File, v: ToggleButton) {
|
||||
f.delete()
|
||||
v.setBackgroundResource(R.drawable.toggle_button)
|
||||
v.isChecked = false
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
fun updateProgressBar() {
|
||||
tdwn.text = "${++dldChapter}/$checkedChapter"
|
||||
setProgress2(dldChapter * 100 / checkedChapter, 233)
|
||||
}
|
||||
|
||||
fun updateProgressBar(pageNow: Int, size: Int) {
|
||||
val delta = 100 / checkedChapter
|
||||
val start = dldChapter * delta
|
||||
val now = pageNow * delta / size
|
||||
setProgress2(start + now, 64)
|
||||
}
|
||||
|
||||
fun setProgress2(end: Int, duration: Long) {
|
||||
ObjectAnimator.ofInt(
|
||||
pdwn,
|
||||
"progress",
|
||||
pdwn.progress,
|
||||
end
|
||||
).setDuration(duration).start()
|
||||
}
|
||||
|
||||
companion object {
|
||||
var comicName = "Null"
|
||||
var json: String? = null
|
||||
}
|
||||
}
|
||||
@@ -1,174 +0,0 @@
|
||||
package top.fumiama.copymanga.activity
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.AlertDialog
|
||||
import android.app.Dialog
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.Toast
|
||||
import kotlinx.android.synthetic.main.activity_dlist.*
|
||||
import kotlinx.android.synthetic.main.widget_titlebar.*
|
||||
import top.fumiama.copymanga.R
|
||||
import top.fumiama.copymanga.handler.DlLHandler
|
||||
import java.io.File
|
||||
import java.util.regex.Pattern
|
||||
import java.util.zip.ZipInputStream
|
||||
|
||||
class DlListActivity:Activity() {
|
||||
private var nullZipDirStr = emptyArray<String>()
|
||||
private var handler: DlLHandler? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_dlist)
|
||||
ttitle.text = intent.getStringExtra("title")
|
||||
handler = DlLHandler(Looper.myLooper()!!, this)
|
||||
handler?.obtainMessage(3, currentDir)?.sendToTarget() //call scanFile
|
||||
}
|
||||
|
||||
fun scanFile(cd: File?){
|
||||
val isRoot = cd == getExternalFilesDir("")
|
||||
val jsonFile = File(cd, "info.bin")
|
||||
if(isRoot || !jsonFile.exists()) cd?.list()?.sortedArrayWith { o1, o2 ->
|
||||
if(o1.endsWith(".zip") && o2.endsWith(".zip")) (10000*getFloat(o1) - 10000*getFloat(o2) + 0.5).toInt()
|
||||
else o1[0] - o2[0]
|
||||
}?.let {
|
||||
mylv.adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, it)
|
||||
mylv.setOnItemClickListener { _, _, position, _ ->
|
||||
val chosenFile = File(cd, it[position])
|
||||
val chosenJson = File(chosenFile, "info.bin")
|
||||
//Toast.makeText(this, "进入$chosenFile", Toast.LENGTH_SHORT).show()
|
||||
when {
|
||||
chosenJson.exists() -> callDownloadActivity(chosenJson)
|
||||
chosenFile.isDirectory -> {
|
||||
currentDir = chosenFile
|
||||
startActivity(
|
||||
Intent(
|
||||
this,
|
||||
DlListActivity::class.java
|
||||
).putExtra("title", it[position])
|
||||
)
|
||||
}
|
||||
chosenFile.name.endsWith(".zip") -> {
|
||||
Toast.makeText(this, "加载中...", Toast.LENGTH_SHORT).show()
|
||||
ViewMangaActivity.zipFile = chosenFile
|
||||
ViewMangaActivity.titleText = it[position]
|
||||
ViewMangaActivity.zipPosition = position
|
||||
ViewMangaActivity.zipList = it as Array<String>
|
||||
ViewMangaActivity.cd = cd
|
||||
startActivity(Intent(this, ViewMangaActivity::class.java))
|
||||
}
|
||||
}
|
||||
}
|
||||
mylv.setOnItemLongClickListener { _, _, position, _ ->
|
||||
val chosenFile = File(cd, it[position])
|
||||
AlertDialog.Builder(this)
|
||||
.setIcon(R.drawable.ic_launcher_foreground).setMessage("在此执行删除/查错?")
|
||||
.setTitle("提示").setPositiveButton("删除"){ _, _ ->
|
||||
if(chosenFile.exists()) handler?.obtainMessage(2, chosenFile)?.sendToTarget() //call rmrf
|
||||
handler?.obtainMessage(3, cd)?.sendToTarget() //call scanFile
|
||||
}.setNegativeButton(android.R.string.cancel){_, _ ->}
|
||||
.setNeutralButton("查错"){_, _ -> handler?.obtainMessage(1, chosenFile)?.sendToTarget()} //call checkDir
|
||||
.show()
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun rmrf(f: File) {
|
||||
if (f.isDirectory) f.listFiles()?.let {
|
||||
for (i in it)
|
||||
if (i.isDirectory) rmrf(i)
|
||||
else i.delete()
|
||||
}
|
||||
f.delete()
|
||||
}
|
||||
|
||||
fun checkDir(f: File){
|
||||
nullZipDirStr = emptyArray()
|
||||
findNullWebpZipFileInDir(f)
|
||||
if(nullZipDirStr.isNotEmpty()) showErrorZip(nullZipDirStr.joinToString("\n"))
|
||||
else Toast.makeText(this, "未发现错误", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
private fun callDownloadActivity(jsonFile: File){
|
||||
DlActivity.json = jsonFile.readText()
|
||||
DlActivity.comicName = jsonFile.parentFile?.name?:"Null"
|
||||
startActivity(
|
||||
Intent(this, DlActivity::class.java)
|
||||
.putExtra("callFromDlList", true)
|
||||
)
|
||||
}
|
||||
|
||||
private fun findNullWebpZipFileInDir(f: File){
|
||||
if (f.isDirectory) f.listFiles()?.let {
|
||||
for (i in it)
|
||||
if (i.isDirectory) findNullWebpZipFileInDir(i)
|
||||
else if(!checkZip(i)) nullZipDirStr += i.path.substringAfterLast(getExternalFilesDir("").toString())
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkZip(f: File): Boolean{
|
||||
return try {
|
||||
val exist = f.exists()
|
||||
if (!exist) true
|
||||
else {
|
||||
var re = true
|
||||
val zip = ZipInputStream(f.inputStream().buffered())
|
||||
var entry = zip.nextEntry
|
||||
while (entry != null) {
|
||||
if (!entry.isDirectory){
|
||||
if(zip.read() == -1 && entry.size == 0L){
|
||||
re = false
|
||||
break
|
||||
}
|
||||
}
|
||||
entry = zip.nextEntry
|
||||
}
|
||||
zip.closeEntry()
|
||||
zip.close()
|
||||
re
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Toast.makeText(this, "读取${f.name}错误!", Toast.LENGTH_SHORT).show()
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
private fun showErrorZip(msg: CharSequence) = AlertDialog.Builder(this)
|
||||
.setIcon(R.drawable.ic_launcher_foreground)
|
||||
.setTitle("找到以下错误文件,是否删除?")
|
||||
.setMessage(msg)
|
||||
.setPositiveButton(android.R.string.ok){_, _ -> deleteErrorZip()}
|
||||
.setNegativeButton(android.R.string.cancel){_, _ ->}
|
||||
.show()
|
||||
|
||||
private fun deleteErrorZip(){
|
||||
val exf = getExternalFilesDir("")
|
||||
for(i in nullZipDirStr){
|
||||
val f = File(exf, i)
|
||||
if(f.exists()) f.delete()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getFloat(oldString: String): Float {
|
||||
val newString = StringBuffer()
|
||||
var matcher = Pattern.compile("\\d+.+\\d+").matcher(oldString)
|
||||
while (matcher.find()) newString.append(matcher.group())
|
||||
//Log.d("MyDLL1", newString.toString())
|
||||
if(newString.isEmpty()){
|
||||
matcher = Pattern.compile("\\d").matcher(oldString)
|
||||
while (matcher.find()) newString.append(matcher.group())
|
||||
}
|
||||
//Log.d("MyDLL2", newString.toString().toFloat().toString())
|
||||
return if(newString.isEmpty()) 0f else newString.toString().toFloat()
|
||||
}
|
||||
|
||||
companion object{
|
||||
var currentDir: File? = null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
package top.fumiama.copymanga.activity
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.Looper
|
||||
import android.view.View
|
||||
import android.webkit.WebView
|
||||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
import top.fumiama.copymanga.R
|
||||
import top.fumiama.copymanga.handler.MainHandler
|
||||
import top.fumiama.copymanga.tool.ToolsBox
|
||||
import top.fumiama.copymanga.view.JSWebView
|
||||
import top.fumiama.copymanga.web.JS
|
||||
import top.fumiama.copymanga.web.JSHidden
|
||||
import top.fumiama.copymanga.web.WebChromeClient
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
class MainActivity: Activity() {
|
||||
var wh: JSWebView? = null
|
||||
var toolsBox: ToolsBox? = null
|
||||
@SuppressLint("JavascriptInterface")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main)
|
||||
|
||||
wm = WeakReference(this)
|
||||
mh = MainHandler(Looper.myLooper()!!)
|
||||
toolsBox = ToolsBox(wm as WeakReference<Any>)
|
||||
toolsBox?.netinfo?.let {
|
||||
if(it == "无网络" || it == "错误"){
|
||||
Thread{mh?.sendEmptyMessage(6)}.start()
|
||||
}else{
|
||||
WebView.setWebContentsDebuggingEnabled(true)
|
||||
w.setWebViewClient("i.js")
|
||||
w.webChromeClient = WebChromeClient()
|
||||
w.loadJSInterface(JS())
|
||||
w.loadUrl(getString(R.string.web_home))
|
||||
|
||||
wh = JSWebView(this, getString(R.string.pc_ua))
|
||||
wh?.setWebViewClient("h.js")
|
||||
wh?.loadJSInterface(JSHidden())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
if(w.canGoBack()) w.goBack()
|
||||
else super.onBackPressed()
|
||||
}
|
||||
|
||||
fun onFabClicked(v: View){
|
||||
DlListActivity.currentDir = getExternalFilesDir("")
|
||||
startActivity(
|
||||
Intent(this, (if(mh?.showDlList == true) DlListActivity::class else DlActivity::class).java)
|
||||
.putExtra("title", "我的下载")
|
||||
)
|
||||
}
|
||||
|
||||
companion object{
|
||||
var wm: WeakReference<MainActivity>? = null
|
||||
var mh: MainHandler? = null
|
||||
}
|
||||
}
|
||||
@@ -1,444 +0,0 @@
|
||||
package top.fumiama.copymanga.activity
|
||||
|
||||
import android.animation.ObjectAnimator
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.os.*
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.SeekBar
|
||||
import android.widget.Toast
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import com.bumptech.glide.Glide
|
||||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
import kotlinx.android.synthetic.main.activity_viewmanga.*
|
||||
import kotlinx.android.synthetic.main.page_imgview.*
|
||||
import kotlinx.android.synthetic.main.page_imgview.view.*
|
||||
import kotlinx.android.synthetic.main.widget_infodrawer.*
|
||||
import kotlinx.android.synthetic.main.widget_infodrawer.view.*
|
||||
import kotlinx.android.synthetic.main.widget_titlebar.*
|
||||
import kotlinx.android.synthetic.main.widget_viewmangainfo.*
|
||||
import top.fumiama.copymanga.R
|
||||
import top.fumiama.copymanga.activity.MainActivity.Companion.wm
|
||||
import top.fumiama.copymanga.handler.TimeThread
|
||||
import top.fumiama.copymanga.tool.PropertiesTools
|
||||
import top.fumiama.copymanga.tool.ToolsBox
|
||||
import java.io.File
|
||||
import java.lang.ref.WeakReference
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import java.util.zip.ZipFile
|
||||
import java.util.zip.ZipInputStream
|
||||
|
||||
|
||||
class ViewMangaActivity : Activity() {
|
||||
var count = 0
|
||||
lateinit var handler: Handler
|
||||
lateinit var tt: TimeThread
|
||||
var clicked = false
|
||||
private var isInSeek = false
|
||||
private var useFullScreen = false
|
||||
var r2l = true
|
||||
private var currentItem = 0
|
||||
private var notUseVP = true
|
||||
//private var q = 90
|
||||
var infoDrawerDelta = 0f
|
||||
lateinit var toolsBox: ToolsBox
|
||||
private lateinit var p: PropertiesTools
|
||||
private var mangaZip = zipFile
|
||||
val dlZip2View = mangaZip != null
|
||||
var pageNum = 1
|
||||
get() {
|
||||
field = getPageNumber()
|
||||
return field
|
||||
}
|
||||
set(value) {
|
||||
setPageNumber(value)
|
||||
if (notUseVP) {
|
||||
//currentItem += delta
|
||||
try {
|
||||
loadOneImg()
|
||||
} catch (e: java.lang.Exception) {
|
||||
e.printStackTrace()
|
||||
toolsBox.toastError("页数${currentItem}不合法")
|
||||
}
|
||||
}// else vp.currentItem += delta
|
||||
field = getPageNumber()
|
||||
}
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_viewmanga)
|
||||
toolsBox = ToolsBox(WeakReference(this))
|
||||
va = WeakReference(this)
|
||||
p = PropertiesTools(File("$filesDir/settings.properties"))
|
||||
useFullScreen = p["useFullScreen"] != "true"
|
||||
r2l = p["r2l"] == "true"
|
||||
//toolsBox = ToolsBox(WeakReference(this))
|
||||
notUseVP = p["noAnimation"] == "true"
|
||||
handler = MyHandler(infcard, toolsBox)
|
||||
//if (p["quality"] == "null") p["quality"] = "90"
|
||||
//else q = p["quality"].toInt()
|
||||
tt = TimeThread(handler, 22)
|
||||
tt.canDo = true
|
||||
tt.start()
|
||||
ttitle.text = titleText
|
||||
//isearch.visibility = View.VISIBLE
|
||||
Log.d("MyVM", "dlZip2View: $dlZip2View, mangaZip: $mangaZip")
|
||||
if(dlZip2View && mangaZip?.exists() != true) toolsBox.toastError("已经到头了~")
|
||||
else {
|
||||
try {
|
||||
count = if (dlZip2View) countZipItems() else imgUrls.size
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
toolsBox.toastError("分析图片url错误")
|
||||
}
|
||||
try {
|
||||
prepareItems()
|
||||
if(pn > 0) {
|
||||
pageNum = pn
|
||||
pn = -1
|
||||
}else if(pn == -2){
|
||||
pageNum = count
|
||||
pn = -1
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
toolsBox.toastError("准备控件错误")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onWindowFocusChanged(hasFocus: Boolean) {
|
||||
super.onWindowFocusChanged(hasFocus)
|
||||
if (useFullScreen) {
|
||||
window.decorView.systemUiVisibility =
|
||||
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
|
||||
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) window.setDecorFitsSystemWindows(false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPageNumber(): Int {
|
||||
return if (r2l && !notUseVP) count - vp.currentItem
|
||||
else (if (notUseVP) currentItem else vp.currentItem) + 1
|
||||
}
|
||||
|
||||
private fun setPageNumber(num: Int) {
|
||||
if (r2l && !notUseVP) vp.currentItem = count - num
|
||||
else if (notUseVP) currentItem = num - 1 else vp.currentItem = num - 1
|
||||
}
|
||||
|
||||
private fun getImgBitmap(position: Int): Bitmap? {
|
||||
if (position >= count || position < 0) return null
|
||||
else {
|
||||
val zip = ZipFile(mangaZip)
|
||||
//if (q == 100)
|
||||
return BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.webp")))
|
||||
/*else {
|
||||
val out = ByteArrayOutputStream()
|
||||
try {
|
||||
BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.jpg")))
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return null
|
||||
}?.compress(Bitmap.CompressFormat.JPEG, q, out)
|
||||
return BitmapFactory.decodeStream(ByteArrayInputStream(out.toByteArray()))
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadOneImg() {
|
||||
if(dlZip2View) onei.setImageBitmap(getImgBitmap(currentItem))
|
||||
else Glide.with(this@ViewMangaActivity)
|
||||
.load(imgUrls[currentItem])
|
||||
.placeholder(R.drawable.ic_dl)
|
||||
.dontAnimate()
|
||||
.into(onei)
|
||||
updateSeekBar()
|
||||
}
|
||||
|
||||
private fun setIdPosition(position: Int) {
|
||||
infoDrawerDelta = position.toFloat()
|
||||
infcard.translationY = infoDrawerDelta
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun prepareItems() {
|
||||
prepareVP()
|
||||
prepareInfoBar(count)
|
||||
if (notUseVP) loadOneImg() else prepareIdBtVH()
|
||||
toolsBox.dp2px(67)?.let { setIdPosition(it) }
|
||||
prepareIdBtFullScreen()
|
||||
prepareIdBtVP()
|
||||
prepareIdBtLR()
|
||||
}
|
||||
|
||||
private fun prepareIdBtLR() {
|
||||
idtblr.isChecked = r2l
|
||||
idtblr.setOnClickListener {
|
||||
if (idtblr.isChecked) p["r2l"] = "true"
|
||||
else p["r2l"] = "false"
|
||||
Toast.makeText(this, "下次浏览生效", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun prepareIdBtVP() {
|
||||
idtbvp.isChecked = notUseVP
|
||||
idtbvp.setOnClickListener {
|
||||
if (idtbvp.isChecked) p["noAnimation"] = "true"
|
||||
else p["noAnimation"] = "false"
|
||||
Toast.makeText(this, "下次浏览生效", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun prepareVP() {
|
||||
if (notUseVP) {
|
||||
vp.visibility = View.INVISIBLE
|
||||
vone.visibility = View.VISIBLE
|
||||
} else {
|
||||
vp.visibility = View.VISIBLE
|
||||
vone.visibility = View.INVISIBLE
|
||||
vp.adapter = ViewData(vp).RecyclerViewAdapter()
|
||||
vp.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
|
||||
override fun onPageSelected(position: Int) {
|
||||
updateSeekBar()
|
||||
super.onPageSelected(position)
|
||||
}
|
||||
})
|
||||
if (r2l) vp.currentItem = count - 1
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateSeekBar() {
|
||||
if (!isInSeek) hideObjs()
|
||||
updateSeekText()
|
||||
updateSeekProgress()
|
||||
sendProgress()
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun prepareInfoBar(size: Int) {
|
||||
oneinfo.alpha = 0F
|
||||
infseek.visibility = View.INVISIBLE
|
||||
isearch.visibility = View.INVISIBLE
|
||||
inftxtprogress.text = "$pageNum/$size"
|
||||
infseek.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
|
||||
override fun onProgressChanged(p0: SeekBar?, p1: Int, isHuman: Boolean) {
|
||||
if (isHuman) {
|
||||
if (p1 >= (pageNum + 1) * 100 / size) scrollForward()
|
||||
else if (p1 < (pageNum - 1) * 100 / size) scrollBack()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStartTrackingTouch(p0: SeekBar?) {
|
||||
isInSeek = true
|
||||
}
|
||||
|
||||
override fun onStopTrackingTouch(p0: SeekBar?) {
|
||||
isInSeek = false
|
||||
}
|
||||
})
|
||||
isearch.setOnClickListener {
|
||||
handler.sendEmptyMessage(3)
|
||||
}
|
||||
}
|
||||
|
||||
private fun prepareIdBtVH() {
|
||||
idtbvh.isChecked =
|
||||
p["vertical"] == "true"
|
||||
if (idtbvh.isChecked) vp.orientation = ViewPager2.ORIENTATION_VERTICAL
|
||||
idtbvh.setOnClickListener {
|
||||
if (idtbvh.isChecked) {
|
||||
vp.orientation = ViewPager2.ORIENTATION_VERTICAL
|
||||
p["vertical"] = "true"
|
||||
} else {
|
||||
vp.orientation = ViewPager2.ORIENTATION_HORIZONTAL
|
||||
p["vertical"] = "false"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun prepareIdBtFullScreen() {
|
||||
idtbfullscreen.isChecked = !useFullScreen
|
||||
idtbfullscreen.setOnClickListener {
|
||||
if (idtbfullscreen.isChecked) p["useFullScreen"] =
|
||||
"true"
|
||||
else p["useFullScreen"] = "false"
|
||||
Toast.makeText(this, "下次浏览生效", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun countZipItems(): Int {
|
||||
var c = 0
|
||||
try {
|
||||
val exist = mangaZip?.exists() == true
|
||||
if (!exist) return 0
|
||||
else {
|
||||
Log.d("Myvm", "zipf: $mangaZip")
|
||||
val zip = ZipInputStream(mangaZip?.inputStream()?.buffered())
|
||||
var entry = zip.nextEntry
|
||||
while (entry != null) {
|
||||
if (!entry.isDirectory) c++
|
||||
entry = zip.nextEntry
|
||||
}
|
||||
zip.closeEntry()
|
||||
zip.close()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
toolsBox.toastError("读取zip错误!")
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
fun scrollBack() {
|
||||
pageNum--
|
||||
}
|
||||
|
||||
fun scrollForward() {
|
||||
pageNum++
|
||||
}
|
||||
|
||||
private fun sendProgress() {
|
||||
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun updateSeekText() {
|
||||
inftxtprogress.text = "$pageNum/$count"
|
||||
}
|
||||
|
||||
private fun updateSeekProgress() {
|
||||
infseek.progress = pageNum * 100 / count
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
tt.canDo = false
|
||||
wm?.get()?.w?.goBack()
|
||||
super.onBackPressed()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
tt.canDo = false
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
inner class ViewData(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
inner class RecyclerViewAdapter :
|
||||
RecyclerView.Adapter<ViewData>() {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewData {
|
||||
return ViewData(
|
||||
LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.page_imgview, parent, false)
|
||||
)
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility", "SetTextI18n")
|
||||
override fun onBindViewHolder(holder: ViewData, position: Int) {
|
||||
val pos = if (r2l) count - position - 1 else position
|
||||
if(dlZip2View) getImgBitmap(pos)?.let {
|
||||
//Glide.with(this@ViewMangaActivity).load(it).placeholder(R.drawable.bg_comment).into(holder.itemView.onei)
|
||||
holder.itemView.onei.setImageBitmap(it)
|
||||
}
|
||||
else Glide.with(this@ViewMangaActivity).load(imgUrls[pos]).placeholder(R.drawable.ic_dl).dontAnimate().timeout(10000).into(holder.itemView.onei)
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return count
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun showObjs() {
|
||||
infseek.visibility = View.VISIBLE
|
||||
isearch.visibility = View.VISIBLE
|
||||
ObjectAnimator.ofFloat(
|
||||
oneinfo,
|
||||
"alpha",
|
||||
oneinfo.alpha,
|
||||
1F
|
||||
).setDuration(233).start()
|
||||
clicked = true
|
||||
}
|
||||
|
||||
fun hideObjs() {
|
||||
ObjectAnimator.ofFloat(
|
||||
oneinfo,
|
||||
"alpha",
|
||||
oneinfo.alpha,
|
||||
0F
|
||||
).setDuration(233).start()
|
||||
clicked = false
|
||||
infseek.postDelayed({
|
||||
infseek.visibility = View.INVISIBLE
|
||||
isearch.visibility = View.INVISIBLE
|
||||
}, 300)
|
||||
handler.sendEmptyMessage(1)
|
||||
}
|
||||
|
||||
class MyHandler(
|
||||
private val infcard: View,
|
||||
private val toolsBox: ToolsBox
|
||||
) : Handler(Looper.myLooper()!!) {
|
||||
private var infcShowed = false
|
||||
private var delta = -1f
|
||||
get() {
|
||||
if (field < 0) field = va?.get()?.infoDrawerDelta ?: 0f
|
||||
return field
|
||||
}
|
||||
|
||||
@SuppressLint("SimpleDateFormat", "SetTextI18n")
|
||||
override fun handleMessage(msg: Message) {
|
||||
super.handleMessage(msg)
|
||||
when (msg.what) {
|
||||
1 -> if (infcShowed) {
|
||||
hideInfCard(); infcShowed = false
|
||||
}
|
||||
2 -> if (!infcShowed) {
|
||||
showInfCard(); infcShowed = true
|
||||
}
|
||||
3 -> infcShowed = if (infcShowed) {
|
||||
hideInfCard(); false
|
||||
} else {
|
||||
showInfCard(); true
|
||||
}
|
||||
22 -> toolsBox.zis?.idtime?.text =
|
||||
SimpleDateFormat("HH:mm").format(Date()) + toolsBox.week + toolsBox.netinfo
|
||||
}
|
||||
}
|
||||
|
||||
private fun showInfCard() {
|
||||
ObjectAnimator.ofFloat(infcard.idc, "alpha", 0.3F, 0.8F).setDuration(233).start()
|
||||
ObjectAnimator.ofFloat(infcard, "translationY", delta, 0F).setDuration(233).start()
|
||||
}
|
||||
|
||||
private fun hideInfCard() {
|
||||
ObjectAnimator.ofFloat(infcard.idc, "alpha", 0.8F, 0.3F).setDuration(233).start()
|
||||
ObjectAnimator.ofFloat(infcard, "translationY", 0F, delta).setDuration(233).start()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
var va: WeakReference<ViewMangaActivity>? = null
|
||||
var imgUrls = arrayOf<String>()
|
||||
var zipFile: File? = null
|
||||
get() {
|
||||
val re = field
|
||||
if(field != null) field = null
|
||||
return re
|
||||
}
|
||||
var titleText = "Null"
|
||||
var nextChapterUrl: String? = null
|
||||
var previousChapterUrl: String? = null
|
||||
var zipPosition = 0
|
||||
var zipList: Array<String>? = null
|
||||
var cd: File? = null
|
||||
var pn = -1
|
||||
}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
package top.fumiama.copymanga.handler
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.os.Message
|
||||
import android.widget.Toast
|
||||
import android.widget.ToggleButton
|
||||
import kotlinx.android.synthetic.main.widget_downloadbar.*
|
||||
import top.fumiama.copymanga.R
|
||||
import top.fumiama.copymanga.activity.DlActivity
|
||||
import top.fumiama.copymanga.tool.MangaDlTools.Companion.wmdlt
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
class DlHandler(activity: DlActivity, looper: Looper) : Handler(looper) {
|
||||
private val da = WeakReference(activity)
|
||||
private val d
|
||||
get() = da.get()
|
||||
private var size = 0
|
||||
private var refreshSize = true
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun handleMessage(msg: Message) {
|
||||
super.handleMessage(msg)
|
||||
when (msg.what) {
|
||||
-2 -> d?.setLayouts()
|
||||
1 -> {
|
||||
d?.tbtnlist?.get(msg.arg1)?.setBackgroundResource(R.drawable.rndbg_checked)
|
||||
d?.tbtnlist?.get(msg.arg1)?.isChecked = false
|
||||
d?.updateProgressBar()
|
||||
if (d?.haveDlStarted == false) {
|
||||
d?.dldChapter = 0
|
||||
d?.checkedChapter = 0
|
||||
this.postDelayed({
|
||||
d?.setProgress2(0, 233)
|
||||
d?.tdwn?.text = "0/0"
|
||||
}, 400)
|
||||
}
|
||||
}
|
||||
-1 -> {
|
||||
d?.tbtnlist?.get(msg.arg1)?.setBackgroundResource(R.drawable.rndbg_error)
|
||||
d!!.dldChapter--
|
||||
Toast.makeText(d, "下载${d?.tbtnlist?.get(msg.arg1)?.textOn}失败", Toast.LENGTH_SHORT).show()
|
||||
d?.updateProgressBar()
|
||||
}
|
||||
4 -> {
|
||||
d?.pdwn?.progress = 0
|
||||
val selectDownloaded = d?.multiSelect?:false
|
||||
if (d?.haveSElectAll == true) {
|
||||
d?.tbtnlist?.forEach { i ->
|
||||
if(i.freezesText) i.setBackgroundResource(R.drawable.rndbg_checked) else i.setBackgroundResource(R.drawable.toggle_button)
|
||||
i.isChecked = false
|
||||
}
|
||||
d?.haveSElectAll = false
|
||||
d?.checkedChapter = 0
|
||||
d?.dldChapter = 0
|
||||
} else {
|
||||
d?.let {
|
||||
val checkBtn = { i: ToggleButton, it: DlActivity ->
|
||||
i.setBackgroundResource(R.drawable.toggle_button)
|
||||
i.isChecked = true
|
||||
it.checkedChapter++
|
||||
}
|
||||
for (i in it.tbtnlist) {
|
||||
if(selectDownloaded) checkBtn(i, it)
|
||||
else if(!i.freezesText) checkBtn(i, it)
|
||||
}
|
||||
}
|
||||
d?.haveSElectAll = true
|
||||
}
|
||||
d?.tdwn?.text = "${d?.dldChapter}/${d?.checkedChapter}"
|
||||
}
|
||||
5 -> {
|
||||
setSize(msg.arg2, msg.arg1)
|
||||
d?.updateProgressBar(msg.arg2, size)
|
||||
if (!(msg.obj as Boolean)) {
|
||||
Toast.makeText(d, "下载${d?.tbtnlist?.get(msg.arg1)?.textOn}的第${msg.arg2}页失败", Toast.LENGTH_SHORT).show()
|
||||
}else{
|
||||
val progressTxt = d?.tdwn?.text.toString()
|
||||
d?.tdwn?.text = "${progressTxt.substringBefore(' ')} 的 ${msg.arg2}/${size} 页"
|
||||
}
|
||||
}
|
||||
6 -> d?.tdwn?.text = "${d?.dldChapter}/${d?.checkedChapter}"
|
||||
7 -> d?.deleteChapters()
|
||||
8 -> d?.resources?.getColor(R.color.colorBlue)?.let { d?.cdwn?.setCardBackgroundColor(it) }
|
||||
9 -> d?.resources?.getColor(R.color.colorRed)?.let { d?.cdwn?.setCardBackgroundColor(it) }
|
||||
10 -> Toast.makeText(d, "下载${d?.tbtnlist?.get(msg.arg1)?.textOn}的第${msg.arg2}页失败,尝试重新下载...", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
private fun setSize(pageNow: Int, tbtnNo: Int){
|
||||
if(refreshSize || size == 0) {
|
||||
size = d?.tbtnlist?.get(tbtnNo)?.hash?.let { wmdlt?.get()?.getImgsCountByHash(it) }?:0
|
||||
refreshSize = false
|
||||
}else if(pageNow == size) refreshSize = true
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
package top.fumiama.copymanga.handler
|
||||
|
||||
import android.animation.ObjectAnimator
|
||||
import android.content.Intent
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.os.Message
|
||||
import android.view.View
|
||||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
import top.fumiama.copymanga.activity.DlActivity.Companion.json
|
||||
import top.fumiama.copymanga.activity.MainActivity.Companion.wm
|
||||
import top.fumiama.copymanga.activity.ViewMangaActivity
|
||||
import top.fumiama.copymanga.tool.MangaDlTools.Companion.wmdlt
|
||||
|
||||
class MainHandler(looper: Looper):Handler(looper) {
|
||||
var saveUrlsOnly = false
|
||||
var showDlList = false
|
||||
override fun handleMessage(msg: Message) {
|
||||
super.handleMessage(msg)
|
||||
when(msg.what){
|
||||
1 -> loadUrlInHiddenWebView(msg.obj as String)
|
||||
2 -> callViewManga(msg.obj as String)
|
||||
3 -> updateLoadProgress(msg.arg1)
|
||||
4 -> setFab(msg.obj as String)
|
||||
5 -> hideFab()
|
||||
6 -> setFab2DlList()
|
||||
}
|
||||
}
|
||||
private fun loadUrlInHiddenWebView(url: String){wm?.get()?.wh?.loadUrl(url)}
|
||||
private fun callViewManga(content: String){
|
||||
val listChapter = content.split('\n')
|
||||
if(!saveUrlsOnly) {
|
||||
ViewMangaActivity.titleText = listChapter[0].substringBeforeLast(' ')
|
||||
ViewMangaActivity.nextChapterUrl = listChapter[1].let { if(it == "null") null else it }
|
||||
ViewMangaActivity.previousChapterUrl = listChapter[2].let { if(it == "null") null else it }
|
||||
ViewMangaActivity.imgUrls = arrayOf()
|
||||
for(i in 3 until listChapter.size) ViewMangaActivity.imgUrls += listChapter[i]
|
||||
wm?.get()?.let { it.startActivity(Intent(it, ViewMangaActivity::class.java)) }
|
||||
} else{
|
||||
var imgs = arrayOf<String>()
|
||||
for(i in 3 until listChapter.size) imgs += listChapter[i]
|
||||
wmdlt?.get()?.setChapterImgs(listChapter[0].substringAfterLast(' '), imgs)
|
||||
}
|
||||
}
|
||||
private fun updateLoadProgress(progress: Int){
|
||||
wm?.get()?.let{
|
||||
if(it.pw.progress == 100 && progress < 100) {
|
||||
it.pw.progress = 0
|
||||
it.pw.visibility = View.VISIBLE
|
||||
}
|
||||
ObjectAnimator.ofInt(it.pw, "progress", it.pw.progress, progress).setDuration(233).start()
|
||||
if(progress == 100) it.pw.postDelayed({it.pw.visibility = View.GONE}, 500)
|
||||
}
|
||||
}
|
||||
private fun showFab() {wm?.get()?.fab?.visibility = View.VISIBLE}
|
||||
private fun hideFab() {wm?.get()?.fab?.visibility = View.GONE}
|
||||
private fun setFab(content: String){
|
||||
//Log.d("MyMH", "Get chapter json: $content")
|
||||
showDlList = false
|
||||
json = content
|
||||
showFab()
|
||||
}
|
||||
private fun setFab2DlList(){
|
||||
showDlList = true
|
||||
showFab()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package top.fumiama.copymanga.json;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class BookInfoStructure extends ReturnBase {
|
||||
public Results results;
|
||||
public static class Results extends ResultsBase{
|
||||
public ComicStructure comic;
|
||||
public HashMap<String, ThemeStructure> groups;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package top.fumiama.copymanga.json;
|
||||
|
||||
public class BookListStructure extends ReturnBase {
|
||||
public Results results;
|
||||
public static class Results {
|
||||
public int total;
|
||||
public ComicStructure[] list;
|
||||
public int limit;
|
||||
public int offset;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package top.fumiama.copymanga.json;
|
||||
|
||||
public class Chapter2Return extends ReturnBase {
|
||||
public Results results;
|
||||
public static class Results extends ResultsBase{
|
||||
public ComicStructure comic;
|
||||
public ChapterWithContent chapter;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package top.fumiama.copymanga.json;
|
||||
|
||||
public class ChapterStructure {
|
||||
public int index;
|
||||
public String uuid;
|
||||
public int count;
|
||||
public int size;
|
||||
public String name;
|
||||
public String comic_id;
|
||||
public String comic_path_word;
|
||||
public String group_id;
|
||||
public String group_path_word;
|
||||
public int type;
|
||||
public int img_type;
|
||||
public String datetime_created;
|
||||
public String prev;
|
||||
public String next;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package top.fumiama.copymanga.json;
|
||||
|
||||
public class ChapterWithContent extends ChapterStructure {
|
||||
public UUIDUrlPair[] contents;
|
||||
public int[] words;
|
||||
public Boolean is_long;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package top.fumiama.copymanga.json;
|
||||
|
||||
public class ComicStructure {
|
||||
public String uuid;
|
||||
public String name;
|
||||
public String alias;
|
||||
public ValueDisplayPair status;
|
||||
public ThemeStructure[] theme;
|
||||
public String path_word;
|
||||
public ThemeStructure[] author;
|
||||
public int img_type;
|
||||
public String brief;
|
||||
public String datetime_updated;
|
||||
public String cover;
|
||||
public int popular;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package top.fumiama.copymanga.data;
|
||||
package top.fumiama.copymanga.json;
|
||||
|
||||
public class ComicStructure {
|
||||
public class ComicStructureOld {
|
||||
public String name;
|
||||
public Chapters[] chapters;
|
||||
public static class Chapters{
|
||||
@@ -0,0 +1,8 @@
|
||||
package top.fumiama.copymanga.json;
|
||||
|
||||
public class FilterStructure extends ReturnBase {
|
||||
public Results results;
|
||||
public static class Results{
|
||||
public ThemeStructure[] theme;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package top.fumiama.copymanga.json;
|
||||
|
||||
public class IndexStructure extends ReturnBase {
|
||||
public Results results;
|
||||
public static class Results{
|
||||
public Banners[] banners;
|
||||
public Topics topics;
|
||||
public RecComics recComics;
|
||||
public RankComics rankDayComics;
|
||||
public RankComics rankWeekComics;
|
||||
public RankComics rankMonthComics;
|
||||
public ComicWrap[] hotComics;
|
||||
public ComicWrap[] newComics;
|
||||
public FinishComics finishComics;
|
||||
|
||||
public static class Banners{
|
||||
public String cover;
|
||||
public String brief;
|
||||
public String out_uuid;
|
||||
public ComicStructure comic;
|
||||
}
|
||||
public static class Topics extends InfoBase{
|
||||
public List[] list;
|
||||
|
||||
public static class List{
|
||||
public String title;
|
||||
public SeriesStructure series;
|
||||
public String journal;
|
||||
public String cover;
|
||||
public String period;
|
||||
public int type;
|
||||
public String brief;
|
||||
public String path_word;
|
||||
public String datetime_created;
|
||||
}
|
||||
}
|
||||
public static class RecComics extends InfoBase{
|
||||
public List[] list;
|
||||
|
||||
public static class List{
|
||||
public int type;
|
||||
public ComicStructure comic;
|
||||
}
|
||||
}
|
||||
public static class RankComics extends InfoBase{
|
||||
public InfoStructure[] list;
|
||||
}
|
||||
public static class ComicWrap{
|
||||
public ComicStructure comic;
|
||||
}
|
||||
public static class FinishComics extends InfoBase{
|
||||
public ComicStructure[] list;
|
||||
public String path_word;
|
||||
public String name;
|
||||
public String type;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package top.fumiama.copymanga.json;
|
||||
|
||||
public class InfoBase {
|
||||
public int total;
|
||||
public int limit;
|
||||
public int offset;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package top.fumiama.copymanga.json;
|
||||
|
||||
public class InfoStructure {
|
||||
public int sort;
|
||||
public int sort_last;
|
||||
public int rise_sort;
|
||||
public int rise_num;
|
||||
public int date_type;
|
||||
public int popular;
|
||||
public ComicStructure comic;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package top.fumiama.copymanga.json;
|
||||
|
||||
public class ResultsBase {
|
||||
public Boolean is_lock;
|
||||
public Boolean is_login;
|
||||
public Boolean is_mobile_bind;
|
||||
public Boolean is_vip;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package top.fumiama.copymanga.json;
|
||||
|
||||
public class ReturnBase {
|
||||
public int code;
|
||||
public String message;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package top.fumiama.copymanga.json;
|
||||
|
||||
public class SeriesStructure extends ThemeStructure {
|
||||
public String color;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package top.fumiama.copymanga.json;
|
||||
|
||||
public class ThemeStructure {
|
||||
public String name;
|
||||
public String path_word;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package top.fumiama.copymanga.json;
|
||||
|
||||
public class UUIDUrlPair {
|
||||
public String uuid;
|
||||
public String url;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package top.fumiama.copymanga.json;
|
||||
|
||||
public class ValueDisplayPair {
|
||||
public int value;
|
||||
public String display;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package top.fumiama.copymanga.json;
|
||||
|
||||
public class VolumeStructure extends ReturnBase {
|
||||
public Results results;
|
||||
public static class Results extends InfoBase{
|
||||
public ChapterStructure[] list;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package top.fumiama.copymanga.template
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import top.fumiama.copymanga.tools.PropertiesTools
|
||||
import top.fumiama.copymanga.tools.UITools
|
||||
import java.io.File
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
open class ActivityTemplate:Activity() {
|
||||
lateinit var p: PropertiesTools
|
||||
lateinit var toolsBox: UITools
|
||||
private val allFullScreen
|
||||
get() = p["allFullScreen"] == "true"
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
p = PropertiesTools(File("$filesDir/settings.properties"))
|
||||
toolsBox = UITools(WeakReference(this))
|
||||
}
|
||||
|
||||
override fun onWindowFocusChanged(hasFocus: Boolean) {
|
||||
super.onWindowFocusChanged(hasFocus)
|
||||
if(allFullScreen) window.decorView.systemUiVisibility =
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package top.fumiama.copymanga.template
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.os.Message
|
||||
import android.util.Log
|
||||
import com.google.gson.Gson
|
||||
import top.fumiama.dmzj.copymanga.R
|
||||
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
|
||||
import top.fumiama.copymanga.json.ReturnBase
|
||||
import top.fumiama.copymanga.tools.DownloadTools
|
||||
import top.fumiama.copymanga.tools.TimeThread
|
||||
|
||||
open class AutoDownloadHandler(private val url: String, private val jsonClass: Class<*>, looper: Looper, private val callCheckMsg: Int = -1): Handler(looper) {
|
||||
private var timeThread: TimeThread? = null
|
||||
private var checkTimes = 0
|
||||
override fun handleMessage(msg: Message) {
|
||||
super.handleMessage(msg)
|
||||
when(msg.what){
|
||||
callCheckMsg -> check()
|
||||
0 -> setLayouts()
|
||||
}
|
||||
}
|
||||
open fun setGsonItem(gsonObj: Any) {}
|
||||
open fun getGsonItem(): ReturnBase? = null
|
||||
open fun onError() {}
|
||||
open fun doWhenFinishDownload() {}
|
||||
fun startLoad() {
|
||||
sendEmptyMessage(0)
|
||||
}
|
||||
private fun download(){
|
||||
Thread{
|
||||
DownloadTools.getHttpContent(url,
|
||||
mainWeakReference?.get()?.getString(R.string.referUrl)!!,
|
||||
mainWeakReference?.get()?.getString(R.string.pc_ua)!!
|
||||
)?.let {
|
||||
val fi = it.inputStream()
|
||||
setGsonItem(Gson().fromJson(fi.reader(), jsonClass))
|
||||
fi.close()
|
||||
}
|
||||
}.start()
|
||||
checkTimes = 0
|
||||
timeThread = TimeThread(this, callCheckMsg)
|
||||
timeThread?.canDo = true
|
||||
timeThread?.start()
|
||||
}
|
||||
private fun check(){
|
||||
val g = getGsonItem()
|
||||
if(g != null) {
|
||||
timeThread?.canDo = false
|
||||
if(g.code == 200) sendEmptyMessage(0)
|
||||
else onError()
|
||||
Log.d("MyADH", "[${g.code}]${g.message}")
|
||||
} else if(checkTimes++ > 10) timeThread?.canDo = false
|
||||
}
|
||||
private fun setLayouts() {
|
||||
if(getGsonItem() == null) download()
|
||||
else doWhenFinishDownload()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package top.fumiama.copymanga.template
|
||||
|
||||
import top.fumiama.dmzj.copymanga.R
|
||||
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
|
||||
import top.fumiama.copymanga.tools.DownloadTools
|
||||
|
||||
class AutoDownloadThread(private val url: String, private val whenFinish: (result: ByteArray?)->Unit): Thread() {
|
||||
override fun run() {
|
||||
super.run()
|
||||
var re: ByteArray? = null
|
||||
var c = 0
|
||||
while (re == null && c++ < 3){
|
||||
re = DownloadTools.getHttpContent(url,
|
||||
mainWeakReference?.get()?.getString(R.string.referUrl)!!,
|
||||
mainWeakReference?.get()?.getString(R.string.pc_ua)!!
|
||||
)
|
||||
}
|
||||
whenFinish(re)
|
||||
}
|
||||
}
|
||||
109
app/src/main/java/top/fumiama/copymanga/template/CardList.kt
Normal file
109
app/src/main/java/top/fumiama/copymanga/template/CardList.kt
Normal file
@@ -0,0 +1,109 @@
|
||||
package top.fumiama.copymanga.template
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.model.GlideUrl
|
||||
import kotlinx.android.synthetic.main.card_book.view.*
|
||||
import kotlinx.android.synthetic.main.line_horizonal_empty.view.*
|
||||
import kotlinx.android.synthetic.main.line_lazybooklines.*
|
||||
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
|
||||
import top.fumiama.copymanga.tools.CMApi
|
||||
import top.fumiama.dmzj.copymanga.R
|
||||
import java.io.File
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
class CardList(
|
||||
fragment: WeakReference<Fragment>,
|
||||
private val cardWidth: Int,
|
||||
private val cardHeight: Int,
|
||||
private val cardPerRow: Int
|
||||
) {
|
||||
private val that = fragment.get()
|
||||
private var rows:Array<View?> = arrayOfNulls(20)
|
||||
private var index = 0
|
||||
private var count = 0
|
||||
var initClickListeners: InitClickListeners? = null
|
||||
|
||||
fun reset(){
|
||||
rows = arrayOfNulls(20)
|
||||
index = 0
|
||||
count = 0
|
||||
}
|
||||
|
||||
private fun manageRow(){
|
||||
if(count++ % cardPerRow == 0) inflateRow()
|
||||
Log.d("MyCL", "index: $index, cardPR: $cardPerRow")
|
||||
}
|
||||
|
||||
private fun inflateRow(){
|
||||
that?.layoutInflater?.inflate(R.layout.line_horizonal_empty, that.mydll, false)?.let {
|
||||
it.layoutParams.height = cardHeight + 16
|
||||
mainWeakReference?.get()?.runOnUiThread {
|
||||
that.mydll.addView(it)
|
||||
}
|
||||
recycleOneRow(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun recycleOneRow(v:View?){
|
||||
if(index < 20) rows[index] = v
|
||||
else{
|
||||
mainWeakReference?.get()?.runOnUiThread {
|
||||
that?.mydll?.removeView(rows[index % 20])
|
||||
//zis.mys?.scrollY = zis.mys?.scrollY?.minus(cardHeight + 16)?:0
|
||||
}
|
||||
rows[index % 20] = v
|
||||
}
|
||||
index++
|
||||
}
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
fun addCard(name: String, append: String? = null, head: String? = null, path: String? = null, chapterUUID: String? = null, pn: Int? = null, isFinish: Boolean = false){
|
||||
manageRow()
|
||||
that?.layoutInflater?.inflate(R.layout.card_book, that.mydll.ltbtn, false)?.let {
|
||||
val card = it.cic
|
||||
card.name = name
|
||||
card.append = append
|
||||
card.headImageUrl = head
|
||||
card.path = path
|
||||
card.index = index - 1
|
||||
card.chapterUUID = chapterUUID
|
||||
card.pageNumber = pn
|
||||
card.isFinish = isFinish
|
||||
mainWeakReference?.get()?.runOnUiThread{
|
||||
addCard(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
@SuppressLint("SetTextI18n")
|
||||
@ExperimentalStdlibApi
|
||||
fun addCard(cardFrame: View) {
|
||||
val card = cardFrame.cic
|
||||
val name = card.name + (card.append?:"")
|
||||
val head = card.headImageUrl
|
||||
val file = File(that?.context?.getExternalFilesDir(""), card.name)
|
||||
cardFrame.let {
|
||||
it.tic.text = name
|
||||
if(!file.exists()){
|
||||
that?.context?.let { context ->
|
||||
Glide.with(context).load(GlideUrl(head, CMApi.myGlideHeaders)).into(it.imic)
|
||||
}
|
||||
}else {
|
||||
val img = File(file, "head.jpg")
|
||||
if(img.exists()) it.imic.setImageURI(Uri.fromFile(img))
|
||||
}
|
||||
if(card.isFinish) it.sgnic.visibility = View.VISIBLE
|
||||
initClickListeners?.prepareListeners(card, card.name, card.path, card.chapterUUID, card.pageNumber)
|
||||
rows[card.index % 20]?.ltbtn?.addView(it)
|
||||
it.layoutParams.height = cardHeight
|
||||
it.layoutParams.width = cardWidth
|
||||
}
|
||||
}
|
||||
interface InitClickListeners{
|
||||
fun prepareListeners(v: View, name: String, path: String?, chapterUUID: String?, pn: Int?)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package top.fumiama.copymanga.template
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.JsonReader
|
||||
import android.view.View
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.navigation.Navigation
|
||||
import com.google.gson.Gson
|
||||
import top.fumiama.dmzj.copymanga.R
|
||||
import top.fumiama.copymanga.json.BookListStructure
|
||||
import top.fumiama.copymanga.tools.DownloadTools
|
||||
import java.io.File
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
open class InfoCardLoader(inflateRes:Int, private val navId:Int): MangaPagesFragmentTemplate(inflateRes) {
|
||||
private val subUrl get() = getApiUrl()
|
||||
|
||||
init {
|
||||
pageHandler = object : PageHandler {
|
||||
override fun addPage(){
|
||||
AutoDownloadThread(subUrl){
|
||||
if(isRefresh){
|
||||
page = 0
|
||||
isRefresh = false
|
||||
}
|
||||
val bookList = Gson().fromJson(it?.decodeToString(), BookListStructure::class.java)
|
||||
bookList?.let {
|
||||
if(it.code == 200) it.results.list?.forEach{ book ->
|
||||
cardList.addCard(book.name, null, book.cover, book.path_word, null, null, false)
|
||||
}
|
||||
}
|
||||
page++
|
||||
onLoadFinish()
|
||||
}.start()
|
||||
}
|
||||
override fun initCardList(weakReference: WeakReference<Fragment>) {
|
||||
cardList = CardList(weakReference, cardWidth, cardHeight, cardPerRow)
|
||||
cardList.initClickListeners = object : CardList.InitClickListeners {
|
||||
override fun prepareListeners(v: View, name: String, path: String?, chapterUUID: String?, pn: Int?) {
|
||||
v.setOnClickListener {
|
||||
val bundle = Bundle()
|
||||
bundle.putString("path", path)
|
||||
rootView?.let { Navigation.findNavController(it).navigate(navId, bundle) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
override fun setListeners() { this@InfoCardLoader.setListeners() }
|
||||
}
|
||||
}
|
||||
|
||||
open fun getApiUrl(): String{
|
||||
return ""
|
||||
}
|
||||
|
||||
open fun setListeners(){}
|
||||
|
||||
open fun onLoadFinish(){}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package top.fumiama.copymanga.template
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
import android.util.JsonReader
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import androidx.fragment.app.Fragment
|
||||
import kotlinx.android.synthetic.main.line_header.view.*
|
||||
import kotlinx.android.synthetic.main.line_lazybooklines.*
|
||||
import top.fumiama.copymanga.template.handler.MPATHandler
|
||||
import top.fumiama.copymanga.tools.UITools
|
||||
import java.lang.Thread.sleep
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
open class MangaPagesFragmentTemplate(inflateRes:Int, val isLazy: Boolean = true, val forceLoad: Boolean = false) : NoBackRefreshFragment(inflateRes) {
|
||||
var cardPerRow = 3
|
||||
var cardWidth = 0
|
||||
var cardHeight = 0
|
||||
lateinit var cardList: CardList
|
||||
var mh: MPATHandler? = null
|
||||
var row: View? = null
|
||||
var isEnd = false
|
||||
var jsonReaderNow: JsonReader? = null
|
||||
var page = 0
|
||||
|
||||
var isRefresh = false
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
@ExperimentalStdlibApi
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
if(isFirstInflate) {
|
||||
mh = MPATHandler(WeakReference(this))
|
||||
Thread {
|
||||
sleep(600)
|
||||
mh?.sendEmptyMessage(0)
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
|
||||
fun setLayouts() {
|
||||
val toolsBox = this.context?.let { UITools(it) }
|
||||
val widthData = toolsBox?.calcWidthFromDp(8, 135)
|
||||
cardPerRow = widthData?.get(0) ?: 3
|
||||
cardWidth = widthData?.get(2) ?: 128
|
||||
cardHeight = (cardWidth / 0.75 + 0.5).toInt()
|
||||
mysp.footerView.lht.text = "加载"
|
||||
mysp.headerView.lht.text = "刷新"
|
||||
Log.d("MyMPAT", "Card per row: $cardPerRow")
|
||||
Log.d("MyMPAT", "Card width: $cardWidth")
|
||||
|
||||
pageHandler?.initCardList(WeakReference(this))
|
||||
Thread { mh?.sendEmptyMessage(1) }.start()
|
||||
pageHandler?.setListeners()
|
||||
//mypl.visibility = View.GONE
|
||||
}
|
||||
|
||||
var pageHandler: PageHandler? = null
|
||||
|
||||
interface PageHandler {
|
||||
fun addPage()
|
||||
fun initCardList(weakReference: WeakReference<Fragment>)
|
||||
fun setListeners()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package top.fumiama.copymanga.template
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
|
||||
open class NoBackRefreshFragment(private val layoutToLoad: Int):Fragment() {
|
||||
var rootView: View? = null
|
||||
var isFirstInflate = true
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
if(rootView == null){
|
||||
isFirstInflate = true
|
||||
rootView = inflater.inflate(layoutToLoad, container, false)
|
||||
} else isFirstInflate = false
|
||||
return rootView
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package top.fumiama.copymanga.template
|
||||
|
||||
import android.os.Bundle
|
||||
import kotlinx.android.synthetic.main.widget_titlebar.*
|
||||
|
||||
open class TitleActivityTemplate:ActivityTemplate() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ilogo.setOnClickListener {
|
||||
onBackPressed()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package top.fumiama.copymanga.template.handler
|
||||
|
||||
import android.content.Context
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.NetworkCapabilities
|
||||
import android.os.Handler
|
||||
import android.os.Message
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import com.liaoinstan.springview.widget.SpringView
|
||||
import top.fumiama.dmzj.copymanga.R
|
||||
import kotlinx.android.synthetic.main.line_lazybooklines.*
|
||||
import top.fumiama.copymanga.template.MangaPagesFragmentTemplate
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
|
||||
class MPATHandler(private val w: WeakReference<MangaPagesFragmentTemplate>) : Handler() {
|
||||
private val wa get() = w.get()
|
||||
private val netinfo: String
|
||||
get() {
|
||||
val cm: ConnectivityManager =
|
||||
wa?.context?.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
return cm.getNetworkCapabilities(cm.activeNetwork)?.let {
|
||||
when {
|
||||
it.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> return@let wa?.context?.getString(
|
||||
R.string.TRANSPORT_WIFI)
|
||||
it.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> return@let wa?.context?.getString(
|
||||
R.string.TRANSPORT_CELLULAR)
|
||||
it.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) -> return@let wa?.context?.getString(
|
||||
R.string.TRANSPORT_BLUETOOTH)
|
||||
it.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> return@let wa?.context?.getString(
|
||||
R.string.TRANSPORT_ETHERNET)
|
||||
it.hasTransport(NetworkCapabilities.TRANSPORT_LOWPAN) -> return@let wa?.context?.getString(
|
||||
R.string.TRANSPORT_LOWPAN)
|
||||
it.hasTransport(NetworkCapabilities.TRANSPORT_VPN) -> return@let "VPN"
|
||||
else -> return@let wa?.context?.getString(R.string.TRANSPORT_NULL)
|
||||
}
|
||||
} ?: "错误"
|
||||
}
|
||||
override fun handleMessage(msg: Message) {
|
||||
super.handleMessage(msg)
|
||||
if (wa?.forceLoad == true || netinfo != "无网络" && netinfo != "错误") {
|
||||
when (msg.what) {
|
||||
0 -> wa?.setLayouts()
|
||||
1 -> managePage()
|
||||
2 -> addPageHandler()
|
||||
3 -> {
|
||||
wa?.pageHandler?.addPage()
|
||||
//wa?.myp?.visibility = View.GONE
|
||||
wa?.mysp?.onFinishFreshAndLoad()
|
||||
//wa?.mys?.fullScroll(ScrollView.FOCUS_UP)
|
||||
}
|
||||
4 ->{
|
||||
wa?.mydll?.removeAllViews()
|
||||
wa?.isEnd = false
|
||||
wa?.jsonReaderNow = null
|
||||
wa?.page = 0
|
||||
wa?.cardList?.reset()
|
||||
addPageHandler()
|
||||
wa?.mysp?.onFinishFreshAndLoad()
|
||||
wa?.mypl?.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
} else Toast.makeText(wa?.context, "${netinfo}链接!", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
private fun managePage() {
|
||||
addPageHandler()
|
||||
if (wa?.isLazy == true) wa?.mysp?.setListener(object :SpringView.OnFreshListener{
|
||||
override fun onLoadmore() {
|
||||
Thread { this@MPATHandler.sendEmptyMessage(2) }.start()
|
||||
}
|
||||
override fun onRefresh() {
|
||||
Thread { this@MPATHandler.sendEmptyMessage(4) }.start()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun addPageHandler() {
|
||||
//wa?.myp?.visibility = View.VISIBLE
|
||||
Thread { this.sendEmptyMessage(3) }.start()
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package top.fumiama.copymanga.tool
|
||||
|
||||
import android.util.Log
|
||||
import java.net.HttpURLConnection
|
||||
import java.net.URL
|
||||
import java.util.concurrent.Callable
|
||||
import java.util.concurrent.FutureTask
|
||||
|
||||
class DownloadTools {
|
||||
fun getHttpContent(Url: String, refer: String? = null, ua: String? = null): ByteArray? {
|
||||
Log.d("Mydl", "getHttp: $Url")
|
||||
var ret: ByteArray? = null
|
||||
val task = FutureTask(Callable {
|
||||
try {
|
||||
val connection = URL(Url).openConnection() as HttpURLConnection
|
||||
connection.requestMethod = "GET"
|
||||
connection.connectTimeout = 10000
|
||||
connection.readTimeout = 10000
|
||||
refer?.let { connection.setRequestProperty("referer", it) }
|
||||
ua?.let { connection.setRequestProperty("User-agent", it) }
|
||||
|
||||
ret = connection.inputStream.readBytes()
|
||||
connection.disconnect()
|
||||
} catch (ex: Exception) {
|
||||
ex.printStackTrace()
|
||||
}
|
||||
return@Callable ret
|
||||
})
|
||||
Thread(task).start()
|
||||
return try {
|
||||
task.get()
|
||||
} catch (ex: Exception) {
|
||||
ex.printStackTrace()
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
package top.fumiama.copymanga.tool
|
||||
|
||||
import top.fumiama.copymanga.R
|
||||
import top.fumiama.copymanga.activity.DlActivity
|
||||
import top.fumiama.copymanga.data.ComicStructure
|
||||
import top.fumiama.copymanga.view.JSWebView
|
||||
import top.fumiama.copymanga.web.JSHidden
|
||||
import java.io.File
|
||||
import java.lang.Thread.sleep
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.zip.CRC32
|
||||
import java.util.zip.CheckedOutputStream
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipOutputStream
|
||||
|
||||
class MangaDlTools(activity: DlActivity) {
|
||||
var exit = false
|
||||
private val da = WeakReference(activity)
|
||||
private val d = da.get()
|
||||
private val p = PropertiesTools(File("${d?.filesDir}/chapters.hash"))
|
||||
private var imgUrlsList: Array<Array<String>?>? = null
|
||||
private var chaptersCount = 0
|
||||
private val newWebViewHidden: JSWebView?
|
||||
get() {
|
||||
val re = d?.let { JSWebView(it, it.getString(R.string.pc_ua)) }
|
||||
re?.setWebViewClient("h.js")
|
||||
re?.loadJSInterface(JSHidden())
|
||||
return re
|
||||
}
|
||||
|
||||
init {
|
||||
wmdlt = WeakReference(this)
|
||||
}
|
||||
|
||||
fun getImgsCountByHash(hash: String): Int?{
|
||||
return imgUrlsList?.get(p[hash].toInt())?.size
|
||||
}
|
||||
|
||||
fun allocateChapterUrls(count: Int){
|
||||
imgUrlsList = arrayOfNulls(count)
|
||||
chaptersCount = 0
|
||||
}
|
||||
|
||||
fun dlChapterUrl(url: String){
|
||||
p[url.substringAfterLast("/")] = (chaptersCount++).toString()
|
||||
newWebViewHidden?.loadUrl(url)
|
||||
}
|
||||
|
||||
fun setChapterImgs(hash: String, imgUrls: Array<String>){
|
||||
imgUrlsList?.set(p[hash].toInt(), imgUrls)
|
||||
}
|
||||
|
||||
fun dlChapterAndPackIntoZip(zipf: File, hash: String){
|
||||
imgUrlsList?.get(p[hash].toInt())?.let {
|
||||
val dl = DownloadTools()
|
||||
zipf.parentFile?.let { if (!it.exists()) it.mkdirs() }
|
||||
if (zipf.exists()) zipf.delete()
|
||||
zipf.createNewFile()
|
||||
val zip = ZipOutputStream(CheckedOutputStream(zipf.outputStream(), CRC32()))
|
||||
zip.setLevel(9)
|
||||
var succeed = true
|
||||
for (i in it.indices) {
|
||||
zip.putNextEntry(ZipEntry("$i.webp"))
|
||||
var tryTimes = 3
|
||||
var s = false
|
||||
while (!s && tryTimes-- > 0){
|
||||
s = dl.getHttpContent(it[i], d?.getString(R.string.web_home_www), d?.getString(R.string.pc_ua))?.let { zip.write(it); true } ?: false
|
||||
if (!s) {
|
||||
onDownloadedListener?.handleMessage(i + 1)
|
||||
sleep(2000)
|
||||
}
|
||||
}
|
||||
if(!s && tryTimes <= 0) succeed = false
|
||||
onDownloadedListener?.handleMessage(s, i + 1)
|
||||
zip.flush()
|
||||
if (exit) break
|
||||
}
|
||||
zip.close()
|
||||
onDownloadedListener?.handleMessage(succeed)
|
||||
}
|
||||
}
|
||||
|
||||
var onDownloadedListener: OnDownloadedListener? = null
|
||||
|
||||
interface OnDownloadedListener {
|
||||
fun handleMessage(succeed: Boolean)
|
||||
fun handleMessage(succeed: Boolean, pageNow: Int)
|
||||
fun handleMessage(pageNow: Int)
|
||||
}
|
||||
|
||||
companion object {
|
||||
var wmdlt: WeakReference<MangaDlTools>? = null
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
package top.fumiama.copymanga.tool
|
||||
|
||||
import android.content.Intent
|
||||
import android.widget.Toast
|
||||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
import top.fumiama.copymanga.activity.MainActivity.Companion.wm
|
||||
import top.fumiama.copymanga.activity.ViewMangaActivity
|
||||
import java.io.File
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
class PagesManager(w: WeakReference<ViewMangaActivity>) {
|
||||
val v = w.get()
|
||||
private var isEndL = false
|
||||
private var isEndR = false
|
||||
@ExperimentalStdlibApi
|
||||
fun toPreviousPage(){ toPage(v?.r2l==true) }
|
||||
@ExperimentalStdlibApi
|
||||
fun toNextPage(){ toPage(v?.r2l!=true) }
|
||||
private fun judgePrevious() = v?.pageNum?:0 > 1
|
||||
private fun judgeNext() = v?.pageNum?:0 < v?.count?:0
|
||||
@ExperimentalStdlibApi
|
||||
private fun toPage(goNext:Boolean){
|
||||
if (v?.clicked == false) {
|
||||
if (if(goNext)judgeNext() else judgePrevious()) {
|
||||
if(goNext) {
|
||||
v.scrollForward()
|
||||
isEndR = false
|
||||
} else {
|
||||
v.scrollBack()
|
||||
isEndL = false
|
||||
}
|
||||
} else {
|
||||
val chapterUrl = if(goNext) ViewMangaActivity.nextChapterUrl else ViewMangaActivity.previousChapterUrl
|
||||
if (chapterUrl != null) {
|
||||
if (if(goNext)isEndR else isEndL) {
|
||||
if(!goNext) ViewMangaActivity.pn = -2
|
||||
wm?.get()?.w?.loadUrl("javascript:invoke.clickClass(\"comicControlBottomTopClick\",${if(goNext)1 else 0});")
|
||||
v.tt.canDo = false
|
||||
v.finish()
|
||||
} else doubleTapToast(goNext)
|
||||
} else {
|
||||
val newZipPosition = ViewMangaActivity.zipPosition + (if(goNext) 1 else -1)
|
||||
if(v.dlZip2View && newZipPosition >= 0 && newZipPosition < ViewMangaActivity.zipList?.size?:0){
|
||||
if (if(goNext)isEndR else isEndL){
|
||||
if(!goNext) ViewMangaActivity.pn = -2
|
||||
ViewMangaActivity.zipPosition = newZipPosition
|
||||
ViewMangaActivity.titleText = ViewMangaActivity.zipList?.get(newZipPosition) ?: "null"
|
||||
ViewMangaActivity.zipFile = File(ViewMangaActivity.cd, ViewMangaActivity.titleText)
|
||||
v.startActivity(Intent(v, ViewMangaActivity::class.java))
|
||||
v.tt.canDo = false
|
||||
v.finish()
|
||||
}else doubleTapToast(goNext)
|
||||
}
|
||||
else Toast.makeText(
|
||||
v.applicationContext,
|
||||
"已经到头了~",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}
|
||||
} else v?.hideObjs()
|
||||
}
|
||||
fun manageInfo(){
|
||||
if (v?.clicked == false) v.showObjs() else v?.hideObjs()
|
||||
}
|
||||
private fun doubleTapToast(goNext: Boolean){
|
||||
val hint = if(goNext) "下" else "上"
|
||||
Toast.makeText(
|
||||
v?.applicationContext,
|
||||
"再次按下加载${hint}一章",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
if(goNext) isEndR = true
|
||||
else isEndL = true
|
||||
}
|
||||
}
|
||||
18
app/src/main/java/top/fumiama/copymanga/tools/CMApi.kt
Normal file
18
app/src/main/java/top/fumiama/copymanga/tools/CMApi.kt
Normal file
@@ -0,0 +1,18 @@
|
||||
package top.fumiama.copymanga.tools
|
||||
|
||||
import com.bumptech.glide.load.model.LazyHeaders
|
||||
import top.fumiama.dmzj.copymanga.R
|
||||
import top.fumiama.copymanga.MainActivity
|
||||
import top.fumiama.copymanga.json.Chapter2Return
|
||||
import java.io.File
|
||||
|
||||
object CMApi {
|
||||
var myGlideHeaders: LazyHeaders? = null
|
||||
get() {
|
||||
if(field === null) field = LazyHeaders.Builder().addHeader("referer", MainActivity.mainWeakReference?.get()?.getString(R.string.referUrl)!!).addHeader("User-Agent", MainActivity.mainWeakReference?.get()?.getString(R.string.pc_ua)!!).build()
|
||||
return field
|
||||
}
|
||||
fun getImgZipFileFromVM(exDir: File?, chapter2Return: Chapter2Return?) = File(exDir, "${chapter2Return?.results?.comic?.name}/${chapter2Return?.results?.chapter?.group_path_word}/${chapter2Return?.results?.chapter?.name}.zip")
|
||||
fun getZipFile(exDir: File?, manga: String, caption: CharSequence, name: CharSequence) = File(exDir, "$manga/$caption/$name.zip")
|
||||
fun getApiUrl(id: Int, arg1: String?, arg2: String?) = MainActivity.mainWeakReference?.get()?.getString(id)?.let { String.format(it, arg1, arg2) }
|
||||
}
|
||||
119
app/src/main/java/top/fumiama/copymanga/tools/DownloadTools.kt
Normal file
119
app/src/main/java/top/fumiama/copymanga/tools/DownloadTools.kt
Normal file
@@ -0,0 +1,119 @@
|
||||
package top.fumiama.copymanga.tools
|
||||
|
||||
import android.util.Log
|
||||
import java.io.File
|
||||
import java.net.HttpURLConnection
|
||||
import java.net.URL
|
||||
import java.util.concurrent.Callable
|
||||
import java.util.concurrent.FutureTask
|
||||
|
||||
object DownloadTools {
|
||||
fun getHttpContent(Url: String, refer: String? = null, ua: String? = null): ByteArray? {
|
||||
Log.d("Mydl", "getHttp: $Url")
|
||||
var ret: ByteArray? = null
|
||||
val task = FutureTask(Callable {
|
||||
try {
|
||||
val connection = URL(Url).openConnection() as HttpURLConnection
|
||||
connection.requestMethod = "GET"
|
||||
connection.connectTimeout = 10000
|
||||
connection.readTimeout = 10000
|
||||
refer?.let { connection.setRequestProperty("referer", it) }
|
||||
ua?.let { connection.setRequestProperty("User-agent", it) }
|
||||
|
||||
ret = connection.inputStream.readBytes()
|
||||
connection.disconnect()
|
||||
} catch (ex: Exception) {
|
||||
ex.printStackTrace()
|
||||
}
|
||||
return@Callable ret
|
||||
})
|
||||
Thread(task).start()
|
||||
return try {
|
||||
task.get()
|
||||
} catch (ex: Exception) {
|
||||
ex.printStackTrace()
|
||||
null
|
||||
}
|
||||
}
|
||||
fun downloadUsingUrlRet(Url: String?, f: File): Boolean {
|
||||
Log.d("Mydl", "Ret Get Url: $Url, File: $f")
|
||||
val task = FutureTask(Callable {
|
||||
try {
|
||||
val connection = URL(Url).openConnection() as HttpURLConnection
|
||||
connection.requestMethod = "GET"
|
||||
connection.connectTimeout = 10000
|
||||
connection.readTimeout = 10000
|
||||
|
||||
if (f.exists()) f.delete()
|
||||
else f.parentFile?.mkdirs()
|
||||
f.parentFile?.let {
|
||||
if (!it.canRead()) it.setReadable(true)
|
||||
if (!it.canWrite()) it.setWritable(true)
|
||||
}
|
||||
connection.inputStream.buffered().copyTo(f.outputStream())
|
||||
connection.disconnect()
|
||||
return@Callable true
|
||||
} catch (ex: Exception) {
|
||||
ex.printStackTrace()
|
||||
return@Callable false
|
||||
}
|
||||
})
|
||||
Thread(task).start()
|
||||
return try {
|
||||
task.get()
|
||||
} catch (ex: Exception) {
|
||||
ex.printStackTrace()
|
||||
false
|
||||
}
|
||||
}
|
||||
fun downloadUsingUrl(Url: String?, f: File, refer: String? = null) {
|
||||
Log.d("Mydl", "Get Url: $Url, File: $f")
|
||||
Thread(Runnable {
|
||||
try {
|
||||
val connection = URL(Url).openConnection() as HttpURLConnection
|
||||
connection.requestMethod = "GET"
|
||||
connection.connectTimeout = 10000
|
||||
connection.readTimeout = 10000
|
||||
refer?.let { connection.setRequestProperty("referer", it) }
|
||||
|
||||
if (f.exists()) f.delete()
|
||||
else f.parentFile?.mkdirs()
|
||||
f.parentFile?.let {
|
||||
if (!it.canRead()) it.setReadable(true)
|
||||
if (!it.canWrite()) it.setWritable(true)
|
||||
}
|
||||
connection.inputStream.buffered().copyTo(f.outputStream())
|
||||
connection.disconnect()
|
||||
} catch (ex: Exception) {
|
||||
ex.printStackTrace()
|
||||
}
|
||||
}).start()
|
||||
}
|
||||
|
||||
fun getHttpContent(Url: String, refer: String? = null): ByteArray? {
|
||||
Log.d("Mydl", "getHttp: $Url")
|
||||
var ret: ByteArray? = null
|
||||
val task = FutureTask(Callable {
|
||||
try {
|
||||
val connection = URL(Url).openConnection() as HttpURLConnection
|
||||
connection.requestMethod = "GET"
|
||||
connection.connectTimeout = 10000
|
||||
connection.readTimeout = 10000
|
||||
refer?.let { connection.setRequestProperty("referer", it) }
|
||||
|
||||
ret = connection.inputStream.readBytes()
|
||||
connection.disconnect()
|
||||
} catch (ex: Exception) {
|
||||
ex.printStackTrace()
|
||||
}
|
||||
return@Callable ret
|
||||
})
|
||||
Thread(task).start()
|
||||
return try {
|
||||
task.get()
|
||||
} catch (ex: Exception) {
|
||||
ex.printStackTrace()
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package top.fumiama.copymanga.tools
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.renderscript.Allocation
|
||||
import android.renderscript.Element
|
||||
import android.renderscript.RenderScript
|
||||
import android.renderscript.ScriptIntrinsicBlur
|
||||
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool
|
||||
import com.bumptech.glide.load.resource.bitmap.CenterCrop
|
||||
|
||||
class GlideBlurTransformation(private val context: Context) : CenterCrop() {
|
||||
override fun transform(
|
||||
pool: BitmapPool,
|
||||
toTransform: Bitmap,
|
||||
outWidth: Int,
|
||||
outHeight: Int
|
||||
): Bitmap {
|
||||
val bitmap = super.transform(pool, toTransform, outWidth, outHeight)
|
||||
return blurBitmap(context, bitmap, 25f, outWidth / 2, outHeight / 2)
|
||||
}
|
||||
|
||||
private fun blurBitmap(
|
||||
context: Context?,
|
||||
image: Bitmap?,
|
||||
blurRadius: Float,
|
||||
outWidth: Int,
|
||||
outHeight: Int
|
||||
): Bitmap {
|
||||
// 将缩小后的图片做为预渲染的图片
|
||||
val inputBitmap = Bitmap.createScaledBitmap(image!!, outWidth, outHeight, false)
|
||||
// 创建一张渲染后的输出图片
|
||||
val outputBitmap = Bitmap.createBitmap(inputBitmap)
|
||||
// 创建RenderScript内核对象
|
||||
val rs = RenderScript.create(context)
|
||||
// 创建一个模糊效果的RenderScript的工具对象
|
||||
val blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs))
|
||||
// 由于RenderScript并没有使用VM来分配内存,所以需要使用Allocation类来创建和分配内存空间
|
||||
// 创建Allocation对象的时候其实内存是空的,需要使用copyTo()将数据填充进去
|
||||
val tmpIn = Allocation.createFromBitmap(rs, inputBitmap)
|
||||
val tmpOut = Allocation.createFromBitmap(rs, outputBitmap)
|
||||
// 设置渲染的模糊程度, 25f是最大模糊度
|
||||
blurScript.setRadius(blurRadius)
|
||||
// 设置blurScript对象的输入内存
|
||||
blurScript.setInput(tmpIn)
|
||||
// 将输出数据保存到输出内存中
|
||||
blurScript.forEach(tmpOut)
|
||||
// 将数据填充到Allocation中
|
||||
tmpOut.copyTo(outputBitmap)
|
||||
return outputBitmap
|
||||
}
|
||||
}
|
||||
106
app/src/main/java/top/fumiama/copymanga/tools/MangaDlTools.kt
Normal file
106
app/src/main/java/top/fumiama/copymanga/tools/MangaDlTools.kt
Normal file
@@ -0,0 +1,106 @@
|
||||
package top.fumiama.copymanga.tools
|
||||
|
||||
import android.util.Log
|
||||
import com.google.gson.Gson
|
||||
import top.fumiama.dmzj.copymanga.R
|
||||
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
|
||||
import top.fumiama.copymanga.json.Chapter2Return
|
||||
import top.fumiama.copymanga.template.AutoDownloadThread
|
||||
import top.fumiama.copymanga.tools.DownloadTools.getHttpContent
|
||||
import java.io.File
|
||||
import java.lang.Thread.sleep
|
||||
import java.util.zip.CRC32
|
||||
import java.util.zip.CheckedOutputStream
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipOutputStream
|
||||
|
||||
class MangaDlTools {
|
||||
var exit = false
|
||||
private var comicFileRelative: String? = null
|
||||
var size = 0
|
||||
var complete = false
|
||||
|
||||
fun downloadChapterInVol(url: CharSequence, chapterName: CharSequence, group: CharSequence, index: Int){
|
||||
comicFileRelative = "$group/$chapterName.zip"
|
||||
complete = false
|
||||
getChapterInfo(url, index)
|
||||
while (!complete) sleep(1000)
|
||||
}
|
||||
|
||||
private fun getChapterInfo(chapter2Return: Chapter2Return, index: Int) {
|
||||
if(index >= 0){
|
||||
comicFileRelative?.let {
|
||||
dlChapterAndPackIntoZip(
|
||||
File(
|
||||
mainWeakReference?.get()?.getExternalFilesDir(""),
|
||||
"${chapter2Return.results.comic.name}/$it"
|
||||
),
|
||||
getMangaUrls(chapter2Return)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMangaUrls(chapter2Return: Chapter2Return): Array<String>{
|
||||
var re: Array<String> = arrayOf()
|
||||
val hm: HashMap<Int, String> = hashMapOf()
|
||||
val chapter = chapter2Return.results.chapter
|
||||
for(i in 0 until chapter.size) {
|
||||
hm[chapter.words[i]] = chapter.contents[i].url
|
||||
}
|
||||
for(i in 0 until chapter.size){
|
||||
re += hm[i]?:""
|
||||
}
|
||||
size = re.size
|
||||
return re
|
||||
}
|
||||
|
||||
private fun getChapterInfo(url: CharSequence, index: Int){
|
||||
Log.d("MyMDT", "下载:$url, index:$index")
|
||||
AutoDownloadThread(url.toString()){
|
||||
Gson().fromJson(it?.decodeToString(), Chapter2Return::class.java)?.let {
|
||||
getChapterInfo(it, index)
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
|
||||
private fun dlChapterAndPackIntoZip(zipf: File, urls: Array<String>) {
|
||||
zipf.parentFile?.let { if (!it.exists()) it.mkdirs() }
|
||||
if (zipf.exists()) zipf.delete()
|
||||
zipf.createNewFile()
|
||||
val zip = ZipOutputStream(CheckedOutputStream(zipf.outputStream(), CRC32()))
|
||||
zip.setLevel(9)
|
||||
var succeed = true
|
||||
for (i in urls.indices) {
|
||||
zip.putNextEntry(ZipEntry("$i.webp"))
|
||||
var tryTimes = 3
|
||||
var s = false
|
||||
while (!s && tryTimes-- > 0) {
|
||||
s = getHttpContent(
|
||||
urls[i],
|
||||
mainWeakReference?.get()?.getString(R.string.referUrl),
|
||||
mainWeakReference?.get()?.getString(R.string.pc_ua)
|
||||
)?.let { zip.write(it); true } ?: false
|
||||
if (!s) {
|
||||
onDownloadedListener?.handleMessage(i + 1)
|
||||
sleep(2000)
|
||||
}
|
||||
}
|
||||
if (!s && tryTimes <= 0) succeed = false
|
||||
onDownloadedListener?.handleMessage(s, i + 1)
|
||||
zip.flush()
|
||||
if (exit) break
|
||||
}
|
||||
zip.close()
|
||||
onDownloadedListener?.handleMessage(succeed)
|
||||
complete = true
|
||||
}
|
||||
|
||||
var onDownloadedListener: OnDownloadedListener? = null
|
||||
|
||||
interface OnDownloadedListener {
|
||||
fun handleMessage(succeed: Boolean)
|
||||
fun handleMessage(succeed: Boolean, pageNow: Int)
|
||||
fun handleMessage(pageNow: Int)
|
||||
}
|
||||
}
|
||||
@@ -1,32 +1,31 @@
|
||||
package top.fumiama.copymanga.tool
|
||||
package top.fumiama.copymanga.tools
|
||||
//PropertiesTools.kt
|
||||
//created by fumiama 20200724
|
||||
import android.util.Log
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import java.util.*
|
||||
|
||||
class PropertiesTools(private val f: File):Properties() {
|
||||
private val propfile:File
|
||||
get() {
|
||||
if(!f.exists()) {
|
||||
if(f.parentFile?.exists() != true) f.parentFile?.mkdirs()
|
||||
get() {
|
||||
if(!f.exists()) {
|
||||
if(f.parentFile?.exists() != true) f.parentFile?.mkdirs()
|
||||
if(f.parentFile?.canWrite() != true) f.parentFile?.setWritable(true)
|
||||
createNew(f)
|
||||
}else if(f.isDirectory) {
|
||||
if(f.parentFile?.canWrite() != true) f.parentFile?.setWritable(true)
|
||||
f.delete()
|
||||
createNew(f)
|
||||
}
|
||||
if(f.parentFile?.canWrite() != true) f.parentFile?.setWritable(true)
|
||||
createNew(f)
|
||||
}else if(f.isDirectory) {
|
||||
if(f.parentFile?.canWrite() != true) f.parentFile?.setWritable(true)
|
||||
f.delete()
|
||||
createNew(f)
|
||||
if(f.parentFile?.canRead() != true) f.parentFile?.setReadable(true)
|
||||
return f
|
||||
}
|
||||
if(f.parentFile?.canWrite() != true) f.parentFile?.setWritable(true)
|
||||
if(f.parentFile?.canRead() != true) f.parentFile?.setReadable(true)
|
||||
return f
|
||||
}
|
||||
private fun createNew(f: File){
|
||||
f.createNewFile()
|
||||
val o = f.outputStream()
|
||||
this.storeToXML(o, "store")
|
||||
Log.d("MyPT", "Generate new prop.")
|
||||
//Log.d("MyPT", "Generate new prop.")
|
||||
o.close()
|
||||
}
|
||||
private fun loadFromXml(`in`: InputStream?): PropertiesTools {
|
||||
@@ -40,14 +39,14 @@ class PropertiesTools(private val f: File):Properties() {
|
||||
operator fun get(key: String): String{
|
||||
val i = propfile.inputStream()
|
||||
val re = this.loadFromXml(i).getProperty(key)?:"null"
|
||||
Log.d("MyPT", "Get $key = $re")
|
||||
//Log.d("MyPT", "Get prop: $re")
|
||||
i.close()
|
||||
return re
|
||||
}
|
||||
operator fun set(key: String, value: String){
|
||||
val o = propfile.outputStream()
|
||||
this.setProp(key, value).storeToXML(o, "store")
|
||||
Log.d("MyPT", "Set $key = $value")
|
||||
//Log.d("MyPT", "Set $key = $value")
|
||||
o.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package top.fumiama.copymanga.handler
|
||||
package top.fumiama.copymanga.tools
|
||||
|
||||
import android.os.Handler
|
||||
|
||||
@@ -1,34 +1,19 @@
|
||||
package top.fumiama.copymanga.tool
|
||||
package top.fumiama.copymanga.tools
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.AlertDialog
|
||||
import android.content.Context
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.NetworkCapabilities
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import top.fumiama.copymanga.R
|
||||
import top.fumiama.dmzj.copymanga.R
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.*
|
||||
import java.util.regex.Pattern
|
||||
import kotlin.math.sqrt
|
||||
|
||||
class ToolsBox(w: WeakReference<Any>) {
|
||||
val zis = (w as WeakReference<Activity>).get()
|
||||
val week: String
|
||||
get() {
|
||||
val cal = Calendar.getInstance()
|
||||
return when (cal[Calendar.DAY_OF_WEEK]) {
|
||||
1 -> "周日"
|
||||
2 -> "周一"
|
||||
3 -> "周二"
|
||||
4 -> "周三"
|
||||
5 -> "周四"
|
||||
6 -> "周五"
|
||||
7 -> "周六"
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
class UITools(that: Context?, w: WeakReference<Activity>? = null) {
|
||||
private val zis = that
|
||||
private val weak = w
|
||||
constructor(w: WeakReference<Activity>): this(w.get()?.applicationContext, w)
|
||||
val netinfo: String
|
||||
get() {
|
||||
val cm: ConnectivityManager =
|
||||
@@ -37,6 +22,7 @@ class ToolsBox(w: WeakReference<Any>) {
|
||||
when {
|
||||
it.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> return@let "WIFI"
|
||||
it.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> return@let "移动数据"
|
||||
it.hasTransport(NetworkCapabilities.TRANSPORT_WIFI_AWARE) -> return@let "WIFI_AWARE"
|
||||
it.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) -> return@let "蓝牙"
|
||||
it.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> return@let "以太网"
|
||||
it.hasTransport(NetworkCapabilities.TRANSPORT_LOWPAN) -> return@let "LOWPAN"
|
||||
@@ -45,8 +31,8 @@ class ToolsBox(w: WeakReference<Any>) {
|
||||
} ?: "错误"
|
||||
}
|
||||
fun toastError(s: String, willFinish: Boolean = true) {
|
||||
Toast.makeText(zis?.applicationContext, s, Toast.LENGTH_SHORT).show()
|
||||
if (willFinish) zis?.finish()
|
||||
Toast.makeText(zis, s, Toast.LENGTH_SHORT).show()
|
||||
if (willFinish) weak?.get()?.finish()
|
||||
}
|
||||
fun buildInfo(
|
||||
title: String,
|
||||
@@ -70,9 +56,18 @@ class ToolsBox(w: WeakReference<Any>) {
|
||||
fun dp2px(dp:Int):Int?{
|
||||
return zis?.resources?.displayMetrics?.density?.let { (dp * it + 0.5).toInt()}
|
||||
}
|
||||
private fun px2dp(px:Int):Int?{
|
||||
fun px2dp(px:Int):Int?{
|
||||
return zis?.resources?.displayMetrics?.density?.let { (px.toDouble() / it + 0.5).toInt()}
|
||||
}
|
||||
fun calcWidthFromDp(marginLeftDp:Int, widthDp:Int):List<Int>{
|
||||
val margin = marginLeftDp.toDouble()
|
||||
val marginPx = dp2px(marginLeftDp)?:16
|
||||
val screenWidth = zis?.resources?.displayMetrics?.widthPixels?:1080
|
||||
val numPerRow = ((px2dp(screenWidth)?:400).toDouble() / (widthDp + 2 * margin) + 0.5).toInt()
|
||||
val w = (screenWidth - marginPx*numPerRow*2)/numPerRow
|
||||
val totalWidth = screenWidth/numPerRow
|
||||
return listOf(numPerRow, w, totalWidth)
|
||||
}
|
||||
private fun root(a:Double, b:Double, c:Double):List<Double>?{
|
||||
val d = b*b - 4.0 * a * c
|
||||
if(d < 0) return null
|
||||
@@ -81,7 +76,7 @@ class ToolsBox(w: WeakReference<Any>) {
|
||||
val x2 = (-b - sd)/(2.0 * a)
|
||||
return listOf(x1, x2)
|
||||
}
|
||||
fun calcWidthFromDp(marginLeftDp:Int, widthDp:Int):List<Int>{
|
||||
fun calcWidthFromDpRoot(marginLeftDp:Int, widthDp:Int):List<Int>{
|
||||
val margin = marginLeftDp.toDouble()
|
||||
val marginPx = dp2px(marginLeftDp)?:16
|
||||
val root = root(margin, widthDp.toDouble(), -((px2dp(zis?.resources?.displayMetrics?.widthPixels?:1080))?:400).toDouble())
|
||||
@@ -90,4 +85,4 @@ class ToolsBox(w: WeakReference<Any>) {
|
||||
val totalWidth = ((zis?.resources?.displayMetrics?.widthPixels?:1080)-marginPx)/numPerRow
|
||||
return listOf(numPerRow, w, totalWidth)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package top.fumiama.copymanga.ui.book
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.Menu
|
||||
import android.view.View
|
||||
import androidx.navigation.Navigation
|
||||
import top.fumiama.dmzj.copymanga.R
|
||||
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
|
||||
import top.fumiama.copymanga.template.NoBackRefreshFragment
|
||||
import java.lang.Thread.sleep
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
class BookFragment:NoBackRefreshFragment(R.layout.fragment_book) {
|
||||
private lateinit var bookHandler: BookHandler
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
if(isFirstInflate) {
|
||||
bookHandler = BookHandler(WeakReference(this), arguments?.getString("path")?:"null")
|
||||
Thread{
|
||||
sleep(600)
|
||||
bookHandler.startLoad()
|
||||
}.start()
|
||||
}
|
||||
else bookHandler.fbibinfo?.layoutParams?.height = (bookHandler.fbibinfo?.width?:0 * 4.0 / 9.0 + 0.5).toInt()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
mainWeakReference?.get()?.menuMain?.let { setMenuVisible(it) }
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
mainWeakReference?.get()?.menuMain?.let { setMenuInvisible(it) }
|
||||
}
|
||||
|
||||
private fun setMenuInvisible(menu: Menu){
|
||||
menu.findItem(R.id.action_download)?.isVisible = false
|
||||
}
|
||||
|
||||
private fun setMenuVisible(menu: Menu) {
|
||||
Log.d("MyBF", "显示下载按钮")
|
||||
val dl = menu.findItem(R.id.action_download)
|
||||
dl?.isVisible = true
|
||||
dl?.setIcon(R.drawable.ic_menu_download)
|
||||
dl?.setOnMenuItemClickListener {
|
||||
if(bookHandler.complete && it.itemId == R.id.action_download){
|
||||
navigate2dl()
|
||||
true
|
||||
}
|
||||
else it.itemId == R.id.action_download
|
||||
}
|
||||
}
|
||||
|
||||
private fun navigate2dl(){
|
||||
val bundle = Bundle()
|
||||
bundle.putString("path", arguments?.getString("path")?:"null")
|
||||
bundle.putString("name", bookHandler.book?.results?.comic?.name)
|
||||
val groups = bookHandler.book?.results?.groups
|
||||
var keys = arrayOf<String>()
|
||||
var gpws = arrayOf<String>()
|
||||
groups?.values?.forEach {
|
||||
keys += it.name
|
||||
gpws += it.path_word
|
||||
}
|
||||
bundle.putStringArray("group", gpws)
|
||||
bundle.putStringArray("groupNames", keys)
|
||||
rootView?.let { Navigation.findNavController(it).navigate(R.id.action_nav_book_to_nav_group, bundle) }
|
||||
}
|
||||
}
|
||||
192
app/src/main/java/top/fumiama/copymanga/ui/book/BookHandler.kt
Normal file
192
app/src/main/java/top/fumiama/copymanga/ui/book/BookHandler.kt
Normal file
@@ -0,0 +1,192 @@
|
||||
package top.fumiama.copymanga.ui.book
|
||||
|
||||
import android.os.Bundle
|
||||
import android.os.Looper
|
||||
import android.os.Message
|
||||
import android.util.Log
|
||||
import android.view.Menu
|
||||
import android.view.View
|
||||
import android.view.ViewTreeObserver
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.navigation.Navigation
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.model.GlideUrl
|
||||
import com.bumptech.glide.load.model.LazyHeaders
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import kotlinx.android.synthetic.main.app_bar_main.*
|
||||
import kotlinx.android.synthetic.main.card_book.*
|
||||
import kotlinx.android.synthetic.main.fragment_book.*
|
||||
import kotlinx.android.synthetic.main.line_2chapters.view.*
|
||||
import kotlinx.android.synthetic.main.line_bookinfo.*
|
||||
import kotlinx.android.synthetic.main.line_bookinfo_text.*
|
||||
import kotlinx.android.synthetic.main.line_chapter.view.*
|
||||
import top.fumiama.dmzj.copymanga.R
|
||||
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
|
||||
import top.fumiama.copymanga.json.BookInfoStructure
|
||||
import top.fumiama.copymanga.json.ReturnBase
|
||||
import top.fumiama.copymanga.json.ThemeStructure
|
||||
import top.fumiama.copymanga.template.AutoDownloadHandler
|
||||
import top.fumiama.copymanga.tools.CMApi
|
||||
import top.fumiama.copymanga.tools.GlideBlurTransformation
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
class BookHandler(that: WeakReference<BookFragment>, path: String)
|
||||
:AutoDownloadHandler(
|
||||
that.get()?.getString(R.string.bookInfoApiUrl)?.let { String.format(it, path) } ?: "",
|
||||
BookInfoStructure::class.java,
|
||||
Looper.myLooper()!!){
|
||||
private val that = that.get()
|
||||
private var hasToastedError = false
|
||||
get(){
|
||||
val re = field
|
||||
field = true
|
||||
return re
|
||||
}
|
||||
var book: BookInfoStructure? = null
|
||||
var fbibinfo:View? = null
|
||||
var complete = false
|
||||
private val divider get() = that?.layoutInflater?.inflate(R.layout.div_h, that.fbl, false)
|
||||
private var fbtinfo: View? = null
|
||||
|
||||
override fun handleMessage(msg: Message) {
|
||||
super.handleMessage(msg)
|
||||
when(msg.what){
|
||||
//0 -> setLayouts()
|
||||
1 -> setCover()
|
||||
2 -> setTexts()
|
||||
3 -> fbibinfo?.let { setInfoHeight(it) }
|
||||
//4 -> setThemes()
|
||||
5 -> setOverScale()
|
||||
6 -> endSetLayouts()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError() {
|
||||
super.onError()
|
||||
if(!hasToastedError) {
|
||||
Toast.makeText(that?.context, R.string.null_book, Toast.LENGTH_SHORT).show()
|
||||
that?.rootView?.let { it1 ->
|
||||
Navigation.findNavController(it1).navigateUp()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun setGsonItem(gsonObj: Any) {
|
||||
super.setGsonItem(gsonObj)
|
||||
book = gsonObj as BookInfoStructure
|
||||
}
|
||||
|
||||
override fun getGsonItem() = book
|
||||
override fun doWhenFinishDownload() {
|
||||
super.doWhenFinishDownload()
|
||||
inflateComponents()
|
||||
Thread{ for (i in 1..6) sendEmptyMessage(i) }.start()
|
||||
}
|
||||
|
||||
private fun endSetLayouts(){
|
||||
that?.fbloading?.visibility = View.GONE
|
||||
complete = true
|
||||
Log.d("MyBH", "Set complete: true")
|
||||
}
|
||||
|
||||
private fun inflateComponents(){
|
||||
fbibinfo = that?.layoutInflater?.inflate(R.layout.line_bookinfo, that.fbl, false)
|
||||
fbtinfo = that?.layoutInflater?.inflate(R.layout.line_text_info, that.fbl, false)
|
||||
}
|
||||
|
||||
private fun setOverScale(){
|
||||
that?.fbov?.setScaleView(that.lbibg)
|
||||
}
|
||||
|
||||
private fun setCover(){
|
||||
that?.let {
|
||||
it.fbl.addView(fbibinfo)
|
||||
val load = Glide.with(it).load(
|
||||
GlideUrl(book?.results?.comic?.cover, CMApi.myGlideHeaders)
|
||||
).timeout(10000)
|
||||
load.into(it.imic)
|
||||
it.context?.let { it1 -> GlideBlurTransformation(it1) }
|
||||
?.let { it2 -> RequestOptions.bitmapTransform(it2) }
|
||||
?.let { it3 -> load.apply(it3).into(it.lbibg) }
|
||||
it.imf.visibility = View.GONE
|
||||
}
|
||||
that?.fbl?.addView(divider)
|
||||
}
|
||||
|
||||
private fun getThemeSeq(authors: Array<ThemeStructure>): CharSequence{
|
||||
var re = ""
|
||||
for(author in authors) re += author.name + ' '
|
||||
return re
|
||||
}
|
||||
|
||||
private fun setTexts(){
|
||||
//that?.tic?.text = book?.name
|
||||
that?.tic?.visibility = View.GONE
|
||||
mainWeakReference?.get()?.toolbar?.title = book?.results?.comic?.name
|
||||
that?.btauth?.text = book?.results?.comic?.author?.let { getThemeSeq(it) }
|
||||
that?.bttag?.text = book?.results?.comic?.theme?.let { getThemeSeq(it) }
|
||||
that?.bthit?.text = that?.getString(R.string.text_format_hit)?.let { String.format(
|
||||
it,
|
||||
book?.results?.comic?.popular
|
||||
) }?:""
|
||||
that?.btsub?.text = that?.getString(R.string.text_format_stat)?.let { String.format(
|
||||
it,
|
||||
book?.results?.comic?.status?.display
|
||||
) }?:""
|
||||
that?.bttime?.text = book?.results?.comic?.datetime_updated
|
||||
(fbtinfo as TextView).text = book?.results?.comic?.brief
|
||||
that?.fbl?.addView(fbtinfo)
|
||||
that?.fbl?.addView(divider)
|
||||
}
|
||||
|
||||
private fun setInfoHeight(v: View){
|
||||
v.viewTreeObserver.addOnGlobalLayoutListener {
|
||||
Log.d("MyMy", "Width: ${v.width}")
|
||||
val newH = (v.width * 4.0 / 9.0 + 0.5).toInt()
|
||||
v.layoutParams.height = newH
|
||||
v.invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setThemes(){
|
||||
book?.results?.groups?.let {
|
||||
val keyIterator = it.keys.iterator()
|
||||
for(i in 0 until it.size){
|
||||
if(i % 2 == 0){
|
||||
that?.fbl?.addView(if(i < it.size - 1){
|
||||
val line = that.layoutInflater.inflate(R.layout.line_2chapters, that.fbl, false)
|
||||
val leftKey = keyIterator.next()
|
||||
line?.l2cl?.lct?.text = it[leftKey]?.name
|
||||
line?.l2cl?.setOnClickListener { _->
|
||||
loadVolume(it[leftKey]?.path_word?:"null")
|
||||
}
|
||||
val rightKey = keyIterator.next()
|
||||
line?.l2cr?.lct?.text = it[rightKey]?.name
|
||||
line?.l2cr?.setOnClickListener { _->
|
||||
loadVolume(it[rightKey]?.path_word?:"null")
|
||||
}
|
||||
line
|
||||
}else{
|
||||
//Log.d("MyBH", "Add chapter: ${vol[i].volume_name}")
|
||||
val line = that.layoutInflater.inflate(R.layout.line_chapter, that.fbl, false)
|
||||
val key = keyIterator.next()
|
||||
line?.lct?.text = it[key]?.name
|
||||
line?.lcc?.setOnClickListener { _->
|
||||
loadVolume(it[key]?.path_word?:"null")
|
||||
}
|
||||
line
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadVolume(gpw: String){
|
||||
Log.d("MyBH", "start to load chapter")
|
||||
val bundle = Bundle()
|
||||
bundle.putString("group", gpw)
|
||||
book?.results?.comic?.path_word?.let { bundle.putString("path", it) }
|
||||
that?.rootView?.let { Navigation.findNavController(it).navigate(R.id.action_nav_book_to_nav_chapter, bundle) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package top.fumiama.copymanga.ui.chapter
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import top.fumiama.dmzj.copymanga.R
|
||||
import top.fumiama.copymanga.template.NoBackRefreshFragment
|
||||
import java.lang.Thread.sleep
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
class ChapterFragment:NoBackRefreshFragment(R.layout.fragment_chapters) {
|
||||
var handler: ChapterHandler? = null
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
if(isFirstInflate){
|
||||
handler = arguments?.let { ChapterHandler(WeakReference(this), it.getString("path")?:"", it.getString("group")?:"") }
|
||||
Thread{
|
||||
sleep(600)
|
||||
handler?.startLoad()
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package top.fumiama.copymanga.ui.chapter
|
||||
|
||||
import android.os.Looper
|
||||
import android.os.Message
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.navigation.Navigation
|
||||
import kotlinx.android.synthetic.main.fragment_book.*
|
||||
import kotlinx.android.synthetic.main.fragment_chapters.*
|
||||
import kotlinx.android.synthetic.main.line_2chapters.view.*
|
||||
import kotlinx.android.synthetic.main.line_chapter.view.*
|
||||
import top.fumiama.dmzj.copymanga.R
|
||||
import top.fumiama.copymanga.json.ChapterStructure
|
||||
import top.fumiama.copymanga.json.VolumeStructure
|
||||
import top.fumiama.copymanga.template.AutoDownloadHandler
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
class ChapterHandler(that: WeakReference<ChapterFragment>, pw: String, gpw: String):AutoDownloadHandler(
|
||||
that.get()?.getString(R.string.groupInfoApiUrl)?.let { String.format(it, pw, gpw) } ?: "",
|
||||
VolumeStructure::class.java,
|
||||
Looper.myLooper()!!
|
||||
) {
|
||||
private val that = that.get()
|
||||
var hasToastedError = false
|
||||
get(){
|
||||
val re = field
|
||||
field = true
|
||||
return re
|
||||
}
|
||||
private var chapters: VolumeStructure? = null
|
||||
|
||||
override fun handleMessage(msg: Message) {
|
||||
super.handleMessage(msg)
|
||||
when(msg.what){
|
||||
//0 -> setLayouts()
|
||||
1 -> inflateChapters()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun getGsonItem() = chapters
|
||||
override fun setGsonItem(gsonObj: Any) {
|
||||
super.setGsonItem(gsonObj)
|
||||
chapters = gsonObj as VolumeStructure
|
||||
}
|
||||
|
||||
override fun onError() {
|
||||
super.onError()
|
||||
if(!hasToastedError) {
|
||||
Toast.makeText(that?.context, R.string.null_book, Toast.LENGTH_SHORT).show()
|
||||
that?.rootView?.let { it1 ->
|
||||
Navigation.findNavController(it1).navigateUp()
|
||||
}
|
||||
}
|
||||
}
|
||||
override fun doWhenFinishDownload() {
|
||||
super.doWhenFinishDownload()
|
||||
Thread{ sendEmptyMessage(1) }.start()
|
||||
}
|
||||
private fun inflateChapters(){
|
||||
|
||||
that?.fcloading?.visibility = View.GONE
|
||||
}
|
||||
private fun addLine(size: Int, name:String, onClick:(()->Unit)? = null){
|
||||
val line =
|
||||
that?.let { it.layoutInflater.inflate(R.layout.line_chapter, it.fbl, false) }
|
||||
line?.lct?.text = name
|
||||
onClick?.let {action->
|
||||
line?.lcc?.setOnClickListener {action()}
|
||||
}
|
||||
that?.fcl?.addView(line)
|
||||
}
|
||||
private fun loadChapter(chapter: ChapterStructure){
|
||||
/*val bundle = Bundle()
|
||||
|
||||
bundle.putInt("id", id)
|
||||
bundle.putInt("volume", volId)
|
||||
bundle.putInt("chapter", cid)
|
||||
that?.rootView?.let { Navigation.findNavController(it).navigate(R.id.action_nav_chapter_to_nav_reader, bundle) }
|
||||
*/}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
package top.fumiama.copymanga.ui.comicdl
|
||||
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.os.Message
|
||||
import android.util.Log
|
||||
import android.view.Menu
|
||||
import android.view.View
|
||||
import com.google.gson.Gson
|
||||
import top.fumiama.dmzj.copymanga.R
|
||||
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
|
||||
import top.fumiama.copymanga.json.VolumeStructure
|
||||
import top.fumiama.copymanga.template.AutoDownloadThread
|
||||
import top.fumiama.copymanga.template.NoBackRefreshFragment
|
||||
import top.fumiama.copymanga.tools.CMApi
|
||||
import java.io.File
|
||||
import java.lang.Thread.sleep
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
class ComicDlFragment:NoBackRefreshFragment(R.layout.fragment_dlcomic) {
|
||||
var handler: ComicDlHandler? = null
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
if(isFirstInflate){
|
||||
when {
|
||||
arguments?.getBoolean("callFromOldDL", false) == true -> initOldComicData()
|
||||
arguments?.getBoolean("loadJson", false) == true -> context?.getExternalFilesDir("")?.let { home ->
|
||||
arguments?.getString("name")?.let {
|
||||
start2load(loadFromJson(), true, loadGroupsFromFile(File(home, "$it/grps.json")))
|
||||
}
|
||||
}
|
||||
else -> initComicData(
|
||||
arguments?.getString("path"),
|
||||
arguments?.getStringArray("group")
|
||||
)
|
||||
}
|
||||
}
|
||||
mainWeakReference?.get()?.menuMain?.let { setMenuVisible(it) }
|
||||
}
|
||||
|
||||
/*override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
mainWeakReference?.get()?.menuMain?.let { setMenuInvisible(it) }
|
||||
}*/
|
||||
|
||||
fun start2load(volumes: Array<VolumeStructure>, isFromFile: Boolean = false, groupArray: Array<String>? =null){
|
||||
handler = ComicDlHandler(Looper.myLooper()!!,
|
||||
WeakReference(this),
|
||||
volumes,
|
||||
arguments?.getString("name")?:"null",
|
||||
if(isFromFile) groupArray else arguments?.getStringArray("groupNames"))
|
||||
if(!isFromFile) Thread{
|
||||
context?.getExternalFilesDir("")?.let { home ->
|
||||
arguments?.getString("name")?.let { name ->
|
||||
val mangaFolder = File(home, name)
|
||||
if(!mangaFolder.exists()) mangaFolder.mkdirs()
|
||||
File(mangaFolder, "info.json").writeText(Gson().toJson(volumes))
|
||||
arguments?.getStringArray("groupNames")?.let {
|
||||
File(mangaFolder, "grps.json").writeText(Gson().toJson(it))
|
||||
}
|
||||
}
|
||||
}
|
||||
}.start()
|
||||
handler?.startLoad()
|
||||
}
|
||||
|
||||
private fun loadFromJson() = Gson().fromJson(json, Array<VolumeStructure>::class.java)
|
||||
private fun loadGroupsFromFile(file: File) = Gson().fromJson(file.reader(), Array<String>::class.java)
|
||||
|
||||
private fun setMenuVisible(menu: Menu) {
|
||||
val dl = menu.findItem(R.id.action_download)
|
||||
dl?.isVisible = true
|
||||
dl?.setIcon(R.drawable.ic_menu_sort)
|
||||
dl?.setOnMenuItemClickListener {
|
||||
if(handler?.complete == true && it.itemId == R.id.action_download){
|
||||
handler?.showMultiSelectInfo()
|
||||
true
|
||||
}
|
||||
else it.itemId == R.id.action_download
|
||||
}
|
||||
}
|
||||
|
||||
/*private fun setMenuInvisible(menu: Menu){
|
||||
menu.findItem(R.id.action_download)?.isVisible = false
|
||||
}*/
|
||||
|
||||
private fun initComicData(pw: String?, gpws: Array<String>?) {
|
||||
var volumes = arrayOf<VolumeStructure>()
|
||||
val waitHandler = WaitHandler(WeakReference(this))
|
||||
if (gpws != null) {
|
||||
gpws.forEach { gpw ->
|
||||
Log.d("MyCDF", "下载:$gpw")
|
||||
CMApi.getApiUrl(R.string.groupInfoApiUrl, pw, gpw)?.let {
|
||||
AutoDownloadThread(it) { result ->
|
||||
//Log.d("MyCDF", "返回:${result?.decodeToString()}")
|
||||
volumes += Gson().fromJson(
|
||||
result?.decodeToString(),
|
||||
VolumeStructure::class.java
|
||||
)
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
Thread {
|
||||
var c = 0
|
||||
while (c < 80 && volumes.size != gpws.size) {
|
||||
sleep(100)
|
||||
Log.d("MyCDF", "已有:${volumes.size} 共:${gpws.size}")
|
||||
c++
|
||||
}
|
||||
if (volumes.size == gpws.size) {
|
||||
waitHandler.obtainMessage(0, volumes).sendToTarget()
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
|
||||
private fun initOldComicData() {
|
||||
handler = ComicDlHandler(Looper.myLooper()!!,
|
||||
WeakReference(this),
|
||||
arguments?.getString("name")?:"null")
|
||||
handler?.startLoad()
|
||||
}
|
||||
|
||||
class WaitHandler(private val that: WeakReference<ComicDlFragment>): Handler(Looper.myLooper()!!){
|
||||
override fun handleMessage(msg: Message) {
|
||||
super.handleMessage(msg)
|
||||
when(msg.what){
|
||||
0 -> that.get()?.start2load(msg.obj as Array<VolumeStructure>)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
var json: String? = null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,451 @@
|
||||
package top.fumiama.copymanga.ui.comicdl
|
||||
|
||||
import android.animation.ObjectAnimator
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Dialog
|
||||
import android.content.Intent
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.os.Message
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewTreeObserver
|
||||
import android.widget.Toast
|
||||
import com.google.gson.Gson
|
||||
import kotlinx.android.synthetic.main.fragment_book.*
|
||||
import kotlinx.android.synthetic.main.fragment_chapters.*
|
||||
import kotlinx.android.synthetic.main.line_chapter.view.*
|
||||
import kotlinx.android.synthetic.main.widget_downloadbar.*
|
||||
import kotlinx.android.synthetic.main.fragment_dlcomic.*
|
||||
import kotlinx.android.synthetic.main.line_horizonal_empty.view.*
|
||||
import kotlinx.android.synthetic.main.button_tbutton.*
|
||||
import kotlinx.android.synthetic.main.button_tbutton.view.*
|
||||
import kotlinx.android.synthetic.main.line_caption.view.*
|
||||
import top.fumiama.dmzj.copymanga.R
|
||||
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
|
||||
import top.fumiama.copymanga.json.ComicStructureOld
|
||||
import top.fumiama.copymanga.json.VolumeStructure
|
||||
import top.fumiama.copymanga.tools.CMApi
|
||||
import top.fumiama.copymanga.tools.MangaDlTools
|
||||
import top.fumiama.copymanga.tools.PropertiesTools
|
||||
import top.fumiama.copymanga.tools.UITools
|
||||
import top.fumiama.copymanga.ui.comicdl.ComicDlFragment.Companion.json
|
||||
import top.fumiama.copymanga.ui.vm.ViewMangaActivity
|
||||
import top.fumiama.copymanga.views.ChapterToggleButton
|
||||
import top.fumiama.copymanga.views.LazyScrollView
|
||||
import java.io.File
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
class ComicDlHandler(looper: Looper, that: WeakReference<ComicDlFragment>, private val vols: Array<VolumeStructure>, private val comicName: String, private val groupNames: Array<String>?):Handler(looper) {
|
||||
constructor(looper: Looper, that: WeakReference<ComicDlFragment>, comicName: String) : this(looper, that, arrayOf(), comicName, null) {
|
||||
isOld = true
|
||||
}
|
||||
private var isOld = false
|
||||
var complete = false
|
||||
private val that = that.get()
|
||||
private val toolsBox = UITools(that.get()?.context)
|
||||
private val p = PropertiesTools(File("${that.get()?.context?.filesDir}/settings.properties"))
|
||||
private var btnNumPerRow = 4
|
||||
private var btnw = 0
|
||||
private var cdwnWidth = 0
|
||||
private var dl: Dialog? = null
|
||||
private var hasToastedError = false
|
||||
get(){
|
||||
val re = field
|
||||
field = true
|
||||
return re
|
||||
}
|
||||
private var haveSElectAll = false
|
||||
private var checkedChapter = 0
|
||||
private var dldChapter = 0
|
||||
private var haveDlStarted = false
|
||||
private var canDl = false
|
||||
private var tbtnlist: Array<ChapterToggleButton> = arrayOf()
|
||||
private var tbtncnt = 0
|
||||
private var isNewTitle = false
|
||||
private val mangaDlTools = MangaDlTools()
|
||||
private var multiSelect = false
|
||||
private var size = 0
|
||||
private var refreshSize = true
|
||||
private var ltbtn: View? = null
|
||||
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun handleMessage(msg: Message) {
|
||||
super.handleMessage(msg)
|
||||
when(msg.what){
|
||||
0 -> dl?.hide()
|
||||
1 -> {
|
||||
tbtnlist[msg.arg1].setBackgroundResource(R.drawable.rndbg_checked)
|
||||
tbtnlist[msg.arg1].isChecked = false
|
||||
updateProgressBar()
|
||||
}
|
||||
-1 -> {
|
||||
tbtnlist.get(msg.arg1).setBackgroundResource(R.drawable.rndbg_error)
|
||||
dldChapter--
|
||||
Toast.makeText(
|
||||
that?.context,
|
||||
"下载${tbtnlist[msg.arg1].chapterName}失败",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
updateProgressBar()
|
||||
}
|
||||
//2 -> scanHiddenChapters()
|
||||
//3 ->
|
||||
4 -> {
|
||||
that?.pdwn?.progress = 0
|
||||
if (haveSElectAll) {
|
||||
for (i in tbtnlist) {
|
||||
if (!isChapterExists(i.chapterName, i.caption ?: "null")) {
|
||||
i.setBackgroundResource(R.drawable.toggle_button)
|
||||
i.isChecked = false
|
||||
} else if(multiSelect) {
|
||||
i.setBackgroundResource(R.drawable.rndbg_checked)
|
||||
i.isChecked = false
|
||||
}
|
||||
}
|
||||
haveSElectAll = false
|
||||
checkedChapter = 0
|
||||
dldChapter = 0
|
||||
} else {
|
||||
for (i in tbtnlist) {
|
||||
if (multiSelect || !i.isChecked && !isChapterExists(i.chapterName, i.caption ?: "null")) {
|
||||
i.setBackgroundResource(R.drawable.toggle_button)
|
||||
i.isChecked = true
|
||||
checkedChapter++
|
||||
}
|
||||
}
|
||||
haveSElectAll = true
|
||||
}
|
||||
that?.tdwn?.text = "${dldChapter}/${checkedChapter}"
|
||||
}
|
||||
5 -> {
|
||||
setSize(msg.arg2)
|
||||
updateProgressBar(msg.arg2, size)
|
||||
if (!(msg.obj as Boolean)) {
|
||||
Toast.makeText(that?.context, "下载${tbtnlist.get(msg.arg1).chapterName}的第${msg.arg2}页失败", Toast.LENGTH_SHORT).show()
|
||||
}else{
|
||||
val progressTxt = that?.tdwn?.text.toString()
|
||||
that?.tdwn?.text = "${progressTxt.substringBefore(' ')} 的 ${msg.arg2}/${size} 页"
|
||||
}
|
||||
}
|
||||
6 -> that?.tdwn?.text = "${dldChapter}/${checkedChapter}"
|
||||
7 -> deleteChapters(msg.obj as File, msg.arg1)
|
||||
8 -> that?.cdwn?.setCardBackgroundColor(that.resources.getColor(R.color.colorBlue))
|
||||
9 -> that?.cdwn?.setCardBackgroundColor(that.resources.getColor(R.color.colorGreen))
|
||||
10 -> addTbtn(msg.obj as Array<String>)
|
||||
11 -> addCaption(msg.obj as String)
|
||||
12 -> addDiv()
|
||||
13 -> that?.let { Toast.makeText(it.context, "下载${tbtnlist[msg.arg1].textOn}的第${msg.arg2}页失败,尝试重新下载...", Toast.LENGTH_SHORT).show() }
|
||||
}
|
||||
}
|
||||
|
||||
fun startLoad(){
|
||||
setComponents()
|
||||
if(isOld) analyzeOldStructure()
|
||||
else Thread{
|
||||
ViewMangaActivity.urlArray = arrayOf()
|
||||
ViewMangaActivity.fileArray = arrayOf()
|
||||
vols.forEachIndexed { i, vol ->
|
||||
val caption = groupNames?.get(i)?:vol.results.list[0].group_path_word
|
||||
Log.d("MyCDH", "caption: $caption, group name: ${groupNames?.get(i)}")
|
||||
obtainMessage(11, caption).sendToTarget() //addCaption
|
||||
vol.results.list.forEach { chapter ->
|
||||
var data = arrayOf<String>()
|
||||
data += chapter.name
|
||||
data += chapter.uuid
|
||||
data += caption
|
||||
data += CMApi.getApiUrl(R.string.chapterInfoApiUrl, chapter.comic_path_word, chapter.uuid)?:""
|
||||
obtainMessage(10, data).sendToTarget()
|
||||
}
|
||||
sendEmptyMessage(12) //addDiv
|
||||
}
|
||||
complete = true
|
||||
}.start()
|
||||
|
||||
}
|
||||
private fun addDiv(){
|
||||
that?.ldwn?.addView(
|
||||
that.layoutInflater.inflate(R.layout.div_h, that.ldwn, false),
|
||||
ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
)
|
||||
}
|
||||
private fun addCaption(title: String){
|
||||
val tc = that?.layoutInflater?.inflate(R.layout.line_caption, that.ldwn, false)
|
||||
tc?.tcptn?.text = title
|
||||
that?.ldwn?.addView(
|
||||
tc,
|
||||
ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
)
|
||||
addDiv()
|
||||
isNewTitle = true
|
||||
}
|
||||
private fun deleteChapter(f: File, v: ChapterToggleButton) {
|
||||
f.delete()
|
||||
v.setBackgroundResource(R.drawable.toggle_button)
|
||||
v.isChecked = false
|
||||
}
|
||||
private fun deleteChapters(zipf: File, index: Int) {
|
||||
if (multiSelect) {
|
||||
for (i in tbtnlist) {
|
||||
if (i.isChecked) {
|
||||
val f = CMApi.getZipFile(that?.context?.getExternalFilesDir(""), comicName, i.caption?:"null", i.chapterName)
|
||||
if (f.exists()) {
|
||||
deleteChapter(f, i)
|
||||
checkedChapter--
|
||||
}
|
||||
}
|
||||
}
|
||||
multiSelect = false
|
||||
sendEmptyMessage(6)
|
||||
} else deleteChapter(zipf, tbtnlist[index])
|
||||
}
|
||||
private fun isChapterExists(chapter: CharSequence, caption: CharSequence) =
|
||||
File(that?.context?.getExternalFilesDir(""),"$comicName/$caption/$chapter.zip").exists()
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun updateProgressBar() {
|
||||
that?.tdwn?.text = "${++dldChapter}/$checkedChapter"
|
||||
setProgress2(dldChapter * 100 / checkedChapter, 233)
|
||||
}
|
||||
private fun updateProgressBar(pageNow: Int, size: Int) {
|
||||
val delta = 100 / checkedChapter
|
||||
val start = dldChapter * delta
|
||||
val now = pageNow * delta / size
|
||||
setProgress2(start + now, 64)
|
||||
}
|
||||
private fun setProgress2(end: Int, duration: Long) {
|
||||
ObjectAnimator.ofInt(
|
||||
that?.pdwn,
|
||||
"progress",
|
||||
that?.pdwn?.progress?:0,
|
||||
end
|
||||
).setDuration(duration).start()
|
||||
}
|
||||
private fun setSize(pageNow: Int){
|
||||
if(refreshSize || size == 0) {
|
||||
size = mangaDlTools.size
|
||||
refreshSize = false
|
||||
}else if(pageNow == size) refreshSize = true
|
||||
}
|
||||
private fun setComponents() {
|
||||
val widthData = toolsBox.calcWidthFromDpRoot(8, 64)
|
||||
btnNumPerRow = widthData[0]
|
||||
btnw = widthData[1]
|
||||
dl = mainWeakReference?.get()?.let { Dialog(it) }
|
||||
dl?.setContentView(R.layout.dialog_unzipping)
|
||||
that?.dlsdwn?.viewTreeObserver?.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener{
|
||||
override fun onGlobalLayout() {
|
||||
cdwnWidth = that.dlsdwn.width
|
||||
Log.d("MyDl", "Get dlsdwn height: $cdwnWidth")
|
||||
that.dlsdwn.viewTreeObserver.removeOnGlobalLayoutListener(this)
|
||||
}
|
||||
})
|
||||
that?.dllazys?.onScrollListener = object : LazyScrollView.OnScrollListener{
|
||||
override fun onBottom() { //if(dlsdwn.translationX > 0f) showDlCard()
|
||||
}
|
||||
override fun onScroll() { if(that?.dlsdwn?.translationX == 0f) hideDlCard() }
|
||||
override fun onTop() { //if(dlsdwn.translationX > 0f) showDlCard()
|
||||
}
|
||||
}
|
||||
that?.cdwn?.setOnClickListener {
|
||||
if(that.dlsdwn.translationX != 0f) showDlCard()
|
||||
else if(checkedChapter == 0) hideDlCard()
|
||||
else{
|
||||
that.pdwn.progress = 0
|
||||
if (canDl || checkedChapter == 0) canDl = false
|
||||
else {
|
||||
haveDlStarted = true
|
||||
canDl = true
|
||||
Thread{
|
||||
sendEmptyMessage(9) //set dl card color to green
|
||||
downloadMangas()
|
||||
sendEmptyMessage(8) //set dl card color to blue
|
||||
if (!haveDlStarted) {
|
||||
dldChapter = 0
|
||||
checkedChapter = 0
|
||||
this.postDelayed({
|
||||
setProgress2(0, 233)
|
||||
that.tdwn?.text = "0/0"
|
||||
}, 400)
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
that?.cdwn?.setOnLongClickListener {
|
||||
Thread { sendEmptyMessage(4) }.start()
|
||||
return@setOnLongClickListener true
|
||||
}
|
||||
}
|
||||
fun showMultiSelectInfo() {
|
||||
toolsBox.buildInfo("进入多选模式?", "之后可以对已下载漫画进行批量删除/重新下载",
|
||||
"确定", null, "取消", { multiSelect = true })
|
||||
}
|
||||
private fun downloadMangas(){
|
||||
for (i in tbtnlist) {
|
||||
if (i.isChecked) downloadChapterPages(i)
|
||||
if (!canDl) {
|
||||
checkedChapter -= dldChapter
|
||||
dldChapter = 0
|
||||
break
|
||||
}
|
||||
}
|
||||
if (canDl) {
|
||||
haveDlStarted = false
|
||||
canDl = false
|
||||
}
|
||||
}
|
||||
|
||||
private fun downloadChapterPages(i: ChapterToggleButton) {
|
||||
mangaDlTools.onDownloadedListener =
|
||||
object : MangaDlTools.OnDownloadedListener {
|
||||
override fun handleMessage(succeed: Boolean) {
|
||||
this@ComicDlHandler.obtainMessage(if (succeed) 1 else -1, i.index, 0)
|
||||
.sendToTarget()
|
||||
}
|
||||
override fun handleMessage(succeed: Boolean, pageNow: Int) {
|
||||
this@ComicDlHandler.obtainMessage(
|
||||
5,
|
||||
i.index,
|
||||
pageNow,
|
||||
succeed
|
||||
).sendToTarget()
|
||||
}
|
||||
override fun handleMessage(pageNow: Int){
|
||||
this@ComicDlHandler.obtainMessage(13, i.index, pageNow).sendToTarget()
|
||||
}
|
||||
}
|
||||
i.url?.let {
|
||||
mangaDlTools.downloadChapterInVol(
|
||||
it,
|
||||
i.chapterName,
|
||||
i.caption?:"null",
|
||||
i.index
|
||||
)
|
||||
}
|
||||
}
|
||||
private fun showDlCard(){
|
||||
//ObjectAnimator.ofFloat(dlsdwn, "alpha", 0.3f, 0.9f).setDuration(233).start()
|
||||
ObjectAnimator.ofFloat(that?.dlsdwn, "translationX", cdwnWidth.toFloat() * 0.9f, 0f).setDuration(233).start()
|
||||
}
|
||||
|
||||
private fun hideDlCard(){
|
||||
//ObjectAnimator.ofFloat(dlsdwn, "alpha", 0.9f, 0.3f).setDuration(233).start()
|
||||
ObjectAnimator.ofFloat(that?.dlsdwn, "translationX", 0f, cdwnWidth.toFloat() * 0.9f).setDuration(233).start()
|
||||
}
|
||||
private fun addTbtn(data: Array<String>){
|
||||
addTbtn(data[0], data[1], data[2], data[3])
|
||||
ViewMangaActivity.urlArray += data[3]
|
||||
}
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun addTbtn(title: String, uuid: String, caption: String, url: String) {
|
||||
if ((tbtncnt % btnNumPerRow == 0) || isNewTitle) {
|
||||
ltbtn = that?.layoutInflater?.inflate(R.layout.line_horizonal_empty, that.ldwn, false)
|
||||
that?.ldwn?.addView(ltbtn)
|
||||
tbtncnt = 0
|
||||
isNewTitle = false
|
||||
}
|
||||
that?.layoutInflater?.inflate(R.layout.button_tbutton, ltbtn?.ltbtn, false)?.let { tbv ->
|
||||
tbv.tbtn.index = tbtnlist.size
|
||||
tbtnlist += tbv.tbtn
|
||||
tbtncnt++
|
||||
|
||||
tbv.tbtn.uuid = uuid
|
||||
tbv.tbtn.chapterName = title
|
||||
tbv.tbtn.url = url
|
||||
//tbv.tbtn.hint = caption
|
||||
tbv.tbtn.caption = caption
|
||||
tbv.tbtn.layoutParams.width = btnw
|
||||
val zipf = CMApi.getZipFile(that.context?.getExternalFilesDir(""), comicName, caption, title)
|
||||
Log.d("MyCD", "Get zipf: $zipf")
|
||||
ViewMangaActivity.fileArray += zipf
|
||||
if (zipf.exists()) {
|
||||
tbv.tbtn.setBackgroundResource(R.drawable.rndbg_checked)
|
||||
tbv.tbtn.isChecked = false
|
||||
}
|
||||
ltbtn?.ltbtn?.addView(tbv)
|
||||
ltbtn?.invalidate()
|
||||
tbv.tbtn.setOnClickListener {
|
||||
if (zipf.exists() && !multiSelect) {
|
||||
it.tbtn.setBackgroundResource(R.drawable.rndbg_checked)
|
||||
it.tbtn.isChecked = false
|
||||
ViewMangaActivity.zipFile = zipf
|
||||
ViewMangaActivity.dlhandler = this
|
||||
ViewMangaActivity.position = it.tbtn.index
|
||||
dl?.show()
|
||||
|
||||
that.startActivity(Intent(that.context, ViewMangaActivity::class.java)
|
||||
.putExtra("callFrom", "zipFirst")
|
||||
)
|
||||
} else {
|
||||
it.tbtn.setBackgroundResource(R.drawable.toggle_button)
|
||||
if (it.tbtn.isChecked) that.tdwn?.text = "$dldChapter/${++checkedChapter}"
|
||||
else that.tdwn.text = "$dldChapter/${--checkedChapter}"
|
||||
}
|
||||
}
|
||||
tbv.tbtn.setOnLongClickListener {
|
||||
if (zipf.exists()) {
|
||||
toolsBox.buildInfo("确认删除${if (multiSelect) "这些" else "本"}章节?",
|
||||
"该操作将不可撤销",
|
||||
"确定",
|
||||
null,
|
||||
"取消",
|
||||
{
|
||||
Thread {
|
||||
obtainMessage(7, it.tbtn.index, 0, zipf).sendToTarget()
|
||||
}.start()
|
||||
})
|
||||
}else{
|
||||
toolsBox.buildInfo("直接观看", "不下载而进行观看", "确定",
|
||||
null, "取消", {
|
||||
ViewMangaActivity.zipFile = null
|
||||
ViewMangaActivity.dlhandler = this
|
||||
ViewMangaActivity.position = it.tbtn.index
|
||||
dl?.show()
|
||||
|
||||
that.startActivity(Intent(that.context, ViewMangaActivity::class.java))
|
||||
}, null, null
|
||||
)
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun analyzeOldStructure() = Thread{
|
||||
Gson().fromJson(json?.reader(), Array<ComicStructureOld>::class.java)?.let {
|
||||
for (group in it) {
|
||||
that?.layoutInflater?.inflate(R.layout.line_caption, that.ldwn, false)?.let { tc ->
|
||||
tc.tcptn.text = group.name
|
||||
that.ldwn.addView(
|
||||
tc,
|
||||
ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
)
|
||||
that.ldwn.addView(
|
||||
that.layoutInflater.inflate(R.layout.div_h, that.ldwn, false),
|
||||
ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
)
|
||||
isNewTitle = true
|
||||
for (chapter in group.chapters) {
|
||||
val newUrl = CMApi.getApiUrl(R.string.chapterInfoApiUrl, chapter.url.substringAfter("/comic/").substringBefore('/'), chapter.url.substringAfterLast('/'))?:""
|
||||
Log.d("MyCD", "Generate new url: $newUrl")
|
||||
obtainMessage(10, arrayOf(chapter.name, "", group.name, newUrl)).sendToTarget()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
@@ -1,15 +1,13 @@
|
||||
package top.fumiama.copymanga.handler
|
||||
package top.fumiama.copymanga.ui.download
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.os.Message
|
||||
import top.fumiama.copymanga.activity.DlListActivity
|
||||
import java.io.File
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
|
||||
class DlLHandler(looper: Looper, activity: DlListActivity): Handler(looper) {
|
||||
private val dll = WeakReference(activity)
|
||||
class DlLHandler(looper: Looper, dl: DownloadFragment): Handler(looper) {
|
||||
private val dll = WeakReference(dl)
|
||||
override fun handleMessage(msg: Message) {
|
||||
super.handleMessage(msg)
|
||||
when(msg.what){
|
||||
@@ -0,0 +1,201 @@
|
||||
package top.fumiama.copymanga.ui.download
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.Toast
|
||||
import androidx.navigation.Navigation
|
||||
import kotlinx.android.synthetic.main.app_bar_main.*
|
||||
import kotlinx.android.synthetic.main.fragment_download.*
|
||||
import top.fumiama.dmzj.copymanga.R
|
||||
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
|
||||
import top.fumiama.copymanga.template.NoBackRefreshFragment
|
||||
import top.fumiama.copymanga.ui.comicdl.ComicDlFragment
|
||||
import top.fumiama.copymanga.ui.vm.ViewMangaActivity
|
||||
import java.io.File
|
||||
import java.util.regex.Pattern
|
||||
import java.util.zip.ZipInputStream
|
||||
|
||||
class DownloadFragment: NoBackRefreshFragment(R.layout.fragment_download) {
|
||||
private var nullZipDirStr = emptyArray<String>()
|
||||
private var handler: DlLHandler? = null
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
if(isFirstInflate) {
|
||||
arguments?.getString("title")?.let {
|
||||
mainWeakReference?.get()?.toolbar?.title = it
|
||||
}
|
||||
|
||||
handler = DlLHandler(Looper.myLooper()!!, this)
|
||||
handler?.obtainMessage(3, currentDir)?.sendToTarget() //call scanFile
|
||||
}
|
||||
}
|
||||
|
||||
fun scanFile(cd: File?){
|
||||
val isRoot = cd == context?.getExternalFilesDir("")
|
||||
val jsonFile = File(cd, "info.bin")
|
||||
if(isRoot || !jsonFile.exists()) cd?.list()?.sortedArrayWith { o1, o2 ->
|
||||
if(o1.endsWith(".zip") && o2.endsWith(".zip")) (10000*getFloat(o1) - 10000*getFloat(o2) + 0.5).toInt()
|
||||
else o1[0] - o2[0]
|
||||
}?.let {
|
||||
mylv.apply {
|
||||
context.let { c ->
|
||||
adapter = ArrayAdapter(c, android.R.layout.simple_list_item_1, it)
|
||||
setOnItemClickListener { _, _, position, _ ->
|
||||
val chosenFile = File(cd, it[position])
|
||||
val chosenJson = File(chosenFile, "info.bin")
|
||||
val newJson = File(chosenFile, "info.json")
|
||||
//Toast.makeText(this, "进入$chosenFile", Toast.LENGTH_SHORT).show()
|
||||
when {
|
||||
chosenJson.exists() -> callDownloadFragment(chosenJson)
|
||||
newJson.exists() -> callDownloadFragment(newJson, true)
|
||||
chosenFile.isDirectory -> {
|
||||
currentDir = chosenFile
|
||||
callSelf(it[position])
|
||||
}
|
||||
chosenFile.name.endsWith(".zip") -> {
|
||||
Toast.makeText(context, "加载中...", Toast.LENGTH_SHORT).show()
|
||||
ViewMangaActivity.zipFile = chosenFile
|
||||
ViewMangaActivity.comicName = it[position]
|
||||
ViewMangaActivity.position = position
|
||||
ViewMangaActivity.fileArray = it.map { File(cd, it) }.toTypedArray()
|
||||
ViewMangaActivity.urlArray = Array(it.size) {return@Array ""}
|
||||
startActivity(Intent(context, ViewMangaActivity::class.java))
|
||||
}
|
||||
}
|
||||
}
|
||||
setOnItemLongClickListener { _, _, position, _ ->
|
||||
val chosenFile = File(cd, it[position])
|
||||
AlertDialog.Builder(context)
|
||||
.setIcon(R.drawable.ic_launcher_foreground).setMessage("在此执行删除/查错?")
|
||||
.setTitle("提示").setPositiveButton("删除") { _, _ ->
|
||||
if (chosenFile.exists()) handler?.obtainMessage(2, chosenFile)
|
||||
?.sendToTarget() //call rmrf
|
||||
handler?.obtainMessage(3, cd)?.sendToTarget() //call scanFile
|
||||
}.setNegativeButton(android.R.string.cancel) { _, _ -> }
|
||||
.setNeutralButton("查错") { _, _ ->
|
||||
handler?.obtainMessage(1, chosenFile)?.sendToTarget()
|
||||
} //call checkDir
|
||||
.show()
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun rmrf(f: File) {
|
||||
if (f.isDirectory) f.listFiles()?.let {
|
||||
for (i in it)
|
||||
if (i.isDirectory) rmrf(i)
|
||||
else i.delete()
|
||||
}
|
||||
f.delete()
|
||||
}
|
||||
|
||||
fun checkDir(f: File){
|
||||
nullZipDirStr = emptyArray()
|
||||
findNullWebpZipFileInDir(f)
|
||||
if(nullZipDirStr.isNotEmpty()) showErrorZip(nullZipDirStr.joinToString("\n"))
|
||||
else Toast.makeText(context, "未发现错误", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
private fun callDownloadFragment(jsonFile: File, isNew: Boolean = false){
|
||||
val bundle = Bundle()
|
||||
Log.d("MyDF", "Call dl and is new: $isNew")
|
||||
bundle.putBoolean(if(isNew) "loadJson" else "callFromOldDL", true)
|
||||
bundle.putString("name", jsonFile.parentFile?.name?:"Null")
|
||||
ComicDlFragment.json = jsonFile.readText()
|
||||
Log.d("MyDF", "root view: $rootView")
|
||||
rootView?.let {
|
||||
Log.d("MyDF", "action_nav_download_to_nav_group")
|
||||
Navigation.findNavController(it).navigate(R.id.action_nav_download_to_nav_group, bundle)
|
||||
}
|
||||
}
|
||||
|
||||
private fun callSelf(title: String){
|
||||
val bundle = Bundle()
|
||||
bundle.putString("title", title)
|
||||
Log.d("MyDF", "Call self to $title")
|
||||
Log.d("MyDF", "root view: $rootView")
|
||||
rootView?.let {
|
||||
Log.d("MyDF", "action_nav_download_self")
|
||||
Navigation.findNavController(it).navigate(R.id.action_nav_download_self, bundle)
|
||||
}
|
||||
}
|
||||
|
||||
private fun findNullWebpZipFileInDir(f: File){
|
||||
if (f.isDirectory) f.listFiles()?.let {
|
||||
for (i in it)
|
||||
if (i.isDirectory) findNullWebpZipFileInDir(i)
|
||||
else if(!checkZip(i)) nullZipDirStr += i.path.substringAfterLast(context?.getExternalFilesDir("").toString())
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkZip(f: File): Boolean{
|
||||
return try {
|
||||
val exist = f.exists()
|
||||
if (!exist) true
|
||||
else {
|
||||
var re = true
|
||||
val zip = ZipInputStream(f.inputStream().buffered())
|
||||
var entry = zip.nextEntry
|
||||
while (entry != null) {
|
||||
if (!entry.isDirectory){
|
||||
if(zip.read() == -1 && entry.size == 0L){
|
||||
re = false
|
||||
break
|
||||
}
|
||||
}
|
||||
entry = zip.nextEntry
|
||||
}
|
||||
zip.closeEntry()
|
||||
zip.close()
|
||||
re
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Toast.makeText(context, "读取${f.name}错误!", Toast.LENGTH_SHORT).show()
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
private fun showErrorZip(msg: CharSequence) = AlertDialog.Builder(context)
|
||||
.setIcon(R.drawable.ic_launcher_foreground)
|
||||
.setTitle("找到以下错误文件,是否删除?")
|
||||
.setMessage(msg)
|
||||
.setPositiveButton(android.R.string.ok){_, _ -> deleteErrorZip()}
|
||||
.setNegativeButton(android.R.string.cancel){_, _ ->}
|
||||
.show()
|
||||
|
||||
private fun deleteErrorZip(){
|
||||
val exf = context?.getExternalFilesDir("")
|
||||
for(i in nullZipDirStr){
|
||||
val f = File(exf, i)
|
||||
if(f.exists()) f.delete()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getFloat(oldString: String): Float {
|
||||
val newString = StringBuffer()
|
||||
var matcher = Pattern.compile("\\d+.+\\d+").matcher(oldString)
|
||||
while (matcher.find()) newString.append(matcher.group())
|
||||
//Log.d("MyDLL1", newString.toString())
|
||||
if(newString.isEmpty()){
|
||||
matcher = Pattern.compile("\\d").matcher(oldString)
|
||||
while (matcher.find()) newString.append(matcher.group())
|
||||
}
|
||||
//Log.d("MyDLL2", newString.toString().toFloat().toString())
|
||||
return if(newString.isEmpty()) 0f else newString.toString().toFloat()
|
||||
}
|
||||
|
||||
companion object{
|
||||
var currentDir: File? = null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package top.fumiama.copymanga.ui.history
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import kotlinx.android.synthetic.main.fragment_history.*
|
||||
import top.fumiama.dmzj.copymanga.R
|
||||
|
||||
class HistoryFragment : Fragment() {
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
return inflater.inflate(R.layout.fragment_history, container, false)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package top.fumiama.copymanga.ui.home
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.navigation.Navigation
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.model.GlideUrl
|
||||
import com.bumptech.glide.load.model.LazyHeaders
|
||||
import kotlinx.android.synthetic.main.fragment_home.*
|
||||
import kotlinx.android.synthetic.main.viewpage_horizonal.view.*
|
||||
import top.fumiama.dmzj.copymanga.R
|
||||
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
|
||||
import top.fumiama.copymanga.template.NoBackRefreshFragment
|
||||
import top.fumiama.copymanga.tools.CMApi
|
||||
import java.lang.Thread.sleep
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
class HomeFragment : NoBackRefreshFragment(R.layout.fragment_home) {
|
||||
lateinit var homeHandler: HomeHandler
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
if(isFirstInflate){
|
||||
val theme = resources.newTheme()
|
||||
swiperefresh.setColorSchemeColors(
|
||||
resources.getColor(R.color.colorAccent, theme),
|
||||
resources.getColor(R.color.colorBlue2, theme),
|
||||
resources.getColor(R.color.colorGreen, theme))
|
||||
|
||||
Thread{
|
||||
homeHandler.obtainMessage(-1, true).sendToTarget()
|
||||
while(mainWeakReference?.get()?.isDrawerClosed != true) sleep(233)
|
||||
//homeHandler.sendEmptyMessage(6) //removeAllViews
|
||||
homeHandler.fhib = null
|
||||
sleep(600)
|
||||
homeHandler.startLoad()
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
homeHandler = HomeHandler(WeakReference(this))
|
||||
}
|
||||
|
||||
inner class ViewData(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
inner class RecyclerViewAdapter :
|
||||
RecyclerView.Adapter<ViewData>() {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewData {
|
||||
return ViewData(layoutInflater.inflate(R.layout.viewpage_horizonal, parent, false))
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewData, position: Int) {
|
||||
val thisBanner = homeHandler.index?.results?.banners?.get(position)
|
||||
thisBanner?.cover?.let {
|
||||
//Log.d("MyHomeFVP", "Load img: $it")
|
||||
Glide.with(this@HomeFragment).load(
|
||||
GlideUrl(it, CMApi.myGlideHeaders)
|
||||
).timeout(10000).into(holder.itemView.vpi)
|
||||
}
|
||||
holder.itemView.vpt.text = thisBanner?.brief
|
||||
holder.itemView.vpc.setOnClickListener {
|
||||
val bundle = Bundle()
|
||||
homeHandler.index?.results?.banners?.get(position)?.comic?.path_word?.let { it1 -> bundle.putString("path", it1) }
|
||||
rootView?.let { it1 -> Navigation.findNavController(it1).navigate(R.id.action_nav_home_to_nav_book, bundle) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = homeHandler.index?.results?.banners?.size?:0
|
||||
}
|
||||
}
|
||||
}
|
||||
326
app/src/main/java/top/fumiama/copymanga/ui/home/HomeHandler.kt
Normal file
326
app/src/main/java/top/fumiama/copymanga/ui/home/HomeHandler.kt
Normal file
@@ -0,0 +1,326 @@
|
||||
package top.fumiama.copymanga.ui.home
|
||||
|
||||
import android.animation.ObjectAnimator
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import android.os.Looper
|
||||
import android.os.Message
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.view.ViewTreeObserver
|
||||
import android.widget.Toast
|
||||
import androidx.cardview.widget.CardView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.navigation.Navigation
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.model.GlideUrl
|
||||
import com.to.aboomy.pager2banner.Banner
|
||||
import com.to.aboomy.pager2banner.IndicatorView
|
||||
import com.to.aboomy.pager2banner.ScaleInTransformer
|
||||
import kotlinx.android.synthetic.main.card_book.view.*
|
||||
import kotlinx.android.synthetic.main.fragment_home.*
|
||||
import kotlinx.android.synthetic.main.line_1bookline.view.*
|
||||
import top.fumiama.dmzj.copymanga.R
|
||||
import top.fumiama.copymanga.json.ComicStructure
|
||||
import top.fumiama.copymanga.json.IndexStructure
|
||||
import top.fumiama.copymanga.template.AutoDownloadHandler
|
||||
import top.fumiama.copymanga.tools.CMApi
|
||||
import top.fumiama.copymanga.tools.UITools
|
||||
import java.lang.Thread.sleep
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
class HomeHandler(that: WeakReference<HomeFragment>) :AutoDownloadHandler(
|
||||
that.get()?.getString(R.string.mainPageApiUrl) ?: "",
|
||||
IndexStructure::class.java,
|
||||
Looper.myLooper()!!,
|
||||
9
|
||||
) {
|
||||
private val homeF = that.get()
|
||||
var index: IndexStructure? = null
|
||||
var fhib: View? = null
|
||||
get() {
|
||||
Log.d("MyHH", "Get fhib.")
|
||||
if(field == null){
|
||||
field = homeF?.layoutInflater?.inflate(R.layout.viewpage_banner, homeF.fhl, false)
|
||||
Thread{homeF?.homeHandler?.sendEmptyMessage(3)}.start()
|
||||
}
|
||||
return field
|
||||
}
|
||||
var indexLines = arrayOf<View>()
|
||||
|
||||
override fun handleMessage(msg: Message) {
|
||||
super.handleMessage(msg)
|
||||
when (msg.what) {
|
||||
-1 -> {
|
||||
homeF?.swiperefresh?.isEnabled = msg.obj as Boolean
|
||||
homeF?.swiperefresh?.isRefreshing = msg.obj as Boolean
|
||||
}
|
||||
//0 -> setLayouts()
|
||||
1 -> inflateCardLines()
|
||||
|
||||
3 -> setBanner(fhib as Banner)
|
||||
|
||||
5 -> setBannerInfo(msg.obj as Banner)
|
||||
6 -> {
|
||||
homeF?.fhl?.let {
|
||||
ObjectAnimator.ofFloat(it, "alpha", 1f, 0f).setDuration(233).start()
|
||||
it.postDelayed({
|
||||
it.removeAllViews()
|
||||
ObjectAnimator.ofFloat(it, "alpha", 0f, 1f).setDuration(233).start()
|
||||
}, 233)
|
||||
}
|
||||
}
|
||||
7 -> inflateBanner()
|
||||
8 -> homeF?.fhl?.addView(indexLines[msg.arg1])
|
||||
//9 -> checkIndex()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getGsonItem() = index
|
||||
override fun setGsonItem(gsonObj: Any) {
|
||||
super.setGsonItem(gsonObj)
|
||||
index = gsonObj as IndexStructure
|
||||
}
|
||||
override fun onError() {
|
||||
super.onError()
|
||||
Toast.makeText(homeF?.context, R.string.web_error, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
override fun doWhenFinishDownload() {
|
||||
super.doWhenFinishDownload()
|
||||
try {
|
||||
Thread {
|
||||
sendEmptyMessage(7) //inflateBanner
|
||||
sendEmptyMessage(1) //inflateCardLines
|
||||
}.start()
|
||||
} catch (e: Exception) {
|
||||
Toast.makeText(homeF?.context, R.string.load_home_error, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun inflateBanner() = homeF?.fhl?.addView(fhib)
|
||||
|
||||
private fun inflateTopics(){
|
||||
index?.results?.topics?.list?.let {
|
||||
var comics = arrayOf<ComicStructure>()
|
||||
for((i, topic) in it.withIndex()){
|
||||
if(i > 2) break
|
||||
val newComic = ComicStructure()
|
||||
newComic.name = topic.title
|
||||
newComic.cover = topic.cover
|
||||
newComic.path_word = topic.path_word
|
||||
comics += newComic
|
||||
}
|
||||
if(comics.size == 3) allocateLine(homeF?.getString(R.string.topics_series)?:"", R.drawable.img_hot_serial, comics)
|
||||
}
|
||||
}
|
||||
|
||||
private fun inflateRec(){
|
||||
index?.results?.recComics?.list?.let {
|
||||
var comics = arrayOf<ComicStructure>()
|
||||
for((i, rec) in it.withIndex()){
|
||||
if(i > 2) break
|
||||
comics += rec.comic
|
||||
}
|
||||
if(comics.size == 3) allocateLine(homeF?.getString(R.string.manga_rec)?:"", R.drawable.img_master_work, comics)
|
||||
}
|
||||
}
|
||||
|
||||
private fun inflateRank(){
|
||||
var comics = arrayOf<ComicStructure>()
|
||||
index?.results?.rankDayComics?.list?.let {
|
||||
for((i, book) in it.withIndex()){
|
||||
if(i > 2) break
|
||||
comics += book.comic
|
||||
}
|
||||
}
|
||||
index?.results?.rankWeekComics?.list?.let {
|
||||
for((i, book) in it.withIndex()){
|
||||
if(i > 2) break
|
||||
comics += book.comic
|
||||
}
|
||||
}
|
||||
index?.results?.rankMonthComics?.list?.let {
|
||||
for((i, book) in it.withIndex()){
|
||||
if(i > 2) break
|
||||
comics += book.comic
|
||||
}
|
||||
}
|
||||
if(comics.size == 9) allocateLine(homeF?.getString(R.string.rank_list)?:"", R.drawable.img_novel_bill, comics)
|
||||
}
|
||||
|
||||
private fun inflateHot(){
|
||||
index?.results?.hotComics?.let {
|
||||
var comics = arrayOf<ComicStructure>()
|
||||
for((i, rec) in it.withIndex()){
|
||||
if(i > 8) break
|
||||
comics += rec.comic
|
||||
}
|
||||
if(comics.size == 9) allocateLine(homeF?.getString(R.string.hot_list)?:"", R.drawable.img_hot, comics)
|
||||
}
|
||||
}
|
||||
|
||||
private fun inflateNew(){
|
||||
index?.results?.newComics?.let {
|
||||
var comics = arrayOf<ComicStructure>()
|
||||
for((i, rec) in it.withIndex()){
|
||||
if(i > 8) break
|
||||
comics += rec.comic
|
||||
}
|
||||
if(comics.size == 9) allocateLine(homeF?.getString(R.string.new_list)?:"", R.drawable.img_latest_pub, comics)
|
||||
}
|
||||
}
|
||||
|
||||
private fun inflateFinish(){
|
||||
index?.results?.finishComics?.list?.let {
|
||||
var comics = arrayOf<ComicStructure>()
|
||||
for((i, rec) in it.withIndex()){
|
||||
if(i > 5) break
|
||||
comics += rec
|
||||
}
|
||||
if(comics.size == 6) allocateLine(homeF?.getString(R.string.complete)?:"", R.drawable.img_novel_eye, comics, true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun inflateCardLines() {
|
||||
inflateRec()
|
||||
inflateTopics()
|
||||
inflateHot()
|
||||
inflateNew()
|
||||
inflateFinish()
|
||||
inflateRank()
|
||||
Thread{
|
||||
for(i in indexLines.indices) obtainMessage(8, i, 0).sendToTarget()
|
||||
obtainMessage(-1, false).sendToTarget() //closeLoad
|
||||
}.start()
|
||||
}
|
||||
|
||||
private fun setBanner(v: Banner): Banner {
|
||||
v.viewTreeObserver.addOnGlobalLayoutListener(object :
|
||||
ViewTreeObserver.OnGlobalLayoutListener {
|
||||
override fun onGlobalLayout() {
|
||||
//Log.d("MyMy", "Width: ${v.width}")
|
||||
v.layoutParams.height = (v.width / 1.875 + 0.5).toInt()
|
||||
v.invalidate()
|
||||
v.viewTreeObserver.removeOnGlobalLayoutListener(this)
|
||||
}
|
||||
})
|
||||
Thread{this.obtainMessage(5, v).sendToTarget()}.start() //setBannerInfo
|
||||
return v
|
||||
}
|
||||
|
||||
private fun setBannerInfo(v: Banner){
|
||||
homeF?.context?.let { UITools(it) }?.let {
|
||||
v
|
||||
.addPageTransformer(ScaleInTransformer())
|
||||
.setPageMargin(it.dp2px(20) ?: 0, it.dp2px(10) ?: 0)
|
||||
.setIndicator(
|
||||
IndicatorView(homeF.context)
|
||||
.setIndicatorColor(Color.DKGRAY)
|
||||
.setIndicatorSelectorColor(Color.WHITE)
|
||||
.setIndicatorStyle(IndicatorView.IndicatorStyle.INDICATOR_BEZIER)
|
||||
).adapter = homeF.ViewData(v).RecyclerViewAdapter()
|
||||
}
|
||||
v.invalidate()
|
||||
homeF?.fhov?.swipeRefreshLayout = homeF?.swiperefresh
|
||||
homeF?.swiperefresh?.setOnRefreshListener {
|
||||
Log.d("MyHFH", "Refresh items.")
|
||||
//index = null
|
||||
//Thread{this@HomeHandler.obtainMessage(-1, true).sendToTarget()}.start() //startLoad
|
||||
Thread{
|
||||
index = null
|
||||
//fhib = null
|
||||
indexLines = arrayOf()
|
||||
this@HomeHandler.sendEmptyMessage(6) //removeAllViews
|
||||
sleep(300)
|
||||
this@HomeHandler.sendEmptyMessage(0) //setLayouts
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
|
||||
private fun allocateLine(title: String, iconResId: Int, comics: Array<ComicStructure>, finish: Boolean = false): Int{
|
||||
val p = indexLines.size
|
||||
val c = comics.size / 3
|
||||
homeF?.layoutInflater?.inflate(
|
||||
when(c){
|
||||
1 -> R.layout.line_1bookline
|
||||
2 -> R.layout.line_2bookline
|
||||
3 -> R.layout.line_3bookline
|
||||
else -> return -1
|
||||
}, homeF.fhl, false)?.let {
|
||||
scanCards(it, comics, finish)
|
||||
it.rttitle.text = title
|
||||
it.ir.setImageResource(iconResId)
|
||||
setLineHeight(it, c)
|
||||
indexLines += it
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
/*private fun setLines(v: View, position: Int) {
|
||||
lines?.let {
|
||||
v.rttitle.text = it[position].title
|
||||
v.ir.setImageResource(
|
||||
when (position) {
|
||||
1 -> R.drawable.img_novel_refresh
|
||||
2 -> R.drawable.img_novel_more
|
||||
3 -> R.drawable.img_novel_play
|
||||
4 -> R.drawable.img_novel_eye
|
||||
else -> R.drawable.img_novel_refresh
|
||||
}
|
||||
)
|
||||
Thread{this.obtainMessage(4, position, 0, v).sendToTarget()}.start() //scanCards
|
||||
setLineHeight(v, if (position == 4) 2 else 1)
|
||||
if(position == 4) {
|
||||
Thread{ this.obtainMessage(-1, false).sendToTarget() }.start() //closeLoad
|
||||
}
|
||||
if(position == 1) v.setOnClickListener {
|
||||
Navigation.findNavController(it).navigate(R.id.action_nav_home_to_nav_latest)
|
||||
}else v.rimore.visibility = View.GONE
|
||||
}
|
||||
}*/
|
||||
|
||||
private fun scanCards(v: View, comics: Array<ComicStructure>, finish: Boolean = false){
|
||||
var id = v.rc1.id
|
||||
var card = v.findViewById<ConstraintLayout>(id)
|
||||
for (data in comics){
|
||||
setCards(
|
||||
card.cic,
|
||||
data.path_word,
|
||||
data.name,
|
||||
data.cover,
|
||||
finish
|
||||
)
|
||||
card = v.findViewById(++id)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setCards(cv: CardView, pw: String, name: String, img: String, isFinal: Boolean = false) {
|
||||
cv.tic.text = name
|
||||
homeF?.let {
|
||||
Glide.with(it).load(GlideUrl(img, CMApi.myGlideHeaders)).timeout(10000).into(cv.imic)
|
||||
}
|
||||
if (isFinal) cv.sgnic.visibility = View.VISIBLE
|
||||
cv.setOnClickListener {
|
||||
val bundle = Bundle()
|
||||
bundle.putString("path", pw)
|
||||
homeF?.rootView?.let { Navigation.findNavController(it).navigate(R.id.action_nav_home_to_nav_book, bundle) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun setLineHeight(v: View, cardCount: Int) {
|
||||
v.viewTreeObserver.addOnGlobalLayoutListener(object :
|
||||
ViewTreeObserver.OnGlobalLayoutListener {
|
||||
override fun onGlobalLayout() {
|
||||
homeF?.context?.let { UITools(it) }?.let {
|
||||
val spaceTitle = it.dp2px(49)!!
|
||||
val cardSpace = it.dp2px(16)!!
|
||||
v.layoutParams.height =
|
||||
((v.width - cardSpace * 3) * cardCount * 4.0 / 9.0 + spaceTitle + cardSpace * cardCount + 0.5).toInt()
|
||||
v.invalidate()
|
||||
v.viewTreeObserver.removeOnGlobalLayoutListener(this)
|
||||
}
|
||||
//Log.d("MyVTOL", "Set card line: (${v.width}, ${v.height})")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package top.fumiama.copymanga.ui.latest
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import top.fumiama.dmzj.copymanga.R
|
||||
import top.fumiama.copymanga.template.InfoCardLoader
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
class LatestFragment: Fragment()/*InfoCardLoader(R.layout.line_lazybooklines, R.id.action_nav_latest_to_nav_book, "name", "cover", "id") {
|
||||
override fun getApiUrl() = getString(R.string.recentUpdateApiUrl).let { String.format(it, page) }
|
||||
}*/
|
||||
@@ -0,0 +1,94 @@
|
||||
package top.fumiama.copymanga.ui.rank
|
||||
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.github.zawadz88.materialpopupmenu.popupMenu
|
||||
import com.google.gson.Gson
|
||||
import kotlinx.android.synthetic.main.anchor_popular.view.*
|
||||
import kotlinx.android.synthetic.main.line_rank.*
|
||||
import top.fumiama.dmzj.copymanga.R
|
||||
import top.fumiama.copymanga.json.FilterStructure
|
||||
import top.fumiama.copymanga.template.InfoCardLoader
|
||||
import java.lang.Thread.sleep
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
class RankFragment: Fragment()/*: InfoCardLoader(R.layout.fragment_rank, R.id.action_nav_rank_to_nav_book, "name", "cover", "id") {
|
||||
private var type = 0
|
||||
private var pop_sub = 0
|
||||
private var filter: Array<FilterStructure>? = null
|
||||
get() {
|
||||
if (field == null) {
|
||||
context?.assets?.open(getString(R.string.assets_filter))?.let {
|
||||
field = Gson().fromJson(it.reader(), Array<FilterStructure>::class.java)
|
||||
it.close()
|
||||
}
|
||||
}
|
||||
return field
|
||||
}
|
||||
|
||||
override fun getApiUrl() =
|
||||
getString(R.string.rankApiUrl).let { String.format(it, pop_sub, type, page) }
|
||||
|
||||
override fun setListeners() {
|
||||
super.setListeners()
|
||||
setPop()
|
||||
setClasses()
|
||||
}
|
||||
|
||||
private fun setPop(){
|
||||
line_rank_pop.apt.setText(if(pop_sub == 1) R.string.menu_pop_sub else R.string.menu_pop_pop)
|
||||
line_rank_pop.setOnClickListener {
|
||||
val popupMenu = popupMenu {
|
||||
style = R.style.Widget_MPM_Menu_Dark_CustomBackground
|
||||
section {
|
||||
item {
|
||||
labelRes = if(pop_sub == 0) R.string.menu_pop_sub else R.string.menu_pop_pop
|
||||
labelColor = it.apt.currentTextColor
|
||||
iconDrawable =
|
||||
this@RankFragment.context?.let { it1 -> ContextCompat.getDrawable(it1, R.drawable.ic_refresh) } //optional
|
||||
iconColor = it.apt.currentTextColor
|
||||
callback = { //optional
|
||||
if(pop_sub == 0){
|
||||
pop_sub = 1
|
||||
it.apt.setText(R.string.menu_pop_sub)
|
||||
}else{
|
||||
pop_sub = 0
|
||||
it.apt.setText(R.string.menu_pop_pop)
|
||||
}
|
||||
Thread{
|
||||
sleep(400)
|
||||
mh?.sendEmptyMessage(4)
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.context?.let { it1 -> popupMenu.show(it1, it) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun setClasses(){
|
||||
val items = filter?.get(0)?.items
|
||||
line_rank_class.apt.text = items?.get(0)?.tag_name?:getString(R.string.text_null)
|
||||
line_rank_class.setOnClickListener {
|
||||
val popupMenu = popupMenu {
|
||||
style = R.style.Widget_MPM_Menu_Dark_CustomBackground
|
||||
if(items != null) section {
|
||||
for(i in items.indices) item {
|
||||
label = items[i]?.tag_name
|
||||
labelColor = it.apt.currentTextColor
|
||||
callback = { //optional
|
||||
it.apt.text = label
|
||||
type = items[i]?.tag_id?:0
|
||||
Thread{
|
||||
sleep(400)
|
||||
mh?.sendEmptyMessage(4)
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.context?.let { it1 -> popupMenu.show(it1, it) }
|
||||
}
|
||||
}
|
||||
}*/
|
||||
@@ -0,0 +1,12 @@
|
||||
package top.fumiama.copymanga.ui.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import top.fumiama.dmzj.copymanga.R
|
||||
import top.fumiama.copymanga.template.NoBackRefreshFragment
|
||||
|
||||
class SettingsFragment:NoBackRefreshFragment(R.layout.fragment_settings) {
|
||||
}
|
||||
126
app/src/main/java/top/fumiama/copymanga/ui/sort/SortFragment.kt
Normal file
126
app/src/main/java/top/fumiama/copymanga/ui/sort/SortFragment.kt
Normal file
@@ -0,0 +1,126 @@
|
||||
package top.fumiama.copymanga.ui.sort
|
||||
|
||||
import android.animation.ObjectAnimator
|
||||
import android.view.View
|
||||
import com.github.zawadz88.materialpopupmenu.popupMenu
|
||||
import com.google.gson.Gson
|
||||
import kotlinx.android.synthetic.main.anchor_popular.view.*
|
||||
import kotlinx.android.synthetic.main.line_lazybooklines.*
|
||||
import kotlinx.android.synthetic.main.line_sort.*
|
||||
import top.fumiama.dmzj.copymanga.R
|
||||
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
|
||||
import top.fumiama.copymanga.json.FilterStructure
|
||||
import top.fumiama.copymanga.template.AutoDownloadThread
|
||||
import top.fumiama.copymanga.template.InfoCardLoader
|
||||
import java.lang.Thread.sleep
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
class SortFragment : InfoCardLoader(R.layout.fragment_sort, R.id.action_nav_sort_to_nav_book) {
|
||||
private val sortWay = listOf("datetime_updated", "-datetime_updated", "popular", "-popular")
|
||||
private var theme = -1
|
||||
private var sortValue = 0
|
||||
private var filter: FilterStructure? = null
|
||||
|
||||
override fun getApiUrl() =
|
||||
getString(R.string.sortApiUrl).let {
|
||||
String.format(
|
||||
it,
|
||||
page * 21,
|
||||
sortWay[sortValue],
|
||||
if(theme >= 0) (filter?.results?.theme?.get(theme)?.path_word ?: "") else ""
|
||||
)
|
||||
}
|
||||
|
||||
override fun setListeners() {
|
||||
super.setListeners()
|
||||
setUpdate()
|
||||
setHot()
|
||||
AutoDownloadThread(getString(R.string.filterApiUrl)) {
|
||||
it?.let {
|
||||
filter = Gson().fromJson(it.inputStream().reader(), FilterStructure::class.java)
|
||||
mainWeakReference?.get()?.runOnUiThread{
|
||||
setClasses()
|
||||
}
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
|
||||
override fun onLoadFinish() {
|
||||
super.onLoadFinish()
|
||||
mainWeakReference?.get()?.runOnUiThread {
|
||||
mypl.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
private fun setUpdate(){
|
||||
line_sort_time.apt.setText(R.string.menu_update_time)
|
||||
line_sort_time.setOnClickListener {
|
||||
sortValue = if(it.apim.rotation == 0f) {
|
||||
ObjectAnimator.ofFloat(it.apim, "rotation", 0f, 180f).setDuration(233).start()
|
||||
1
|
||||
}else{
|
||||
ObjectAnimator.ofFloat(it.apim, "rotation", 180f, 0f).setDuration(233).start()
|
||||
0
|
||||
}
|
||||
Thread{
|
||||
sleep(400)
|
||||
mh?.sendEmptyMessage(4)
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setClasses(){
|
||||
filter?.results?.theme?.let { items ->
|
||||
line_sort_class.apt.text = "全部"
|
||||
line_sort_class.setOnClickListener {
|
||||
val popupMenu = popupMenu {
|
||||
style = R.style.Widget_MPM_Menu_Dark_CustomBackground
|
||||
section {
|
||||
item {
|
||||
label = "全部"
|
||||
labelColor = it.apt.currentTextColor
|
||||
callback = {
|
||||
theme = -1
|
||||
it.apt.text = "全部"
|
||||
Thread{
|
||||
sleep(400)
|
||||
mh?.sendEmptyMessage(4)
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
for(i in items.indices) item {
|
||||
label = items[i].name
|
||||
labelColor = it.apt.currentTextColor
|
||||
callback = { //optional
|
||||
it.apt.text = label
|
||||
theme = i
|
||||
Thread{
|
||||
sleep(400)
|
||||
mh?.sendEmptyMessage(4)
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.context?.let { it1 -> popupMenu.show(it1, it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setHot() {
|
||||
line_sort_hot.apt.setText(R.string.menu_hot)
|
||||
line_sort_hot.setOnClickListener {
|
||||
sortValue = if (it.apim.rotation == 0f) {
|
||||
ObjectAnimator.ofFloat(it.apim, "rotation", 0f, 180f).setDuration(233).start()
|
||||
1
|
||||
} else {
|
||||
ObjectAnimator.ofFloat(it.apim, "rotation", 180f, 0f).setDuration(233).start()
|
||||
0
|
||||
}
|
||||
Thread {
|
||||
sleep(400)
|
||||
mh?.sendEmptyMessage(4)
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package top.fumiama.copymanga.ui.sub
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import kotlinx.android.synthetic.main.fragment_sub.*
|
||||
import top.fumiama.dmzj.copymanga.R
|
||||
|
||||
class SubFragment : Fragment() {
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
return inflater.inflate(R.layout.fragment_sub, container, false)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package top.fumiama.copymanga.ui.vm
|
||||
|
||||
import android.content.Intent
|
||||
import android.widget.Toast
|
||||
import top.fumiama.copymanga.ui.vm.ViewMangaActivity.Companion.fileArray
|
||||
import top.fumiama.copymanga.ui.vm.ViewMangaActivity.Companion.position
|
||||
import top.fumiama.copymanga.ui.vm.ViewMangaActivity.Companion.urlArray
|
||||
import top.fumiama.copymanga.ui.vm.ViewMangaActivity.Companion.zipFile
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
class PagesManager(w: WeakReference<ViewMangaActivity>) {
|
||||
val v = w.get()
|
||||
private var isEndL = false
|
||||
private var isEndR = false
|
||||
@ExperimentalStdlibApi
|
||||
fun toPreviousPage(){
|
||||
toPage(v?.r2l==true)
|
||||
}
|
||||
@ExperimentalStdlibApi
|
||||
fun toNextPage(){
|
||||
toPage(v?.r2l!=true)
|
||||
}
|
||||
private fun judgePrevious() = v?.pageNum?:0 > 1
|
||||
private fun judgeNext() = v?.pageNum?:0 < v?.count?:0
|
||||
@ExperimentalStdlibApi
|
||||
fun toPage(goNext:Boolean){
|
||||
if (v?.clicked == false) {
|
||||
if (if(goNext)judgeNext() else judgePrevious()) {
|
||||
if(goNext) {
|
||||
v.scrollForward()
|
||||
isEndR = false
|
||||
} else {
|
||||
v.scrollBack()
|
||||
isEndL = false
|
||||
}
|
||||
} else {
|
||||
val chapterPosition = position + if(goNext) 1 else -1
|
||||
urlArray.let {
|
||||
if(chapterPosition >= 0 && chapterPosition < it.size) it[chapterPosition].let {
|
||||
if (if(goNext)isEndR else isEndL) {
|
||||
val f = fileArray[chapterPosition]
|
||||
val intent = Intent(v, ViewMangaActivity::class.java)
|
||||
//if(v.zipFirst) intent.putExtra("callFrom", "zipFirst")
|
||||
if(!goNext){
|
||||
ViewMangaActivity.pn = -2
|
||||
intent.putExtra("function", "log")
|
||||
}
|
||||
zipFile = if (f.exists()) f else null
|
||||
position = chapterPosition
|
||||
v.tt.canDo = false
|
||||
//ViewMangaActivity.dlhandler = null
|
||||
v.startActivity(intent)
|
||||
v.finish()
|
||||
} else {
|
||||
val hint = if(goNext) '下' else '上'
|
||||
Toast.makeText(
|
||||
v.applicationContext,
|
||||
"再次按下加载${hint}一章",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
if(goNext) isEndR = true
|
||||
else isEndL = true
|
||||
}
|
||||
} else Toast.makeText(
|
||||
v.applicationContext,
|
||||
"已经到头了~",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}
|
||||
} else v?.hideObjs()
|
||||
}
|
||||
fun manageInfo(){
|
||||
if (v?.clicked == false) v.showObjs() else v?.hideObjs()
|
||||
}
|
||||
}
|
||||
209
app/src/main/java/top/fumiama/copymanga/ui/vm/VMHandler.kt
Normal file
209
app/src/main/java/top/fumiama/copymanga/ui/vm/VMHandler.kt
Normal file
@@ -0,0 +1,209 @@
|
||||
package top.fumiama.copymanga.ui.vm
|
||||
|
||||
import android.animation.ObjectAnimator
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Dialog
|
||||
import android.os.Looper
|
||||
import android.os.Message
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import com.google.gson.Gson
|
||||
import kotlinx.android.synthetic.main.activity_viewmanga.*
|
||||
import kotlinx.android.synthetic.main.widget_infodrawer.*
|
||||
import kotlinx.android.synthetic.main.widget_infodrawer.view.*
|
||||
import top.fumiama.dmzj.copymanga.R
|
||||
import top.fumiama.copymanga.json.Chapter2Return
|
||||
import top.fumiama.copymanga.json.ChapterWithContent
|
||||
import top.fumiama.copymanga.json.ComicStructure
|
||||
import top.fumiama.copymanga.template.AutoDownloadHandler
|
||||
import top.fumiama.copymanga.tools.PropertiesTools
|
||||
import top.fumiama.copymanga.ui.vm.ViewMangaActivity.Companion.comicName
|
||||
import top.fumiama.copymanga.ui.vm.ViewMangaActivity.Companion.pn
|
||||
import top.fumiama.copymanga.views.ScaleImageView
|
||||
import java.io.File
|
||||
import java.lang.Exception
|
||||
import java.lang.Thread.sleep
|
||||
import java.lang.ref.WeakReference
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import java.util.zip.ZipInputStream
|
||||
|
||||
class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler(
|
||||
url, Chapter2Return::class.java, Looper.myLooper()!!
|
||||
) {
|
||||
var manga: Chapter2Return? = null
|
||||
private val wv = WeakReference(activity)
|
||||
private val infcard = wv.get()?.infcard
|
||||
private var infcShowed = false
|
||||
val dl = wv.get()?.let {
|
||||
val re = Dialog(it)
|
||||
re.setContentView(R.layout.dialog_unzipping)
|
||||
re
|
||||
}
|
||||
private var delta = -1f
|
||||
get() {
|
||||
if (field < 0) field = wv.get()?.infoDrawerDelta ?: 0f
|
||||
return field
|
||||
}
|
||||
private val week: String
|
||||
get() {
|
||||
val cal = Calendar.getInstance()
|
||||
return when (cal[Calendar.DAY_OF_WEEK]) {
|
||||
1 -> "周日"
|
||||
2 -> "周一"
|
||||
3 -> "周二"
|
||||
4 -> "周三"
|
||||
5 -> "周四"
|
||||
6 -> "周五"
|
||||
7 -> "周六"
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
var progressLog: PropertiesTools? = null
|
||||
|
||||
@SuppressLint("SimpleDateFormat", "SetTextI18n")
|
||||
override fun handleMessage(msg: Message) {
|
||||
super.handleMessage(msg)
|
||||
when (msg.what) {
|
||||
1 -> if (infcShowed) {
|
||||
hideInfCard(); infcShowed = false
|
||||
}
|
||||
2 -> if (!infcShowed) {
|
||||
showInfCard(); infcShowed = true
|
||||
}
|
||||
3 -> infcShowed = if (infcShowed) {
|
||||
hideInfCard(); false
|
||||
} else {
|
||||
showInfCard(); true
|
||||
}
|
||||
4 -> {
|
||||
val simg = msg.obj as ScaleImageView
|
||||
wv.get()?.loadImgOn(simg, msg.arg1)
|
||||
simg.setHeight2FitImgWidth()
|
||||
if(msg.arg2 == 1) sendEmptyMessage(8)
|
||||
}
|
||||
5 -> wv.get()?.clearImgOn(msg.obj as ScaleImageView)
|
||||
6 -> wv.get()?.prepareLastPage(msg.arg1, msg.arg2)
|
||||
7 -> dl?.show()
|
||||
8 -> Thread{
|
||||
sleep(233)
|
||||
sendEmptyMessage(13)
|
||||
}.start()
|
||||
9 -> loadThread(msg.arg1)
|
||||
10 -> loadThread()
|
||||
11 -> loadImgsIntoLine(msg.arg1)
|
||||
12 -> loadImgsIntoLine()
|
||||
13 -> {
|
||||
dl?.hide()
|
||||
wv.get()?.restorePN()
|
||||
}
|
||||
14 -> {
|
||||
val item = (pn - 1) / (wv.get()?.verticalLoadMaxCount?:40) * (wv.get()?.verticalLoadMaxCount?:40)
|
||||
loadThread(item)
|
||||
Log.d("MyVMH", "Load page from $item")
|
||||
}
|
||||
22 -> wv.get()?.idtime?.text = SimpleDateFormat("HH:mm").format(Date()) + week + wv.get()?.toolsBox?.netinfo
|
||||
}
|
||||
}
|
||||
|
||||
override fun getGsonItem() = manga
|
||||
override fun setGsonItem(gsonObj: Any) {
|
||||
super.setGsonItem(gsonObj)
|
||||
manga = gsonObj as Chapter2Return
|
||||
}
|
||||
override fun onError() {
|
||||
super.onError()
|
||||
wv.get()?.toolsBox?.toastError("下载章节信息失败")
|
||||
}
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
override fun doWhenFinishDownload() {
|
||||
super.doWhenFinishDownload()
|
||||
prepareManga()
|
||||
}
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
fun loadFromFile(file: File): Boolean {
|
||||
return try {
|
||||
val jsonFile = File(file.parentFile, "${file.nameWithoutExtension}.json")
|
||||
if(jsonFile.exists()) manga = Gson().fromJson(jsonFile.reader(), Chapter2Return::class.java)
|
||||
else{
|
||||
manga = Chapter2Return()
|
||||
manga?.let {
|
||||
it.results = Chapter2Return.Results()
|
||||
it.results.comic = ComicStructure()
|
||||
it.results.comic.name = file.parentFile?.name
|
||||
it.results.chapter = ChapterWithContent()
|
||||
it.results.chapter.name = file.nameWithoutExtension
|
||||
it.results.chapter.size = countZipEntries(file)
|
||||
}
|
||||
}
|
||||
prepareManga()
|
||||
true
|
||||
}catch (e: Exception){
|
||||
e.printStackTrace()
|
||||
//wv.get()?.toolsBox?.toastError("读取本地章节信息失败")
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
private fun countZipEntries(file: File): Int{
|
||||
var count = 0
|
||||
try {
|
||||
val zip = ZipInputStream(file.inputStream().buffered())
|
||||
var entry = zip.nextEntry
|
||||
while (entry != null) {
|
||||
if (!entry.isDirectory) count++
|
||||
entry = zip.nextEntry
|
||||
}
|
||||
zip.closeEntry()
|
||||
zip.close()
|
||||
} catch (e: Exception) {
|
||||
wv.get()?.toolsBox?.toastError("统计zip图片数错误!")
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
private fun prepareManga(){
|
||||
comicName = manga?.results?.comic?.name
|
||||
progressLog = PropertiesTools(File("${wv.get()?.filesDir}/progress/${manga?.results?.comic?.name}"))
|
||||
wv.get()?.count = manga?.results?.chapter?.size?:0
|
||||
wv.get()?.initManga()
|
||||
wv.get()?.vprog?.visibility = View.GONE
|
||||
}
|
||||
private fun loadImgsIntoLine(item: Int = (wv.get()?.currentItem?:0), maxCount: Int = (wv.get()?.verticalLoadMaxCount?:40)){
|
||||
Log.d("MyVMH", "Fun: loadImgsIntoLine($item)")
|
||||
val count = wv.get()?.count?.minus(1)?:0
|
||||
val notFull = item + maxCount > count
|
||||
val loadCount = (if(notFull) count - item else maxCount) - 1
|
||||
Log.d("MyVMH", "loadCount: $loadCount")
|
||||
if(loadCount >= 0) for(i in 0..loadCount) obtainMessage(4,item + i, if(i == loadCount - 1)1 else 0, wv.get()?.scrollImages?.get(i)).sendToTarget()
|
||||
else sendEmptyMessage(8)
|
||||
if(notFull) obtainMessage(6, loadCount + 1, maxCount).sendToTarget()
|
||||
}
|
||||
|
||||
private fun loadThread() = Thread{
|
||||
sendEmptyMessage(7)
|
||||
//sleep(233)
|
||||
sendEmptyMessage(12)
|
||||
}.start()
|
||||
|
||||
private fun loadThread(item: Int) = Thread{
|
||||
sendEmptyMessage(7)
|
||||
//sleep(233)
|
||||
Log.d("MyVMH", "loadImgsIntoLine($item)")
|
||||
obtainMessage(11, item, 0).sendToTarget()
|
||||
}.start()
|
||||
|
||||
private fun showInfCard() {
|
||||
Log.d("MyVMH", "Read info drawer delta: $delta")
|
||||
ObjectAnimator.ofFloat(infcard?.idc, "alpha", 0.3F, 0.8F).setDuration(233).start()
|
||||
ObjectAnimator.ofFloat(infcard, "translationY", delta, 0F).setDuration(233).start()
|
||||
}
|
||||
|
||||
private fun hideInfCard() {
|
||||
ObjectAnimator.ofFloat(infcard?.idc, "alpha", 0.8F, 0.3F).setDuration(233).start()
|
||||
ObjectAnimator.ofFloat(infcard, "translationY", 0F, delta).setDuration(233).start()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,474 @@
|
||||
package top.fumiama.copymanga.ui.vm
|
||||
|
||||
import android.animation.ObjectAnimator
|
||||
import android.annotation.SuppressLint
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.util.Log
|
||||
import android.view.*
|
||||
import android.widget.SeekBar
|
||||
import android.widget.Toast
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.model.GlideUrl
|
||||
import com.liaoinstan.springview.widget.SpringView
|
||||
import kotlinx.android.synthetic.main.activity_viewmanga.*
|
||||
import kotlinx.android.synthetic.main.line_header.view.*
|
||||
import kotlinx.android.synthetic.main.page_imgview.*
|
||||
import kotlinx.android.synthetic.main.page_imgview.view.*
|
||||
import kotlinx.android.synthetic.main.page_scrollimgview.*
|
||||
import kotlinx.android.synthetic.main.page_scrollimgview.view.*
|
||||
import kotlinx.android.synthetic.main.widget_infodrawer.*
|
||||
import kotlinx.android.synthetic.main.widget_infodrawer.view.*
|
||||
import kotlinx.android.synthetic.main.widget_titlebar.*
|
||||
import kotlinx.android.synthetic.main.widget_titlebar.view.*
|
||||
import kotlinx.android.synthetic.main.widget_viewmangainfo.*
|
||||
import top.fumiama.dmzj.copymanga.R
|
||||
import top.fumiama.copymanga.template.TitleActivityTemplate
|
||||
import top.fumiama.copymanga.tools.CMApi
|
||||
import top.fumiama.copymanga.tools.DownloadTools
|
||||
import top.fumiama.copymanga.tools.TimeThread
|
||||
import top.fumiama.copymanga.views.ScaleImageView
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.*
|
||||
import java.util.zip.ZipFile
|
||||
|
||||
class ViewMangaActivity : TitleActivityTemplate() {
|
||||
var count = 0
|
||||
private lateinit var handler: VMHandler
|
||||
lateinit var tt: TimeThread
|
||||
var clicked = false
|
||||
private var isInSeek = false
|
||||
private var isInScroll = true
|
||||
//private var progressLog: PropertiesTools? = null
|
||||
var scrollImages = arrayOf<ScaleImageView>()
|
||||
//var zipFirst = false
|
||||
private var useFullScreen = false
|
||||
var r2l = true
|
||||
var currentItem = 0
|
||||
var verticalLoadMaxCount = 40
|
||||
private var notUseVP = true
|
||||
private var isVertical = false
|
||||
private var q = 90
|
||||
private val size get() = if(count / verticalLoadMaxCount > currentItem / verticalLoadMaxCount) verticalLoadMaxCount else count % verticalLoadMaxCount
|
||||
var infoDrawerDelta = 0f
|
||||
var pageNum: Int
|
||||
get() = getPageNumber()
|
||||
set(value) = setPageNumber(value)
|
||||
//var pn = 0
|
||||
private val isPnValid: Boolean get(){
|
||||
if(pn == -2) pn = count
|
||||
return intent.getStringExtra("function") == "log" && pn > 0
|
||||
}
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
setContentView(R.layout.activity_viewmanga)
|
||||
super.onCreate(savedInstanceState)
|
||||
va = WeakReference(this)
|
||||
//progressLog = PropertiesTools(File("$filesDir/progress/${chapter2Return?.results?.chapter?.comic_id}"))
|
||||
//dlZip2View = intent.getStringExtra("callFrom") == "Dl" || p["dlZip2View"] == "true"
|
||||
//zipFirst = intent.getStringExtra("callFrom") == "zipFirst"
|
||||
useFullScreen = p["useFullScreen"] != "true"
|
||||
r2l = p["r2l"] == "true"
|
||||
isVertical = p["vertical"] == "true"
|
||||
notUseVP = p["noVP"] == "true" || isVertical
|
||||
//url = intent.getStringExtra("url")
|
||||
handler = VMHandler(this, if(urlArray.isNotEmpty()) urlArray[position] else "")
|
||||
if (p["quality"] != "null") q = p["quality"].toInt()
|
||||
if (p["verticalMax"] != "null") verticalLoadMaxCount = p["verticalMax"].toInt()
|
||||
tt = TimeThread(handler, 22)
|
||||
tt.canDo = true
|
||||
tt.start()
|
||||
|
||||
Log.d("MyVM", "Now ZipFile is $zipFile")
|
||||
try {
|
||||
if (zipFile != null && zipFile?.exists() == true) {
|
||||
if (!handler.loadFromFile(zipFile!!)) prepareImgFromWeb()
|
||||
} else prepareImgFromWeb()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
toolsBox.toastError("加载漫画错误")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onWindowFocusChanged(hasFocus: Boolean) {
|
||||
super.onWindowFocusChanged(hasFocus)
|
||||
if(useFullScreen) {
|
||||
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.R)
|
||||
window.decorView.systemUiVisibility = 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
|
||||
else {
|
||||
window.setDecorFitsSystemWindows(false)
|
||||
window.insetsController?.hide(WindowInsets.Type.statusBars())
|
||||
//window.insetsController?.hide(WindowInsets.Type.navigationBars())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun restorePN(){
|
||||
if (isPnValid) {
|
||||
isInScroll = false
|
||||
pageNum = pn
|
||||
pn = -1
|
||||
}
|
||||
sendProgress()
|
||||
}
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
fun initManga(){
|
||||
prepareItems(count)
|
||||
if (!isVertical) restorePN()
|
||||
}
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
private fun prepareImgFromWeb() {
|
||||
handler.startLoad()
|
||||
}
|
||||
|
||||
private fun getPageNumber(): Int {
|
||||
return if (r2l && !notUseVP) count - vp.currentItem
|
||||
else (if (notUseVP) currentItem else vp.currentItem) + 1
|
||||
}
|
||||
|
||||
private fun setPageNumber(num: Int) {
|
||||
if (r2l && !notUseVP) vp.currentItem = count - num
|
||||
else if (notUseVP) {
|
||||
if(isVertical){
|
||||
currentItem = num - 1
|
||||
val delta = currentItem % verticalLoadMaxCount
|
||||
Log.d("MyVM", "Height: ${psivl.height}, scrollY: ${psivs.scrollY}")
|
||||
if (!isInScroll || isInSeek) psivs.scrollY = psivl.height / size * delta
|
||||
updateSeekBar()
|
||||
}
|
||||
else {
|
||||
currentItem = num - 1
|
||||
try {
|
||||
loadOneImg()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
toolsBox.toastError("页数${currentItem}不合法")
|
||||
}
|
||||
}
|
||||
} else vp.currentItem = num - 1
|
||||
}
|
||||
|
||||
fun clearImgOn(imgView: ScaleImageView){
|
||||
imgView.visibility = View.GONE
|
||||
}
|
||||
|
||||
private fun getTempFile(position: Int) = File(cacheDir, "$position")
|
||||
|
||||
private fun getImgUrl(position: Int) = handler.manga?.results?.chapter?.let {
|
||||
it.contents[it.words.indexOf(position)].url
|
||||
}
|
||||
|
||||
fun loadImgOn(imgView: ScaleImageView, position: Int){
|
||||
if (zipFile?.exists() == true) imgView.setImageBitmap(getImgBitmap(position))
|
||||
else if(isVertical) {
|
||||
val f = getTempFile(position)
|
||||
if(DownloadTools.downloadUsingUrlRet(getImgUrl(position), f))
|
||||
imgView.setImageBitmap(BitmapFactory.decodeFile(f.path))
|
||||
else Toast.makeText(this, "下载第${position}页失败", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
else Glide.with(this)
|
||||
.load(GlideUrl(getImgUrl(position), CMApi.myGlideHeaders))
|
||||
.timeout(10000)
|
||||
.into(imgView)
|
||||
imgView.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
private fun loadOneImg() {
|
||||
loadImgOn(onei, currentItem)
|
||||
updateSeekBar()
|
||||
}
|
||||
|
||||
private fun initImgList(){
|
||||
for (i in 0..39) {
|
||||
val newImg = ScaleImageView(this)
|
||||
scrollImages += newImg
|
||||
psivl.addView(newImg)
|
||||
}
|
||||
}
|
||||
|
||||
fun prepareLastPage(loadCount: Int, maxCount: Int){
|
||||
for (i in loadCount until maxCount) handler.obtainMessage(5, scrollImages[i]).sendToTarget()
|
||||
handler.dl?.hide()
|
||||
}
|
||||
|
||||
private fun getImgBitmap(position: Int): Bitmap? {
|
||||
Log.d("MyVM", "Get bitmap @$position, count is $count")
|
||||
if (position >= count || position < 0) return null
|
||||
else {
|
||||
val zip = ZipFile(zipFile)
|
||||
if (q == 100) return BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.jpg")))
|
||||
else {
|
||||
val out = ByteArrayOutputStream()
|
||||
try {
|
||||
BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.webp")))
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return null
|
||||
}?.compress(Bitmap.CompressFormat.JPEG, q, out)
|
||||
return BitmapFactory.decodeStream(ByteArrayInputStream(out.toByteArray()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setIdPosition(position: Int) {
|
||||
infoDrawerDelta = position.toFloat()
|
||||
infcard.translationY = infoDrawerDelta
|
||||
Log.d("MyVM", "Set info drawer delta to $infoDrawerDelta")
|
||||
}
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun prepareItems(size: Int) {
|
||||
ttitle.text = handler.manga?.results?.chapter?.name
|
||||
prepareVP()
|
||||
prepareInfoBar(size)
|
||||
if (notUseVP && !isVertical) loadOneImg()
|
||||
prepareIdBtVH()
|
||||
toolsBox.dp2px(67)?.let { setIdPosition(it) }
|
||||
prepareIdBtFullScreen()
|
||||
prepareIdBtVP()
|
||||
prepareIdBtLR()
|
||||
handler.progressLog?.let {
|
||||
//it["uuid"] = handler.manga?.results?.comic?.uuid
|
||||
it["name"] = inftitle.ttitle.text
|
||||
}
|
||||
}
|
||||
|
||||
private fun sendProgress() {
|
||||
handler.progressLog?.let {
|
||||
//it["chapterId"] = hm.chapterId.toString()
|
||||
it["page"] = pageNum.toString()
|
||||
//it["name"] = inftitle.ttitle.text
|
||||
}
|
||||
}
|
||||
|
||||
private fun prepareIdBtLR() {
|
||||
idtblr.isChecked = r2l
|
||||
idtblr.setOnClickListener {
|
||||
if (idtblr.isChecked) p["r2l"] = "true"
|
||||
else p["r2l"] = "false"
|
||||
Toast.makeText(this, "下次浏览生效", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun prepareIdBtVP() {
|
||||
idtbvp.isChecked = notUseVP
|
||||
idtbvp.setOnClickListener {
|
||||
if (idtbvp.isChecked) p["noVP"] = "true"
|
||||
else p["noVP"] = "false"
|
||||
Toast.makeText(this, "下次浏览生效", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun prepareVP() {
|
||||
if (notUseVP) {
|
||||
vp.visibility = View.GONE
|
||||
if(!isVertical) vone.visibility = View.VISIBLE
|
||||
} else {
|
||||
vp.visibility = View.VISIBLE
|
||||
vone.visibility = View.GONE
|
||||
vp.adapter = ViewData(vp).RecyclerViewAdapter()
|
||||
vp.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
|
||||
override fun onPageSelected(position: Int) {
|
||||
updateSeekBar()
|
||||
super.onPageSelected(position)
|
||||
}
|
||||
})
|
||||
if (r2l) vp.currentItem = count - 1
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateSeekBar() {
|
||||
if (!isInSeek) hideObjs()
|
||||
updateSeekText()
|
||||
updateSeekProgress()
|
||||
sendProgress()
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun prepareInfoBar(size: Int) {
|
||||
oneinfo.alpha = 0F
|
||||
infseek.visibility = View.GONE
|
||||
isearch.visibility = View.GONE
|
||||
inftitle.ttitle.text = handler.manga?.results?.chapter?.name
|
||||
inftxtprogress.text = "$pageNum/$size"
|
||||
infseek.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
|
||||
override fun onProgressChanged(p0: SeekBar?, p1: Int, isHuman: Boolean) {
|
||||
if (isHuman) {
|
||||
if (p1 >= (pageNum + 1) * 100 / size) scrollForward()
|
||||
else if (p1 < (pageNum - 1) * 100 / size) scrollBack()
|
||||
}
|
||||
}
|
||||
override fun onStartTrackingTouch(p0: SeekBar?) {
|
||||
isInSeek = true
|
||||
}
|
||||
|
||||
override fun onStopTrackingTouch(p0: SeekBar?) {
|
||||
isInSeek = false
|
||||
}
|
||||
})
|
||||
isearch.setOnClickListener {
|
||||
handler.sendEmptyMessage(3)
|
||||
}
|
||||
}
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
private fun prepareIdBtVH() {
|
||||
idtbvh.isChecked = isVertical
|
||||
if (isVertical) {
|
||||
val vsps = vsp as SpringView
|
||||
vsps.footerView.lht.text = "更多"
|
||||
vsps.headerView.lht.text = "更多"
|
||||
val pm = PagesManager(WeakReference(this))
|
||||
vsps.setListener(object :SpringView.OnFreshListener{
|
||||
override fun onLoadmore() {
|
||||
//scrollForward()
|
||||
pm.toPage(true)
|
||||
vsps.onFinishFreshAndLoad()
|
||||
}
|
||||
override fun onRefresh() {
|
||||
//scrollBack()
|
||||
pm.toPage(false)
|
||||
vsps.onFinishFreshAndLoad()
|
||||
}
|
||||
})
|
||||
vp.visibility = View.GONE
|
||||
vsp.visibility = View.VISIBLE
|
||||
initImgList()
|
||||
handler.sendEmptyMessage(if(isPnValid)14 else 10)
|
||||
psivs.setOnScrollChangeListener { _, _, scrollY, _, _ ->
|
||||
isInScroll = true
|
||||
if(!isInSeek){
|
||||
val newCurrent = (scrollY.toFloat() * size.toFloat() / psivl.height.toFloat() + 0.5).toInt()
|
||||
pageNum += newCurrent - currentItem % verticalLoadMaxCount
|
||||
}
|
||||
}
|
||||
}
|
||||
idtbvh.setOnClickListener {
|
||||
p["vertical"] = if (idtbvh.isChecked) "true" else "false"
|
||||
Toast.makeText(this, "下次浏览生效", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun prepareIdBtFullScreen() {
|
||||
idtbfullscreen.isChecked = !useFullScreen
|
||||
idtbfullscreen.setOnClickListener {
|
||||
p["useFullScreen"] = if (idtbfullscreen.isChecked) "true" else "false"
|
||||
Toast.makeText(this, "下次浏览生效", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
fun scrollBack() {
|
||||
isInScroll = false
|
||||
if(isVertical && (pageNum-1) % verticalLoadMaxCount == 0){
|
||||
Log.d("MyVM", "Do scroll back, isVertical: $isVertical, pageNum: $pageNum")
|
||||
handler.obtainMessage(9, currentItem - verticalLoadMaxCount, 0).sendToTarget() //loadImgsIntoLine(currentItem - verticalLoadMaxCount)
|
||||
psivl.postDelayed({ pageNum-- }, 233)
|
||||
}else pageNum--
|
||||
}
|
||||
|
||||
fun scrollForward() {
|
||||
isInScroll = false
|
||||
pageNum++
|
||||
if(isVertical && (pageNum-1) % verticalLoadMaxCount == 0) handler.sendEmptyMessage(10)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun updateSeekText() {
|
||||
inftxtprogress.text = "$pageNum/$count"
|
||||
}
|
||||
|
||||
private fun updateSeekProgress() {
|
||||
infseek.progress = pageNum * 100 / count
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
dlhandler?.sendEmptyMessage(0)
|
||||
tt.canDo = false
|
||||
dlhandler = null
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
inner class ViewData(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
inner class RecyclerViewAdapter :
|
||||
RecyclerView.Adapter<ViewData>() {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewData {
|
||||
return ViewData(
|
||||
LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.page_imgview, parent, false)
|
||||
)
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility", "SetTextI18n")
|
||||
override fun onBindViewHolder(holder: ViewData, position: Int) {
|
||||
val pos = if (r2l) count - position - 1 else position
|
||||
if (zipFile?.exists() == true) getImgBitmap(pos)?.let {
|
||||
Glide.with(this@ViewMangaActivity).load(it)
|
||||
//.thumbnail(Glide.with(this@ViewMangaActivity).load(R.drawable.load))
|
||||
.into(holder.itemView.onei)
|
||||
//holder.itemView.onei.setImageBitmap(it)
|
||||
}
|
||||
else Glide.with(this@ViewMangaActivity).load(
|
||||
GlideUrl(getImgUrl(pos), CMApi.myGlideHeaders))
|
||||
.timeout(10000)
|
||||
//.thumbnail(Glide.with(this@ViewMangaActivity).load(R.drawable.load))
|
||||
.into(holder.itemView.onei)
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return count
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun showObjs() {
|
||||
infseek.visibility = View.VISIBLE
|
||||
isearch.visibility = View.VISIBLE
|
||||
ObjectAnimator.ofFloat(
|
||||
oneinfo,
|
||||
"alpha",
|
||||
oneinfo.alpha,
|
||||
1F
|
||||
).setDuration(233).start()
|
||||
clicked = true
|
||||
}
|
||||
|
||||
fun hideObjs() {
|
||||
ObjectAnimator.ofFloat(
|
||||
oneinfo,
|
||||
"alpha",
|
||||
oneinfo.alpha,
|
||||
0F
|
||||
).setDuration(233).start()
|
||||
clicked = false
|
||||
infseek.postDelayed({
|
||||
infseek.visibility = View.GONE
|
||||
isearch.visibility = View.GONE
|
||||
}, 300)
|
||||
handler.sendEmptyMessage(1)
|
||||
}
|
||||
|
||||
companion object {
|
||||
var comicName: String? = null
|
||||
var urlArray = arrayOf<String>()
|
||||
var fileArray = arrayOf<File>()
|
||||
var position = 0
|
||||
var zipFile: File? = null
|
||||
var dlhandler: Handler? = null
|
||||
var va: WeakReference<ViewMangaActivity>? = null
|
||||
var pn = 0
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package top.fumiama.copymanga.view
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.util.Log
|
||||
import android.webkit.WebView
|
||||
import top.fumiama.copymanga.web.WebViewClient
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@SuppressLint("JavascriptInterface")
|
||||
class JSWebView : WebView {
|
||||
constructor(context: Context): super(context)
|
||||
constructor(context: Context, attributeSet: AttributeSet): super(context, attributeSet)
|
||||
constructor(context: Context, attributeSet: AttributeSet, defSA: Int): super(context, attributeSet, defSA)
|
||||
constructor(context: Context, UA: String) : super(context) { settings.userAgentString = UA }
|
||||
init {
|
||||
settings.javaScriptEnabled = true
|
||||
settings.domStorageEnabled = true
|
||||
Log.d("MyJSW", "UA is: ${settings.userAgentString}")
|
||||
}
|
||||
fun setWebViewClient(jsFileName: String){webViewClient = WebViewClient(context, jsFileName)}
|
||||
fun loadJSInterface(obj: Any){addJavascriptInterface(obj, "GM")}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package top.fumiama.copymanga.view
|
||||
package top.fumiama.copymanga.views
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
@@ -10,9 +10,9 @@ class ChapterToggleButton: ToggleButton {
|
||||
constructor(context: Context?): super(context, null)
|
||||
|
||||
var url: CharSequence? = null
|
||||
val hash get() = url?.toString()?.substringAfterLast('/')
|
||||
var caption: CharSequence? = null
|
||||
var index: Int = 0
|
||||
var uuid: CharSequence? = null
|
||||
var chapterName: CharSequence = "null"
|
||||
set(value) {
|
||||
textOn = value
|
||||
@@ -1,20 +1,20 @@
|
||||
package top.fumiama.copymanga.view
|
||||
package top.fumiama.copymanga.views
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.widget.ScrollView
|
||||
import androidx.core.widget.NestedScrollView
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
class LazyScrollView : ScrollView {
|
||||
class LazyScrollView : NestedScrollView {
|
||||
private val view: View?
|
||||
get() = getChildAt(0)
|
||||
|
||||
constructor(context: Context?) : super(context)
|
||||
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
|
||||
constructor(context: Context?, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle)
|
||||
constructor(context: Context) : super(context)
|
||||
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
|
||||
constructor(context: Context, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle)
|
||||
|
||||
init {
|
||||
setOnTouchListener { _, event ->
|
||||
@@ -0,0 +1,22 @@
|
||||
package top.fumiama.copymanga.views
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import androidx.cardview.widget.CardView
|
||||
import java.io.File
|
||||
|
||||
class MangaCardView:CardView {
|
||||
constructor(context: Context): super(context)
|
||||
constructor(context: Context, attrs: AttributeSet?): super (context, attrs)
|
||||
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int): super(context, attrs, defStyleAttr)
|
||||
|
||||
var name = ""
|
||||
var append: String? = null
|
||||
var headImageUrl: String? = null
|
||||
//var uuid: String? = null
|
||||
var path: String? = null
|
||||
var isFinish = false
|
||||
var index = 0
|
||||
var chapterUUID: String? = null
|
||||
var pageNumber: Int? = null
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package top.fumiama.copymanga.views
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import com.akscorp.overscrollablescrollview.OverscrollableNestedScrollView
|
||||
import kotlinx.android.synthetic.main.app_bar_main.*
|
||||
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
|
||||
|
||||
open class OverScrollView :OverscrollableNestedScrollView{
|
||||
constructor(context: Context) : super(context)
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle)
|
||||
|
||||
override fun isAchieveTop(): Boolean {
|
||||
val re = super.isAchieveTop()
|
||||
if(re) mainWeakReference?.get()?.appbar?.setExpanded(true)
|
||||
return re
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package top.fumiama.copymanga.view
|
||||
package top.fumiama.copymanga.views
|
||||
|
||||
import android.animation.ValueAnimator
|
||||
import android.animation.ValueAnimator.AnimatorUpdateListener
|
||||
@@ -14,8 +14,8 @@ import android.view.GestureDetector
|
||||
import android.view.GestureDetector.SimpleOnGestureListener
|
||||
import android.view.MotionEvent
|
||||
import android.widget.ImageView
|
||||
import top.fumiama.copymanga.activity.ViewMangaActivity
|
||||
import top.fumiama.copymanga.tool.PagesManager
|
||||
import top.fumiama.copymanga.ui.vm.PagesManager
|
||||
import top.fumiama.copymanga.ui.vm.ViewMangaActivity
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.*
|
||||
import kotlin.math.sqrt
|
||||
@@ -94,17 +94,17 @@ class ScaleImageView : ImageView {
|
||||
* 外部变换矩阵记录了图片手势操作的最终结果,是相对于图片fit center状态的变换.
|
||||
* 默认值为单位矩阵,此时图片为fit center状态.
|
||||
*
|
||||
@param matrix 用于填充结果的对象
|
||||
@return 如果传了matrix参数则将matrix填充后返回,否则new一个填充返回
|
||||
@param matrix 用于填充结果的对象
|
||||
@return 如果传了matrix参数则将matrix填充后返回,否则new一个填充返回
|
||||
|
||||
fun getOuterMatrix(matrix: Matrix?): Matrix {
|
||||
var matrix = matrix
|
||||
if (matrix == null) {
|
||||
matrix = Matrix(mOuterMatrix)
|
||||
} else {
|
||||
matrix.set(mOuterMatrix)
|
||||
}
|
||||
return matrix
|
||||
var matrix = matrix
|
||||
if (matrix == null) {
|
||||
matrix = Matrix(mOuterMatrix)
|
||||
} else {
|
||||
matrix.set(mOuterMatrix)
|
||||
}
|
||||
return matrix
|
||||
}*/
|
||||
|
||||
/**
|
||||
@@ -140,21 +140,23 @@ class ScaleImageView : ImageView {
|
||||
}
|
||||
|
||||
fun setHeight2FitImgWidth(){
|
||||
matrix.reset()
|
||||
val imgX = drawable.intrinsicWidth.toFloat()
|
||||
val imgY = drawable.intrinsicHeight.toFloat()
|
||||
//Log.d("MySIV", "ix: $imgX, iy: $imgY, w: $width, h: $height")
|
||||
//原图大小
|
||||
val tempSrc = rectFTake(0f, 0f, imgX, imgY)
|
||||
layoutParams.height = (imgY / imgX * width + 0.5).toInt()
|
||||
invalidate()
|
||||
//控件大小
|
||||
val tempDst = rectFTake(0f, 0f, width.toFloat(), height.toFloat())
|
||||
//计算fit center矩阵
|
||||
matrix.setRectToRect(tempSrc, tempDst, Matrix.ScaleToFit.CENTER)
|
||||
//释放临时对象
|
||||
rectFGiven(tempDst)
|
||||
rectFGiven(tempSrc)
|
||||
if(matrix != null && drawable != null && layoutParams != null){
|
||||
matrix.reset()
|
||||
val imgX = drawable.intrinsicWidth.toFloat()
|
||||
val imgY = drawable.intrinsicHeight.toFloat()
|
||||
//Log.d("MySIV", "ix: $imgX, iy: $imgY, w: $width, h: $height")
|
||||
//原图大小
|
||||
val tempSrc = rectFTake(0f, 0f, imgX, imgY)
|
||||
layoutParams.height = (imgY / imgX * width + 0.5).toInt()
|
||||
invalidate()
|
||||
//控件大小
|
||||
val tempDst = rectFTake(0f, 0f, width.toFloat(), height.toFloat())
|
||||
//计算fit center矩阵
|
||||
matrix.setRectToRect(tempSrc, tempDst, Matrix.ScaleToFit.CENTER)
|
||||
//释放临时对象
|
||||
rectFGiven(tempDst)
|
||||
rectFGiven(tempSrc)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -210,11 +212,11 @@ class ScaleImageView : ImageView {
|
||||
* @return 返回当前的mask对象副本,如果当前没有设置mask则返回null
|
||||
|
||||
val mask: RectF?
|
||||
get() = if (mMask != null) {
|
||||
RectF(mMask)
|
||||
} else {
|
||||
null
|
||||
}*/
|
||||
get() = if (mMask != null) {
|
||||
RectF(mMask)
|
||||
} else {
|
||||
null
|
||||
}*/
|
||||
|
||||
/**
|
||||
* 与ViewPager结合的时候使用
|
||||
@@ -262,29 +264,29 @@ class ScaleImageView : ImageView {
|
||||
* 调用此方法会停止正在进行中的手势以及手势动画.
|
||||
* 当duration为0时,outerMatrix值会被立即设置而不会启动动画.
|
||||
*
|
||||
@param endMatrix 动画目标矩阵
|
||||
@param duration 动画持续时间
|
||||
@param endMatrix 动画目标矩阵
|
||||
@param duration 动画持续时间
|
||||
*
|
||||
@see .getOuterMatrix
|
||||
@see .getOuterMatrix
|
||||
|
||||
fun outerMatrixTo(endMatrix: Matrix?, duration: Long) {
|
||||
if (endMatrix == null) {
|
||||
return
|
||||
}
|
||||
//将手势设置为PINCH_MODE_FREE将停止后续手势的触发
|
||||
pinchMode = PINCH_MODE_FREE
|
||||
//停止所有正在进行的动画
|
||||
cancelAllAnimator()
|
||||
//如果时间不合法立即执行结果
|
||||
if (duration <= 0) {
|
||||
mOuterMatrix.set(endMatrix)
|
||||
dispatchOuterMatrixChanged()
|
||||
invalidate()
|
||||
} else {
|
||||
//创建矩阵变化动画
|
||||
mScaleAnimator = ScaleAnimator(mOuterMatrix, endMatrix, duration)
|
||||
mScaleAnimator!!.start()
|
||||
}
|
||||
if (endMatrix == null) {
|
||||
return
|
||||
}
|
||||
//将手势设置为PINCH_MODE_FREE将停止后续手势的触发
|
||||
pinchMode = PINCH_MODE_FREE
|
||||
//停止所有正在进行的动画
|
||||
cancelAllAnimator()
|
||||
//如果时间不合法立即执行结果
|
||||
if (duration <= 0) {
|
||||
mOuterMatrix.set(endMatrix)
|
||||
dispatchOuterMatrixChanged()
|
||||
invalidate()
|
||||
} else {
|
||||
//创建矩阵变化动画
|
||||
mScaleAnimator = ScaleAnimator(mOuterMatrix, endMatrix, duration)
|
||||
mScaleAnimator!!.start()
|
||||
}
|
||||
}*/
|
||||
|
||||
/**
|
||||
@@ -294,32 +296,32 @@ class ScaleImageView : ImageView {
|
||||
* 当前mask为null时,则不执行动画立即设置为目标mask.
|
||||
* 当duration为0时,立即将当前mask设置为目标mask,不会执行动画.
|
||||
*
|
||||
@param mask 动画目标mask
|
||||
@param duration 动画持续时间
|
||||
@param mask 动画目标mask
|
||||
@param duration 动画持续时间
|
||||
*
|
||||
@see .getMask
|
||||
@see .getMask
|
||||
|
||||
fun zoomMaskTo(mask: RectF?, duration: Long) {
|
||||
if (mask == null) {
|
||||
return
|
||||
}
|
||||
//停止mask动画
|
||||
if (mMaskAnimator != null) {
|
||||
mMaskAnimator!!.cancel()
|
||||
mMaskAnimator = null
|
||||
}
|
||||
//如果duration为0或者之前没有设置过mask,不执行动画,立即设置
|
||||
if (duration <= 0 || mMask == null) {
|
||||
if (mMask == null) {
|
||||
mMask = RectF()
|
||||
}
|
||||
mMask!!.set(mask)
|
||||
invalidate()
|
||||
} else {
|
||||
//执行mask动画
|
||||
mMaskAnimator = MaskAnimator(mMask!!, mask, duration)
|
||||
mMaskAnimator!!.start()
|
||||
}
|
||||
if (mask == null) {
|
||||
return
|
||||
}
|
||||
//停止mask动画
|
||||
if (mMaskAnimator != null) {
|
||||
mMaskAnimator!!.cancel()
|
||||
mMaskAnimator = null
|
||||
}
|
||||
//如果duration为0或者之前没有设置过mask,不执行动画,立即设置
|
||||
if (duration <= 0 || mMask == null) {
|
||||
if (mMask == null) {
|
||||
mMask = RectF()
|
||||
}
|
||||
mMask!!.set(mask)
|
||||
invalidate()
|
||||
} else {
|
||||
//执行mask动画
|
||||
mMaskAnimator = MaskAnimator(mMask!!, mask, duration)
|
||||
mMaskAnimator!!.start()
|
||||
}
|
||||
}*/
|
||||
|
||||
/**
|
||||
@@ -329,24 +331,24 @@ class ScaleImageView : ImageView {
|
||||
* 但不清空drawable,以及事件绑定相关数据.
|
||||
|
||||
fun reset() {
|
||||
//重置位置到fit
|
||||
mOuterMatrix.reset()
|
||||
dispatchOuterMatrixChanged()
|
||||
//清空mask
|
||||
mMask = null
|
||||
//停止所有手势
|
||||
pinchMode = PINCH_MODE_FREE
|
||||
mLastMovePoint[0f] = 0f
|
||||
mScaleCenter[0f] = 0f
|
||||
mScaleBase = 0f
|
||||
//停止所有动画
|
||||
if (mMaskAnimator != null) {
|
||||
mMaskAnimator!!.cancel()
|
||||
mMaskAnimator = null
|
||||
}
|
||||
cancelAllAnimator()
|
||||
//重绘
|
||||
invalidate()
|
||||
//重置位置到fit
|
||||
mOuterMatrix.reset()
|
||||
dispatchOuterMatrixChanged()
|
||||
//清空mask
|
||||
mMask = null
|
||||
//停止所有手势
|
||||
pinchMode = PINCH_MODE_FREE
|
||||
mLastMovePoint[0f] = 0f
|
||||
mScaleCenter[0f] = 0f
|
||||
mScaleBase = 0f
|
||||
//停止所有动画
|
||||
if (mMaskAnimator != null) {
|
||||
mMaskAnimator!!.cancel()
|
||||
mMaskAnimator = null
|
||||
}
|
||||
cancelAllAnimator()
|
||||
//重绘
|
||||
invalidate()
|
||||
}*/
|
||||
////////////////////////////////对外广播事件////////////////////////////////
|
||||
/**
|
||||
@@ -399,64 +401,64 @@ class ScaleImageView : ImageView {
|
||||
/**
|
||||
* 添加外部矩阵变化监听
|
||||
*
|
||||
@param listener
|
||||
@param listener
|
||||
|
||||
fun addOuterMatrixChangedListener(listener: OuterMatrixChangedListener?) {
|
||||
if (listener == null) {
|
||||
return
|
||||
}
|
||||
//如果监听列表没有被修改锁定直接将监听添加到监听列表
|
||||
if (mDispatchOuterMatrixChangedLock == 0) {
|
||||
if (mOuterMatrixChangedListeners == null) {
|
||||
mOuterMatrixChangedListeners =
|
||||
ArrayList()
|
||||
}
|
||||
mOuterMatrixChangedListeners!!.add(listener)
|
||||
} else {
|
||||
//如果监听列表修改被锁定,那么尝试在监听列表副本上添加
|
||||
//监听列表副本将会在锁定被解除时替换到监听列表里
|
||||
if (mOuterMatrixChangedListenersCopy == null) {
|
||||
mOuterMatrixChangedListenersCopy = if (mOuterMatrixChangedListeners != null) {
|
||||
ArrayList(
|
||||
mOuterMatrixChangedListeners!!
|
||||
)
|
||||
} else {
|
||||
ArrayList()
|
||||
}
|
||||
}
|
||||
mOuterMatrixChangedListenersCopy!!.add(listener)
|
||||
}
|
||||
if (listener == null) {
|
||||
return
|
||||
}
|
||||
//如果监听列表没有被修改锁定直接将监听添加到监听列表
|
||||
if (mDispatchOuterMatrixChangedLock == 0) {
|
||||
if (mOuterMatrixChangedListeners == null) {
|
||||
mOuterMatrixChangedListeners =
|
||||
ArrayList()
|
||||
}
|
||||
mOuterMatrixChangedListeners!!.add(listener)
|
||||
} else {
|
||||
//如果监听列表修改被锁定,那么尝试在监听列表副本上添加
|
||||
//监听列表副本将会在锁定被解除时替换到监听列表里
|
||||
if (mOuterMatrixChangedListenersCopy == null) {
|
||||
mOuterMatrixChangedListenersCopy = if (mOuterMatrixChangedListeners != null) {
|
||||
ArrayList(
|
||||
mOuterMatrixChangedListeners!!
|
||||
)
|
||||
} else {
|
||||
ArrayList()
|
||||
}
|
||||
}
|
||||
mOuterMatrixChangedListenersCopy!!.add(listener)
|
||||
}
|
||||
}*/
|
||||
|
||||
/**
|
||||
* 删除外部矩阵变化监听
|
||||
*
|
||||
@param listener
|
||||
@param listener
|
||||
|
||||
fun removeOuterMatrixChangedListener(listener: OuterMatrixChangedListener?) {
|
||||
if (listener == null) {
|
||||
return
|
||||
}
|
||||
//如果监听列表没有被修改锁定直接在监听列表数据结构上修改
|
||||
if (mDispatchOuterMatrixChangedLock == 0) {
|
||||
if (mOuterMatrixChangedListeners != null) {
|
||||
mOuterMatrixChangedListeners!!.remove(listener)
|
||||
}
|
||||
} else {
|
||||
//如果监听列表被修改锁定,那么就在其副本上修改
|
||||
//其副本将会在锁定解除时替换回监听列表
|
||||
if (mOuterMatrixChangedListenersCopy == null) {
|
||||
if (mOuterMatrixChangedListeners != null) {
|
||||
mOuterMatrixChangedListenersCopy =
|
||||
ArrayList(
|
||||
mOuterMatrixChangedListeners!!
|
||||
)
|
||||
}
|
||||
}
|
||||
if (mOuterMatrixChangedListenersCopy != null) {
|
||||
mOuterMatrixChangedListenersCopy!!.remove(listener)
|
||||
}
|
||||
}
|
||||
if (listener == null) {
|
||||
return
|
||||
}
|
||||
//如果监听列表没有被修改锁定直接在监听列表数据结构上修改
|
||||
if (mDispatchOuterMatrixChangedLock == 0) {
|
||||
if (mOuterMatrixChangedListeners != null) {
|
||||
mOuterMatrixChangedListeners!!.remove(listener)
|
||||
}
|
||||
} else {
|
||||
//如果监听列表被修改锁定,那么就在其副本上修改
|
||||
//其副本将会在锁定解除时替换回监听列表
|
||||
if (mOuterMatrixChangedListenersCopy == null) {
|
||||
if (mOuterMatrixChangedListeners != null) {
|
||||
mOuterMatrixChangedListenersCopy =
|
||||
ArrayList(
|
||||
mOuterMatrixChangedListeners!!
|
||||
)
|
||||
}
|
||||
}
|
||||
if (mOuterMatrixChangedListenersCopy != null) {
|
||||
mOuterMatrixChangedListenersCopy!!.remove(listener)
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
/**
|
||||
@@ -583,10 +585,10 @@ class ScaleImageView : ImageView {
|
||||
* 记录两个手指的中点,作为和mScaleCenter绑定的点.
|
||||
* 这个绑定可以保证mScaleCenter无论如何都会跟随这个中点.
|
||||
*
|
||||
@see .mScaleCenter
|
||||
@see .mScaleCenter
|
||||
*
|
||||
@see .scale
|
||||
@see .scaleEnd
|
||||
@see .scale
|
||||
@see .scaleEnd
|
||||
*/
|
||||
private val mLastMovePoint = PointF()
|
||||
|
||||
@@ -674,7 +676,6 @@ class ScaleImageView : ImageView {
|
||||
}
|
||||
|
||||
var v :WeakReference<ViewMangaActivity>? = null
|
||||
var pm:PagesManager? = null
|
||||
override fun onSingleTapConfirmed(event: MotionEvent): Boolean {
|
||||
if(v == null) {
|
||||
v = ViewMangaActivity.va
|
||||
@@ -1234,8 +1235,8 @@ class ScaleImageView : ImageView {
|
||||
*
|
||||
* 参数单位为 像素/帧
|
||||
*
|
||||
@param vectorX 速度向量
|
||||
@param vectorY 速度向量
|
||||
@param vectorX 速度向量
|
||||
@param vectorY 速度向量
|
||||
*/
|
||||
init {
|
||||
setFloatValues(0f, 1f)
|
||||
@@ -1296,8 +1297,8 @@ class ScaleImageView : ImageView {
|
||||
*
|
||||
* 从一个矩阵变换到另外一个矩阵
|
||||
*
|
||||
@param start 开始矩阵
|
||||
@param end 结束矩阵
|
||||
@param start 开始矩阵
|
||||
@param end 结束矩阵
|
||||
*/
|
||||
init {
|
||||
setFloatValues(0f, 1f)
|
||||
@@ -1387,7 +1388,7 @@ class ScaleImageView : ImageView {
|
||||
/**
|
||||
* 创建一个对象池
|
||||
*
|
||||
@param size 对象池最大容量
|
||||
@param size 对象池最大容量
|
||||
*/
|
||||
init {
|
||||
mQueue = LinkedList()
|
||||
@@ -1485,11 +1486,11 @@ class ScaleImageView : ImageView {
|
||||
* 获取某个矩形的副本
|
||||
|
||||
fun rectFTake(rectF: RectF?): RectF {
|
||||
val result = mRectFPool.take()!!
|
||||
if (rectF != null) {
|
||||
result.set(rectF)
|
||||
}
|
||||
return result
|
||||
val result = mRectFPool.take()!!
|
||||
if (rectF != null) {
|
||||
result.set(rectF)
|
||||
}
|
||||
return result
|
||||
}*/
|
||||
|
||||
/**
|
||||
@@ -1630,5 +1631,7 @@ class ScaleImageView : ImageView {
|
||||
* @see .getPinchMode
|
||||
*/
|
||||
const val PINCH_MODE_SCALE = 2
|
||||
|
||||
var pm:PagesManager? = null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package top.fumiama.copymanga.views
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import androidx.core.widget.NestedScrollView
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
|
||||
class ScrollRefreshView : NestedScrollView {
|
||||
constructor(context: Context) : super(context)
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(
|
||||
context,
|
||||
attrs,
|
||||
defStyle
|
||||
)
|
||||
|
||||
var swipeRefreshLayout: SwipeRefreshLayout? = null
|
||||
|
||||
override fun onScrollChanged(l: Int, t: Int, oldl: Int, oldt: Int) {
|
||||
super.onScrollChanged(l, t, oldl, oldt)
|
||||
//Log.d("MyOSV", "$l, $t, $oldl, $oldt")
|
||||
swipeRefreshLayout?.isEnabled = t == 0
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package top.fumiama.copymanga.web
|
||||
|
||||
import android.util.Log
|
||||
import android.webkit.JavascriptInterface
|
||||
import top.fumiama.copymanga.R
|
||||
import top.fumiama.copymanga.activity.MainActivity.Companion.mh
|
||||
import top.fumiama.copymanga.activity.MainActivity.Companion.wm
|
||||
import top.fumiama.copymanga.activity.ViewMangaActivity
|
||||
|
||||
class JS {
|
||||
@JavascriptInterface
|
||||
fun loadComic(url: String){
|
||||
val u = when {
|
||||
url.contains("/details/comic/") -> "${wm?.get()?.getString(R.string.web_comic_detail_pc)}${url.substringAfter("comic")}"
|
||||
url.contains("/comicContent/") -> "${wm?.get()?.getString(R.string.web_comic_detail_pc)}/${url.substringAfter("comicContent/").substringBefore("/")}/chapter/${url.substringAfterLast("/")}"
|
||||
else -> ""
|
||||
}
|
||||
Log.d("MyJS", "Load comic: $u")
|
||||
Thread{mh?.obtainMessage(1, u)?.sendToTarget()}.start()
|
||||
}
|
||||
@JavascriptInterface
|
||||
fun hideFab(){
|
||||
Thread{mh?.sendEmptyMessage(5)}.start()
|
||||
}
|
||||
@JavascriptInterface
|
||||
fun enterProfile(){
|
||||
Thread{mh?.sendEmptyMessage(6)}.start()
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package top.fumiama.copymanga.web
|
||||
|
||||
import android.util.Log
|
||||
import android.webkit.JavascriptInterface
|
||||
import top.fumiama.copymanga.activity.DlActivity
|
||||
import top.fumiama.copymanga.activity.MainActivity.Companion.mh
|
||||
|
||||
class JSHidden {
|
||||
@JavascriptInterface
|
||||
fun loadChapter(listString: String){
|
||||
Thread{mh?.obtainMessage(2, listString)?.sendToTarget()}.start()
|
||||
}
|
||||
@JavascriptInterface
|
||||
fun setTitle(title:String){
|
||||
Log.d("MyJSH", "Set title: $title")
|
||||
DlActivity.comicName = title
|
||||
}
|
||||
@JavascriptInterface
|
||||
fun setFab(content: String){
|
||||
Thread{mh?.obtainMessage(4, content)?.sendToTarget()}.start()
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package top.fumiama.copymanga.web
|
||||
|
||||
import android.webkit.JsPromptResult
|
||||
import android.webkit.JsResult
|
||||
import android.webkit.WebChromeClient
|
||||
import android.webkit.WebView
|
||||
import top.fumiama.copymanga.activity.MainActivity.Companion.mh
|
||||
|
||||
class WebChromeClient:WebChromeClient() {
|
||||
override fun onProgressChanged(view: WebView?, newProgress: Int) {
|
||||
super.onProgressChanged(view, newProgress)
|
||||
//Log.d("MyWCC", "W progress: $newProgress")
|
||||
Thread{mh?.obtainMessage(3, newProgress, 0)?.sendToTarget()}.start()
|
||||
}
|
||||
|
||||
override fun onJsAlert(
|
||||
view: WebView?,
|
||||
url: String?,
|
||||
message: String?,
|
||||
result: JsResult?
|
||||
): Boolean {
|
||||
result?.confirm()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onJsPrompt(
|
||||
view: WebView?,
|
||||
url: String?,
|
||||
message: String?,
|
||||
defaultValue: String?,
|
||||
result: JsPromptResult?
|
||||
): Boolean {
|
||||
result?.confirm()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onJsConfirm(
|
||||
view: WebView?,
|
||||
url: String?,
|
||||
message: String?,
|
||||
result: JsResult?
|
||||
): Boolean {
|
||||
result?.confirm()
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package top.fumiama.copymanga.web
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.util.Log
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
import android.widget.Toast
|
||||
import top.fumiama.copymanga.R
|
||||
|
||||
class WebViewClient(private val context: Context, jsFileName: String):WebViewClient() {
|
||||
private val js = context.assets.open(jsFileName).readBytes().decodeToString()
|
||||
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
|
||||
super.onPageStarted(view, url, favicon)
|
||||
Log.d("MyWC", "Load URL: $url")
|
||||
url?.let {
|
||||
if(!it.startsWith(context.getString(R.string.web_home)) && !it.startsWith(context.getString(R.string.web_home_www))){
|
||||
view?.goBack()
|
||||
Toast.makeText(context, R.string.blocked_ad, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPageFinished(view: WebView?, url: String?) {
|
||||
super.onPageFinished(view, url)
|
||||
url?.let {
|
||||
view?.loadUrl(js)
|
||||
}
|
||||
}
|
||||
}
|
||||
8
app/src/main/res/anim/slide_in_right.xml
Normal file
8
app/src/main/res/anim/slide_in_right.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<translate
|
||||
android:duration="@android:integer/config_mediumAnimTime"
|
||||
android:fromXDelta="100%"
|
||||
android:interpolator="@android:anim/accelerate_interpolator"
|
||||
android:toXDelta="0" />
|
||||
</set>
|
||||
8
app/src/main/res/anim/slide_in_right_exit.xml
Normal file
8
app/src/main/res/anim/slide_in_right_exit.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<translate
|
||||
android:duration="@android:integer/config_mediumAnimTime"
|
||||
android:fromXDelta="0"
|
||||
android:interpolator="@android:anim/accelerate_interpolator"
|
||||
android:toXDelta="100%" />
|
||||
</set>
|
||||
8
app/src/main/res/anim/slide_out_left.xml
Normal file
8
app/src/main/res/anim/slide_out_left.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<translate
|
||||
android:duration="@android:integer/config_mediumAnimTime"
|
||||
android:fromXDelta="0"
|
||||
android:interpolator="@android:anim/accelerate_interpolator"
|
||||
android:toXDelta="-100%"/>
|
||||
</set>
|
||||
8
app/src/main/res/anim/slide_out_left_exit.xml
Normal file
8
app/src/main/res/anim/slide_out_left_exit.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<translate
|
||||
android:duration="@android:integer/config_mediumAnimTime"
|
||||
android:fromXDelta="-100%"
|
||||
android:interpolator="@android:anim/accelerate_interpolator"
|
||||
android:toXDelta="0"/>
|
||||
</set>
|
||||
33
app/src/main/res/drawable-anydpi/bg_rnd_green.xml
Normal file
33
app/src/main/res/drawable-anydpi/bg_rnd_green.xml
Normal file
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item android:state_pressed="true">
|
||||
<shape android:shape="rectangle" >
|
||||
<!-- 填充的颜色 -->
|
||||
<solid android:color="@color/colorPrimaryDark" />
|
||||
<!-- 设置按钮的四个角为弧形 -->
|
||||
<!-- android:radius 弧形的半径 -->
|
||||
<corners android:radius="16dip" />
|
||||
<!-- padding:Button里面的文字与Button边界的间隔 -->
|
||||
<padding android:bottom="1dp" android:left="1dp" android:right="1dp" android:top="1dp" />
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
<item android:state_pressed="false">
|
||||
<shape android:shape="rectangle" >
|
||||
<!-- 填充的颜色 -->
|
||||
<solid android:color="@color/colorGreen" />
|
||||
<!-- 设置按钮的四个角为弧形 -->
|
||||
<!-- android:radius 弧形的半径 -->
|
||||
<corners android:radius="16dip" />
|
||||
<!-- stroke 设置边框显示 -->
|
||||
<stroke
|
||||
android:dashGap="0dp"
|
||||
android:width="1dp"
|
||||
android:color="@color/colorAccent" />
|
||||
<!-- padding:Button里面的文字与Button边界的间隔 -->
|
||||
<padding android:bottom="1dp" android:left="1dp" android:right="1dp" android:top="1dp" />
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
</selector>
|
||||
11
app/src/main/res/drawable-anydpi/buttonshapewhitebg.xml
Normal file
11
app/src/main/res/drawable-anydpi/buttonshapewhitebg.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<corners android:radius="8dp" />
|
||||
<solid android:color="@android:color/transparent"/>
|
||||
<stroke android:color="#ffffff"
|
||||
android:width="2dp"/>
|
||||
</shape>
|
||||
</item>
|
||||
</selector>
|
||||
9
app/src/main/res/drawable-anydpi/ic_anchor_down.xml
Normal file
9
app/src/main/res/drawable-anydpi/ic_anchor_down.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="?attr/colorOnSurface"
|
||||
android:pathData="M890 331c-13-12-33-12-45 0L517 662 185 333c-13-12-33-12-45 0-12 13-12 33 0 45l353 350c1 1 1 1 2 1 0 0 0 0 0 0a32 32 0 0 0 23 9c8 0 16-3 23-9l350-353c12-13 12-33-0-45z" />
|
||||
</vector>
|
||||
@@ -5,6 +5,6 @@
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:fillColor="?attr/colorOnSurface"
|
||||
android:pathData="M896 864a32 32 0 0 1 0 64H128a32 32 0 0 1 0-64z m-60-734l15 15c46 46 46 120 0 166L419 743a160 160 0 0 1-78 43l-152 34c-24 5-45-17-38-40l43-147a160 160 0 0 1 40-68l435-435c46-46 120-46 166 0zM636 254L280 611a96 96 0 0 0-24 41l-28 95 99-22a96 96 0 0 0 47-26L727 345l-91-91z m79-79l-33 33 91 91 33-33a53 53 0 0 0 0-75l-15-15a53 53 0 0 0-75 0z"/>
|
||||
</vector>
|
||||
10
app/src/main/res/drawable-anydpi/ic_dere.xml
Normal file
10
app/src/main/res/drawable-anydpi/ic_dere.xml
Normal file
File diff suppressed because one or more lines are too long
9
app/src/main/res/drawable-anydpi/ic_email_white_24dp.xml
Normal file
9
app/src/main/res/drawable-anydpi/ic_email_white_24dp.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="?attr/colorOnSurface"
|
||||
android:pathData="M20,4L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM20,8l-8,5 -8,-5L4,6l8,5 8,-5v2z"/>
|
||||
</vector>
|
||||
@@ -5,7 +5,7 @@
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="@color/colorPrimary"
|
||||
android:fillColor="#FFCC7F"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
|
||||
10
app/src/main/res/drawable-anydpi/ic_line_more.xml
Normal file
10
app/src/main/res/drawable-anydpi/ic_line_more.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="?attr/colorOnSurface"
|
||||
android:pathData="M299 587a75 75 0 1 1 0-149 75 75 0 0 1 0 149z m213 0a75 75 0 1 1 0-149 75 75 0 0 1 0 149z m213 0a75 75 0 1 1 0-149 75 75 0 0 1 0 149z"/>
|
||||
</vector>
|
||||
10
app/src/main/res/drawable-anydpi/ic_list.xml
Normal file
10
app/src/main/res/drawable-anydpi/ic_list.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="?attr/colorOnSurface"
|
||||
android:pathData="M821 256a32 32 0 0 1 64 0v565c0 65-53 117-117 117H256c-65 0-117-53-117-117V203c0-65 53-117 117-117h597a32 32 0 0 1 0 64H256a53 53 0 0 0-53 53v619a53 53 0 0 0 53 53h512a53 53 0 0 0 53-53V256zM341 437a32 32 0 0 1 0-64h341a32 32 0 0 1 0 64H341z m0 171a32 32 0 0 1 0-64h213a32 32 0 0 1 0 64H341z"/>
|
||||
</vector>
|
||||
9
app/src/main/res/drawable-anydpi/ic_locate.xml
Normal file
9
app/src/main/res/drawable-anydpi/ic_locate.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="?attr/colorOnSurface"
|
||||
android:pathData="M648 850a32 32 0 1 1-41-49C758 677 832 566 832 471 832 293 689 149 512 149c-177 0-320 144-320 322 0 115 108 253 329 409a32 32 0 0 1-37 52C248 765 128 613 128 471 128 258 300 85 512 85s384 173 384 386c0 118-84 244-248 379zM512 619c-82 0-149-67-149-149s67-149 149-149 149 67 149 149-67 149-149 149z m0-64a85 85 0 1 0 0-171 85 85 0 0 0 0 171z" />
|
||||
</vector>
|
||||
9
app/src/main/res/drawable-anydpi/ic_lock_white_24dp.xml
Normal file
9
app/src/main/res/drawable-anydpi/ic_lock_white_24dp.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="?attr/colorOnSurface"
|
||||
android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM15.1,8L8.9,8L8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2z"/>
|
||||
</vector>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user