diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..603b140 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..681f41a --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,116 @@ + + + + + + + +
+ + + + xmlns:android + + ^$ + + + +
+
+ + + + xmlns:.* + + ^$ + + + BY_NAME + +
+
+ + + + .*:id + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + .*:name + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + name + + ^$ + + + +
+
+ + + + style + + ^$ + + + +
+
+ + + + .* + + ^$ + + + BY_NAME + +
+
+ + + + .* + + http://schemas.android.com/apk/res/android + + + ANDROID_ATTRIBUTE_ORDER + +
+
+ + + + .* + + .* + + + BY_NAME + +
+
+
+
+
+
\ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..61a9130 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..41871c2 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,22 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..1e2d92c --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..19aa6a5 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..7f68460 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..b63d04a --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,41 @@ +apply plugin: 'com.android.application' +apply plugin: 'org.greenrobot.greendao' + +android { + compileSdkVersion 29 + buildToolsVersion "29.0.2" + defaultConfig { + applicationId "com.tdkankan" + minSdkVersion 21 + targetSdkVersion 29 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } +} + +greendao { + schemaVersion 1 //当前数据库版本 + daoPackage 'com.tdkankan.greendao.green' + targetGenDir 'src/main/java' +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation 'androidx.appcompat:appcompat:1.2.0' + implementation 'androidx.constraintlayout:constraintlayout:2.0.4' + implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test.ext:junit:1.1.2' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' + implementation 'org.jsoup:jsoup:1.13.1' + implementation 'com.github.HanHuoBin:BaseDialog:1.2.0' + implementation 'com.android.volley:volley:1.1.1' + implementation 'org.greenrobot:greendao:3.3.0' // add library +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/app/src/androidTest/java/com/tdkankan/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/tdkankan/ExampleInstrumentedTest.java new file mode 100644 index 0000000..534b20c --- /dev/null +++ b/app/src/androidTest/java/com/tdkankan/ExampleInstrumentedTest.java @@ -0,0 +1,27 @@ +package com.tdkankan; + +import android.content.Context; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + + assertEquals("com.tdkankan", appContext.getPackageName()); + } +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..f281bdd --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/ic_launcher_bookcity-web.png b/app/src/main/ic_launcher_bookcity-web.png new file mode 100644 index 0000000..e63ef71 Binary files /dev/null and b/app/src/main/ic_launcher_bookcity-web.png differ diff --git a/app/src/main/ic_launcher_bookcity_select-web.png b/app/src/main/ic_launcher_bookcity_select-web.png new file mode 100644 index 0000000..8a68e6a Binary files /dev/null and b/app/src/main/ic_launcher_bookcity_select-web.png differ diff --git a/app/src/main/ic_launcher_setting-web.png b/app/src/main/ic_launcher_setting-web.png new file mode 100644 index 0000000..19e806f Binary files /dev/null and b/app/src/main/ic_launcher_setting-web.png differ diff --git a/app/src/main/ic_launcher_setting_select-web.png b/app/src/main/ic_launcher_setting_select-web.png new file mode 100644 index 0000000..e372c7b Binary files /dev/null and b/app/src/main/ic_launcher_setting_select-web.png differ diff --git a/app/src/main/ic_launcher_shujia-web.png b/app/src/main/ic_launcher_shujia-web.png new file mode 100644 index 0000000..02e4b41 Binary files /dev/null and b/app/src/main/ic_launcher_shujia-web.png differ diff --git a/app/src/main/ic_launcher_shujia_select-web.png b/app/src/main/ic_launcher_shujia_select-web.png new file mode 100644 index 0000000..61e0321 Binary files /dev/null and b/app/src/main/ic_launcher_shujia_select-web.png differ diff --git a/app/src/main/java/com/tdkankan/Adapter/BookListAdapter2.java b/app/src/main/java/com/tdkankan/Adapter/BookListAdapter2.java new file mode 100644 index 0000000..9110aed --- /dev/null +++ b/app/src/main/java/com/tdkankan/Adapter/BookListAdapter2.java @@ -0,0 +1,175 @@ +package com.tdkankan.Adapter; + +import android.app.Activity; + +import android.content.Intent; +import android.content.res.Resources; +import android.graphics.Bitmap; + +import android.graphics.BitmapFactory; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; + + +import com.tdkankan.Cache.BookInfoCache; +import com.tdkankan.Data.GlobalConfig; +import com.tdkankan.ViewUitl.BookItem; +import com.tdkankan.R; +import com.tdkankan.UI.BookInfoDetailActivity; + +import java.util.ArrayList; +import java.util.HashMap; + + +/** + * @author ZQZESS + * @date 12/9/2020. + * @file BookListAdapter2 + * GitHub:https://github.com/zqzess + * 不会停止运行的app不是好app w(゚Д゚)w + */ +public class BookListAdapter2 extends BaseAdapter { + private ArrayList> list; + private int sumCount; + Activity activity; + Bitmap bitmap; + Bitmap bitmap2; +// BookInfoCache cache=new BookInfoCache(); + + public BookListAdapter2(ArrayList> list, Activity activity) { + super(); + this.list = list; + this.activity = activity; + } + + @Override + public int getCount() { + int count = list.size(); + if (count % 2 == 0) { + sumCount = count / 2; // 如果是双数直接减半 + } else { + sumCount = (int) Math.floor((double) count / 2) + 1; + } + + return sumCount; + } + + @Override + public Object getItem(int position) { + return list.get(position); + } + + @Override + public long getItemId(int position) { + return 0; + } + + @Override + public View getView(final int position, View convertView, ViewGroup parent) { +// int count=position; + final BookListAdapter2.ViewHolder holder; + LayoutInflater inflater = activity.getLayoutInflater(); + + if (convertView == null) { + convertView = inflater.inflate(R.layout.listview_bookitem, null); + holder = new BookListAdapter2.ViewHolder(); + holder.bookItem1 = (BookItem) convertView.findViewById(R.id.bookItem1); + holder.bookItem2 = (BookItem) convertView.findViewById(R.id.bookItem2); + convertView.setTag(holder); + } else { + holder = (BookListAdapter2.ViewHolder) convertView.getTag(); + } +// HashMap map = list.get(count); + //获取缓存的图片 +// final String picname = list.get(position * 2).get("picname"); +// final String picname2 = list.get(position * 2 + 1).get("picname"); + String piclink=list.get(position * 2).get("piclink"); + piclink= GlobalConfig.PicLinkCheck(piclink); + String piclink2 = list.get(position * 2 + 1).get("piclink"); + piclink2=GlobalConfig.PicLinkCheck(piclink2); + + + /* + *从本地读取图片 + */ + /*new Thread(new Runnable() { + @Override + public void run() { + bitmap = BitmapUtils.readBitmapFromFileDescriptor("/data/data/com.tdkankan/temp/images/" + finapicname + ".jpg", 50, 80); + } + }).start(); + new Thread(new Runnable() { + @Override + public void run() { + bitmap2 = BitmapUtils.readBitmapFromFileDescriptor("/data/data/com.tdkankan/temp/images/" + finapicname2 + ".jpg", 50, 80); + } + }).start();*/ + + //从内存读取 +// bitmap= BookInfoCache.loadImage(picname,piclink); +// bitmap2= BookInfoCache.loadImage(picname2,piclink2); + + + holder.bookItem1.setName(list.get(position * 2).get("name")); + holder.bookItem1.setAuthor(list.get(position * 2).get("author")); + holder.bookItem1.setInfo(list.get(position * 2).get("info")); + holder.bookItem1.setPic(piclink,GlobalConfig.bitmapnull); +// holder.img.setText(list.get(count).get("name")); +// count++; + if (position * 2 + 1 == list.size()) { + holder.bookItem2.setVisibility(View.INVISIBLE); + holder.bookItem2.setVisibility(View.INVISIBLE); + holder.bookItem2.setVisibility(View.INVISIBLE); + holder.bookItem2.setVisibility(View.INVISIBLE); + } else { + holder.bookItem2.setVisibility(View.VISIBLE); + holder.bookItem2.setVisibility(View.VISIBLE); + holder.bookItem2.setVisibility(View.VISIBLE); + holder.bookItem2.setVisibility(View.VISIBLE); + holder.bookItem2.setName(list.get(position * 2 + 1).get("name")); + holder.bookItem2.setAuthor(list.get(position * 2 + 1).get("author")); + holder.bookItem2.setInfo(list.get(position * 2 + 1).get("info")); + holder.bookItem2.setPic(piclink2,getBitmapFromRes(activity,R.drawable.nonepic)); + } + + holder.bookItem1.setMyItemClickedListener(new MyOnEvenClick(position*2)); + holder.bookItem2.setMyItemClickedListener(new MyOnEvenClick(position*2+1)); + return convertView; + } + + private Bitmap getBitmapFromRes(Activity activity,int resId) { + Resources res = activity.getResources(); + return BitmapFactory.decodeResource(res, resId); + } + private class ViewHolder { + BookItem bookItem1; + BookItem bookItem2; + } + + private class MyOnEvenClick implements BookItem.MyItemClicked { + int pos = 0; + + public MyOnEvenClick(int position) { + this.pos = position; + } + + @Override + public void myItemClicked() { + Log.d("clickposition",pos+""); + Intent intent=new Intent(activity, BookInfoDetailActivity.class); + intent.putExtra("name",list.get(pos).get("name")); + intent.putExtra("author",list.get(pos).get("author")); + intent.putExtra("info",list.get(pos).get("info")); + intent.putExtra("picname",list.get(pos).get("picname")); + intent.putExtra("link",list.get(pos).get("link")); + intent.putExtra("piclink",list.get(pos).get("piclink")); + activity.startActivity(intent); + + } + } + + +} diff --git a/app/src/main/java/com/tdkankan/Adapter/BookShelfAdapter.java b/app/src/main/java/com/tdkankan/Adapter/BookShelfAdapter.java new file mode 100644 index 0000000..f93685c --- /dev/null +++ b/app/src/main/java/com/tdkankan/Adapter/BookShelfAdapter.java @@ -0,0 +1,154 @@ +package com.tdkankan.Adapter; + +import android.app.Activity; +import android.content.Intent; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; + +import com.tdkankan.Cache.ImageCacheManager; +import com.tdkankan.Data.GlobalConfig; +import com.tdkankan.R; +import com.tdkankan.UI.ReadingActivity; +import com.tdkankan.ViewUitl.BookItemTypeThree; +import com.tdkankan.greendao.model.Bookinfodb; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * @author ZQZESS + * @date 2/19/2021. + * @file BookShelfAdapter + * GitHub:https://github.com/zqzess + * 不会停止运行的app不是好app w(゚Д゚)w + */ +public class BookShelfAdapter extends BaseAdapter { + private List list; + private int sumCount; + Activity activity; + Bitmap bitmap; + Bitmap bitmap2; + Bitmap bitmap3; + public BookShelfAdapter(List list, Activity activity) { + super(); + this.list = list; + this.activity = activity; + } + @Override + public int getCount() { + int count = list.size(); + if (count % 3 == 0) { + sumCount = count / 3; // 如果是3倍数 + } else { + sumCount = (int) Math.floor((double) count / 3) + 1; + } + + return sumCount; + } + + @Override + public Object getItem(int position) { + return list.get(position); + } + + @Override + public long getItemId(int position) { + return 0; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + final BookShelfAdapter.ViewHolder holder; + LayoutInflater inflater = activity.getLayoutInflater(); + + if (convertView == null) { + convertView = inflater.inflate(R.layout.listview_bookshelf, null); + holder = new BookShelfAdapter.ViewHolder(); + holder.bookItem1 = (BookItemTypeThree) convertView.findViewById(R.id.bookItemTypeThree); + holder.bookItem2 = (BookItemTypeThree) convertView.findViewById(R.id.bookItemTypeThree2); + holder.bookItem3 = (BookItemTypeThree) convertView.findViewById(R.id.bookItemTypeThree3); + convertView.setTag(holder); + } else { + holder = (BookShelfAdapter.ViewHolder) convertView.getTag(); + } + String piclink=list.get(position * 3).getPiclink(); + piclink= GlobalConfig.PicLinkCheck(piclink); + holder.bookItem1.setName(list.get(position * 3).getName()); + ImageCacheManager.loadImage(piclink,holder.bookItem1.img_pic,getBitmapFromRes(activity,R.drawable.nonepic),getBitmapFromRes(activity,R.drawable.nonepic)); + if (position * 3 + 1 == list.size()) { + holder.bookItem2.setVisibility(View.INVISIBLE); + holder.bookItem2.setVisibility(View.INVISIBLE); + holder.bookItem2.setVisibility(View.INVISIBLE); + holder.bookItem2.setVisibility(View.INVISIBLE); + holder.bookItem3.setVisibility(View.INVISIBLE); + holder.bookItem3.setVisibility(View.INVISIBLE); + holder.bookItem3.setVisibility(View.INVISIBLE); + holder.bookItem3.setVisibility(View.INVISIBLE); + } else{ + holder.bookItem2.setVisibility(View.VISIBLE); + holder.bookItem2.setVisibility(View.VISIBLE); + holder.bookItem2.setVisibility(View.VISIBLE); + holder.bookItem2.setVisibility(View.VISIBLE); + String piclink2 = list.get(position * 3 + 1).getPiclink(); + piclink2=GlobalConfig.PicLinkCheck(piclink2); + holder.bookItem2.setName(list.get(position * 3 + 1).getName()); +// holder.bookItem2.setPiclink(piclink2,GlobalConfig.bitmapnull,GlobalConfig.bitmapnull); + ImageCacheManager.loadImage(piclink2,holder.bookItem2.img_pic,getBitmapFromRes(activity,R.drawable.nonepic),getBitmapFromRes(activity,R.drawable.nonepic)); + + } + if (position * 3 + 2 >= list.size()) { + holder.bookItem3.setVisibility(View.INVISIBLE); + holder.bookItem3.setVisibility(View.INVISIBLE); + holder.bookItem3.setVisibility(View.INVISIBLE); + holder.bookItem3.setVisibility(View.INVISIBLE); + } else { + holder.bookItem3.setVisibility(View.VISIBLE); + holder.bookItem3.setVisibility(View.VISIBLE); + holder.bookItem3.setVisibility(View.VISIBLE); + holder.bookItem3.setVisibility(View.VISIBLE); + String piclink3 = list.get(position * 3 + 2).getPiclink(); + piclink3=GlobalConfig.PicLinkCheck(piclink3); + holder.bookItem3.setName(list.get(position * 3+2).getName()); +// holder.bookItem3.setPiclink(piclink3,GlobalConfig.bitmapnull,GlobalConfig.bitmapnull); + ImageCacheManager.loadImage(piclink3,holder.bookItem3.img_pic,getBitmapFromRes(activity,R.drawable.nonepic),getBitmapFromRes(activity,R.drawable.nonepic)); + + } + holder.bookItem1.setMyItemClickedListener(new MyOnEvenClick(position*3)); + holder.bookItem2.setMyItemClickedListener(new MyOnEvenClick(position*3+1)); + holder.bookItem3.setMyItemClickedListener(new MyOnEvenClick(position*3+1)); + return convertView; + } + private class ViewHolder { + BookItemTypeThree bookItem1; + BookItemTypeThree bookItem2; + BookItemTypeThree bookItem3; + } + private Bitmap getBitmapFromRes(Activity activity,int resId) { + Resources res = activity.getResources(); + return BitmapFactory.decodeResource(res, resId); + } + private class MyOnEvenClick implements BookItemTypeThree.MyItemClicked { + int pos = 0; + + public MyOnEvenClick(int position) { + this.pos = position; + } + + @Override + public void myItemClicked() { + Log.d("clickposition",pos+""); + Intent intent=new Intent(activity, ReadingActivity.class); + intent.putExtra("link",list.get(pos).getLink()); + intent.putExtra("chapternum",list.get(pos).getChapternum()); + activity.startActivity(intent); + + } + } +} diff --git a/app/src/main/java/com/tdkankan/Adapter/ChapterAdapter.java b/app/src/main/java/com/tdkankan/Adapter/ChapterAdapter.java new file mode 100644 index 0000000..dda8742 --- /dev/null +++ b/app/src/main/java/com/tdkankan/Adapter/ChapterAdapter.java @@ -0,0 +1,113 @@ +package com.tdkankan.Adapter; + +import android.graphics.Color; +import android.os.AsyncTask; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.view.GravityCompat; + +import com.hb.dialog.dialog.LoadingDialog; +import com.tdkankan.Data.GlobalConfig; +import com.tdkankan.Data.ReadConfig; +import com.tdkankan.R; +import com.tdkankan.Reptile.GetAndRead; +import com.tdkankan.Reptile.GetBook; +import com.tdkankan.UI.ReadingActivity; + +import java.util.ArrayList; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author ZQZESS + * @date 1/6/2021. + * @file ChapterAdapter + * GitHub:https://github.com/zqzess + * 不会停止运行的app不是好app w(゚Д゚)w + */ +public class ChapterAdapter extends BaseAdapter { + private ArrayList> list; + ReadingActivity activity; + LoadingDialog loadingDialog; + + public ChapterAdapter(ArrayList> list, ReadingActivity activity) { + this.list = list; + this.activity = activity; + } + + @Override + public int getCount() { + return list.size(); + } + + @Override + public Object getItem(int position) { + return list.get(position); + } + + @Override + public long getItemId(int position) { + return 0; + } + + @NonNull + @Override + public View getView(final int position, @Nullable View convertView, @NonNull ViewGroup parent) { + View v = LayoutInflater.from(activity).inflate(R.layout.listview_chapter_list, null); + TextView textView=v.findViewById(R.id.tv_listview_chapter_list_name); + if(position== GlobalConfig.chapternow) + { + textView.setTextColor(Color.RED); + }else + { + textView.setTextColor(activity.getResources().getColor(ReadConfig.fontColor)); + } + textView.setText(list.get(position).get("title")); + textView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + loadingDialog=new LoadingDialog(activity); + GlobalConfig.chapternow=position; + GlobalConfig.Page=0; +// activity.mReadPresenter.LoadChapterContent(); +// GlobalConfig.SaveReadSetting(activity);//保存阅读进度 +// activity.tv_read.setImageBitmap(activity.mReadPresenter.changePageContent(GlobalConfig.Page)); +// GetAndRead.ReadingBackground(GlobalConfig.chapternow); + new setChapter().executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); + activity.drawerLayout.closeDrawer(GravityCompat.START); + } + }); + return v; + } + private class setChapter extends AsyncTask + { + @Override + protected void onPreExecute() { + super.onPreExecute(); + loadingDialog.setMessage("加载中..."); + loadingDialog.setCancelable(true); // 是否可以按“返回键”消失 + loadingDialog.setCanceledOnTouchOutside(false); // 点击加载框以外的区域 + loadingDialog.show(); + } + + @Override + protected Boolean doInBackground(Void... voids) { + activity.mReadPresenter.LoadChapterContent(); + GlobalConfig.SaveReadSetting(activity);//保存阅读进度 + GetAndRead.ReadingBackground(GlobalConfig.chapternow); + return null; + } + + @Override + protected void onPostExecute(Boolean aBoolean) { + super.onPostExecute(aBoolean); + activity.tv_read.setImageBitmap(activity.mReadPresenter.changePageContent(GlobalConfig.Page)); + loadingDialog.dismiss(); + } + } +} diff --git a/app/src/main/java/com/tdkankan/Adapter/FengTuiAdapter.java b/app/src/main/java/com/tdkankan/Adapter/FengTuiAdapter.java new file mode 100644 index 0000000..876c25b --- /dev/null +++ b/app/src/main/java/com/tdkankan/Adapter/FengTuiAdapter.java @@ -0,0 +1,155 @@ +package com.tdkankan.Adapter; + +import android.app.Activity; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import com.tdkankan.Cache.ImageCacheManager; +import com.tdkankan.Data.BitmapUtils; +import com.tdkankan.Data.GlobalConfig; +import com.tdkankan.R; + +import java.util.ArrayList; +import java.util.HashMap; + +/** + * @author ZQZESS + * @date 12/9/2020. + * @file FengTuiAdapter + * GitHub:https://github.com/zqzess + * 不会停止运行的app不是好app w(゚Д゚)w + */ +public class FengTuiAdapter extends BaseAdapter { + public ArrayList> list; + private int sumCount; + Activity activity; + Bitmap bitmap; + Bitmap bitmap2; + + public FengTuiAdapter(ArrayList> list, Activity activity) { + super(); + this.list = list; + this.activity = activity; + } + + @Override + public int getCount() { + int count = list.size(); + if (count % 2 == 0) { + sumCount = count / 2; // 如果是双数直接减半 + } else { + sumCount = (int) Math.floor((double) count / 2) + 1; + } + + return sumCount; + } + + @Override + public Object getItem(int position) { + return list.get(position); + } + + @Override + public long getItemId(int position) { + return 0; + } + + @Override + public View getView(final int position, View convertView, ViewGroup parent) { +// int count=position; + final FengTuiAdapter.ViewHolder holder; + LayoutInflater inflater = activity.getLayoutInflater(); + + if (convertView == null) { + convertView = inflater.inflate(R.layout.listview_topfragment, null); + holder = new FengTuiAdapter.ViewHolder(); + holder.name = (TextView) convertView.findViewById(R.id.tv_topfragment_fengtui_name_1); + holder.name2 = (TextView) convertView.findViewById(R.id.tv_topfragment_fengtui_name_2); + holder.author = (TextView) convertView.findViewById(R.id.tv_topfragment_fengtui_author_1); + holder.author2 = (TextView) convertView.findViewById(R.id.tv_topfragment_fengtui_author_2); + holder.info = (TextView) convertView.findViewById(R.id.tv_topfragment_fengtui_info_1); + holder.info2 = (TextView) convertView.findViewById(R.id.tv_topfragment_fengtui_info_2); + holder.img = (ImageView) convertView.findViewById(R.id.img_topfragment_fengtui_1); + holder.img2 = (ImageView) convertView.findViewById(R.id.img_topfragment_fengtui_2); + + holder.name.setEllipsize(TextUtils.TruncateAt.END); + holder.name2.setEllipsize(TextUtils.TruncateAt.END); + holder.author.setEllipsize(TextUtils.TruncateAt.END); + holder.author2.setEllipsize(TextUtils.TruncateAt.END); + holder.info.setEllipsize(TextUtils.TruncateAt.END); + holder.info2.setEllipsize(TextUtils.TruncateAt.END); + + + convertView.setTag(holder); + } else { + holder = (FengTuiAdapter.ViewHolder) convertView.getTag(); + } +// HashMap map = list.get(count); + //获取缓存的图片 +// String picname=list.get(position*2).get("finalPicName"); +// String picname2=list.get(position*2+1).get("finalPicName"); +// bitmap= BitmapUtils.readBitmapFromFileDescriptor("/data/data/com.tdkankan/temp/images/"+picname+".jpg",50,80); +// bitmap2=BitmapUtils.readBitmapFromFileDescriptor("/data/data/com.tdkankan/temp/images/"+picname2+".jpg",50,80); + + String piclink=list.get(position*2).get("piclink"); + piclink= GlobalConfig.PicLinkCheck(piclink); + String piclink2=list.get(position*2+1).get("piclink"); + piclink2=GlobalConfig.PicLinkCheck(piclink2); + + holder.name.setText(list.get(position * 2).get("name")); + holder.author.setText(list.get(position * 2).get("author")); + holder.info.setText(list.get(position * 2).get("info")); +// holder.img.setImageBitmap(bitmap); + ImageCacheManager.loadImage(piclink,holder.img,getBitmapFromRes(activity,R.drawable.nonepic),getBitmapFromRes(activity,R.drawable.nonepic)); +// holder.img.setText(list.get(count).get("name")); +// count++; + if (position * 2 + 1 == list.size()) { + holder.name2.setVisibility(View.INVISIBLE); + holder.author2.setVisibility(View.INVISIBLE); + holder.info2.setVisibility(View.INVISIBLE); + holder.img2.setVisibility(View.INVISIBLE); + } else { + holder.name2.setVisibility(View.VISIBLE); + holder.author2.setVisibility(View.VISIBLE); + holder.info2.setVisibility(View.VISIBLE); + holder.img2.setVisibility(View.VISIBLE); + holder.name2.setText(list.get(position * 2 + 1).get("name")); + holder.author2.setText(list.get(position * 2 + 1).get("author")); + holder.info2.setText(list.get(position * 2 + 1).get("info")); +// holder.img2.setImageBitmap(bitmap2); + ImageCacheManager.loadImage(piclink2,holder.img2,getBitmapFromRes(activity,R.drawable.nonepic),getBitmapFromRes(activity,R.drawable.nonepic)); + } + + return convertView; + } + + private Bitmap getBitmapFromRes(Activity activity,int resId) { + Resources res = activity.getResources(); + return BitmapFactory.decodeResource(res, resId); + } + private class ViewHolder { + TextView name; + TextView author; + TextView info; + ImageView img; + + TextView name2; + TextView author2; + TextView info2; + ImageView img2; + } + + +} + + + + diff --git a/app/src/main/java/com/tdkankan/Adapter/SearchListAdapter.java b/app/src/main/java/com/tdkankan/Adapter/SearchListAdapter.java new file mode 100644 index 0000000..d31bf30 --- /dev/null +++ b/app/src/main/java/com/tdkankan/Adapter/SearchListAdapter.java @@ -0,0 +1,125 @@ +package com.tdkankan.Adapter; + +import android.app.Activity; +import android.content.Intent; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; + +import com.android.volley.toolbox.ImageLoader; +import com.tdkankan.Cache.BookInfoCache; +import com.tdkankan.Cache.ImageCacheManager; +import com.tdkankan.Cache.ImageCacheUtil; +import com.tdkankan.Cache.VolleyRequestQueueManager; +import com.tdkankan.Data.BookInfo; +import com.tdkankan.Data.GlobalConfig; +import com.tdkankan.R; +import com.tdkankan.UI.BookInfoDetailActivity; +import com.tdkankan.UI.SearchActivity; +import com.tdkankan.ViewUitl.BookItem; +import com.tdkankan.ViewUitl.BookItemTypeTwo; +import java.util.ArrayList; +import java.util.HashMap; + +/** + * @author ZQZESS + * @date 1/6/2021. + * @file SearchListAdapter + * GitHub:https://github.com/zqzess + * 不会停止运行的app不是好app w(゚Д゚)w + */ +public class SearchListAdapter extends BaseAdapter { + public ArrayList> list; + Activity activity; + Bitmap bitmap; + SearchActivity searchActivity; + + public SearchListAdapter(ArrayList> list, Activity activity) { + super(); + this.list = list; + this.activity = activity; + } + + @Override + public int getCount() { + int count = list.size(); + + return count; + } + + @Override + public Object getItem(int position) { + return list.get(position); + } + + @Override + public long getItemId(int position) { + return 0; + } + + @Override + public View getView(final int position, View convertView, ViewGroup parent) { + final SearchListAdapter.ViewHolder holder; + LayoutInflater inflater = activity.getLayoutInflater(); + + if (convertView == null) { + convertView = inflater.inflate(R.layout.listview_bookitem2, null); + holder = new SearchListAdapter.ViewHolder(); + holder.bookItem = (BookItemTypeTwo) convertView.findViewById(R.id.bookItemTypeTwo); + + convertView.setTag(holder); + } else { + holder = (SearchListAdapter.ViewHolder) convertView.getTag(); + } +// HashMap map = list.get(count); + //获取缓存的图片 + String picname = list.get(position).get("picname"); +// final Stripiclink = "//bqgxs.cdn.bcebos.com/web//files/article/image/107/106151/106151.jpg "ng piclink=list.get(position ).get("piclink"); +// String piclink= BookInfoCache.loadBook(picname).getBookInfo().getPiclink(); + String piclink= list.get(position).get("piclink"); + +// bitmap= BookInfoCache.loadImage(picname,piclink); +// searchActivity.imageCacheManager.loadImage("http"+piclink, holder.bookItem, getBitmapFromRes(activity,R.drawable.jay_icon),getBitmapFromRes(activity,R.drawable.jay_icon),80,110); + piclink= GlobalConfig.PicLinkCheck(piclink); + ImageCacheManager.loadImage(piclink,holder.bookItem.img_pic,getBitmapFromRes(activity,R.drawable.nonepic),getBitmapFromRes(activity,R.drawable.nonepic)); + + holder.bookItem.setName(list.get(position).get("name")); + holder.bookItem.setAuthor(list.get(position ).get("author")); + holder.bookItem.setInfo(list.get(position ).get("info")); +// holder.bookItem.setPic("http:"+piclink); + + holder.bookItem.setMyItemClickedListener(new MyOnEvenClick(position)); + return convertView; + } + + private class ViewHolder { + BookItemTypeTwo bookItem; + } + private Bitmap getBitmapFromRes(Activity activity,int resId) { + Resources res = activity.getResources(); + return BitmapFactory.decodeResource(res, resId); + } + private class MyOnEvenClick implements BookItemTypeTwo.MyItemClicked{ + int pos = 0; + + public MyOnEvenClick(int position) { + this.pos = position; + } + + @Override + public void myItemClicked() { + Intent intent=new Intent(activity, BookInfoDetailActivity.class); + intent.putExtra("name",list.get(pos).get("name")); + intent.putExtra("author",list.get(pos).get("author")); + intent.putExtra("info",list.get(pos).get("info")); + intent.putExtra("picname",list.get(pos).get("picname")); + intent.putExtra("link",list.get(pos).get("link")); + intent.putExtra("piclink",list.get(pos).get("piclink")); + activity.startActivity(intent); + } + } +} diff --git a/app/src/main/java/com/tdkankan/Cache/BookContentCache.java b/app/src/main/java/com/tdkankan/Cache/BookContentCache.java new file mode 100644 index 0000000..110b1fb --- /dev/null +++ b/app/src/main/java/com/tdkankan/Cache/BookContentCache.java @@ -0,0 +1,95 @@ +package com.tdkankan.Cache; + +import com.tdkankan.Reptile.GetAndRead; + +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author ZQZESS + * @date 1/6/2021. + * @file BookContentCache + * GitHub:https://github.com/zqzess + * 不会停止运行的app不是好app w(゚Д゚)w + */ +public class BookContentCache { + private static ConcurrentHashMap cacheMap = new ConcurrentHashMap<>(); + + /** + * 获取缓存的对象 + * + * @param url + * @return + */ + public static String getCache(String url) { + +// url = getCacheKey(url); + // 如果缓冲中有该链接,则返回value + if (cacheMap.containsKey(url)) { + return cacheMap.get(url); + } + // 如果缓存中没有该链接,把该帐号对象缓存到concurrentHashMap中 + initCache(url); + return cacheMap.get(url); + } + + /** + * 初始化缓存 + * + * @param url + */ + private static void initCache(String url) { + String content= GetAndRead.GetBookContent(url); + if(!content.isEmpty()) + { + cacheMap.put(url, content); + } +// final String url2=url; +// Thread thread1=new Thread(new Runnable() { +// @Override +// public void run() { +// String content=GetBook.GetBookContent(url2); +// if(!content.isEmpty()) +// { +// cacheMap.put(url2, content); +// } +// } +// }); +// thread1.start(); +// try { +// thread1.join(); +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } + + } + + /** + * 拼接一个缓存key + * + * @param url + * @return + */ +// private static String getCacheKey(String url) { +// return Thread.currentThread().getId() + "-" + url; +// } + + /** + * 移除缓存信息 + * + * @param url + */ + public static void removeCache(String url) { +// cacheMap.remove(getCacheKey(url)); + cacheMap.remove(url); + } + + /** + * 清除所有缓存 + * + */ + + public static void removeAll() + { + cacheMap.clear(); + } +} diff --git a/app/src/main/java/com/tdkankan/Cache/BookInfoCache.java b/app/src/main/java/com/tdkankan/Cache/BookInfoCache.java new file mode 100644 index 0000000..a3dfda4 --- /dev/null +++ b/app/src/main/java/com/tdkankan/Cache/BookInfoCache.java @@ -0,0 +1,73 @@ +package com.tdkankan.Cache; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.util.Log; + +import com.tdkankan.Data.BitmapUtils; +import com.tdkankan.Data.Book; +import com.tdkankan.Data.BookInfo; +import com.tdkankan.Data.GlobalConfig; +import com.tdkankan.Data.Picture; +import com.tdkankan.Reptile.GetBook; + +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.HashMap; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author ZQZESS + * @date 12/13/2020. + * @file BookInfoCache + * GitHub:https://github.com/zqzess + * 不会停止运行的app不是好app w(゚Д゚)w + */ +public class BookInfoCache extends HashMap { + private static ConcurrentHashMap imageMap = new ConcurrentHashMap<>(); + public static Bitmap loadImage(final String url, String dlink) { + if (imageMap.containsKey(url)) { + Log.d("picCacheGet", "图片缓存已存在:" + url); + return imageMap.get(url); + } else { + Log.d("picCacheGet", "图片缓存不存在:" + url); + initPicture(url,dlink); + return imageMap.get(url); + } + } + + private static void initPicture(String url, String dlink) { + try { + //通过传入的图片地址,获取图片 + HttpURLConnection connection = (HttpURLConnection) (new URL("http:" + dlink).openConnection()); + InputStream is = connection.getInputStream(); + Bitmap bitmap = BitmapFactory.decodeStream(is); +// if (bitmap.getByteCount() != 0) { + if (bitmap!=null) { + Log.d("pic", "图片获取成功"); + bitmap = BitmapUtils.compressImage(bitmap);//图片压缩 +// Picture picture2 = new Picture(url, bitmap); + imageMap.put(url, bitmap); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static BookInfo loadBook(String id) { + if (GlobalConfig.bookmap.containsKey(id)) { + BookInfo book = GlobalConfig.bookmap.get(id); + Log.d("bookCacheGet", "图书缓存已存在:" + id); + return book; + } else { + Log.d("bookCacheGet", "图书缓存不存在:" + id); + BookInfo book2 = GetBook.GetBookInfo(id);//爬虫爬取书本信息 +// BookInfo book2 = new BookInfo(id, bookInfo); + GlobalConfig.bookmap.put(id, book2);//书本信息存入hashmap缓存 + return book2; + } + } + +} diff --git a/app/src/main/java/com/tdkankan/Cache/ImageCacheManager.java b/app/src/main/java/com/tdkankan/Cache/ImageCacheManager.java new file mode 100644 index 0000000..3113a25 --- /dev/null +++ b/app/src/main/java/com/tdkankan/Cache/ImageCacheManager.java @@ -0,0 +1,87 @@ +package com.tdkankan.Cache; + +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.widget.ImageView; + +import com.android.volley.VolleyError; +import com.android.volley.toolbox.ImageLoader; +import com.tdkankan.ViewUitl.BookItemTypeTwo; + +/** + * @author ZQZESS + * @date 1/7/2021. + * @file ImageCacheManager + * GitHub:https://github.com/zqzess + * 不会停止运行的app不是好app w(゚Д゚)w + */ +public class ImageCacheManager { + /** + * 图片缓存管理类 获取ImageLoader对象 + */ + private static String TAG = ImageCacheManager.class.getSimpleName(); + + // 获取图片缓存类对象 + private static ImageLoader.ImageCache mImageCache = new ImageCacheUtil(); + // 获取ImageLoader对象 + public static ImageLoader mImageLoader = new ImageLoader(VolleyRequestQueueManager.mRequestQueue, mImageCache); + + + /** + * 获取ImageListener + * + * @param imageView + * @param defaultImage + * @param errorImage + * @return + */ + public static ImageLoader.ImageListener getImageListener(final ImageView imageView, final Bitmap defaultImage, final Bitmap errorImage) { + + return new ImageLoader.ImageListener() { + + @Override + public void onErrorResponse(VolleyError error) { + // 回调失败 + if (errorImage != null) { + imageView.setImageBitmap(errorImage); + } + } + + @Override + public void onResponse(ImageLoader.ImageContainer response, boolean isImmediate) { + // 回调成功 + if (response.getBitmap() != null) { + imageView.setImageBitmap(response.getBitmap()); + } else if (defaultImage != null) { + imageView.setImageBitmap(defaultImage); + } + } + }; + + } + + /** + * 提供给外部调用方法 + * + * @param url + * @param imageView + * @param defaultImage + * @param errorImage + */ + public static void loadImage(String url, ImageView imageView, Bitmap defaultImage, Bitmap errorImage) { + mImageLoader.get(url, ImageCacheManager.getImageListener(imageView, defaultImage, errorImage), 0, 0); + } + + /** + * 提供给外部调用方法 + * + * @param url + * @param imageView + * @param defaultImage + * @param errorImage + */ + public static void loadImage(String url, ImageView imageView, Bitmap defaultImage, Bitmap errorImage, int maxWidth, int maxHeight) { + mImageLoader.get(url, ImageCacheManager.getImageListener(imageView, defaultImage, errorImage), maxWidth, maxHeight); + } +} diff --git a/app/src/main/java/com/tdkankan/Cache/ImageCacheUtil.java b/app/src/main/java/com/tdkankan/Cache/ImageCacheUtil.java new file mode 100644 index 0000000..389dc5c --- /dev/null +++ b/app/src/main/java/com/tdkankan/Cache/ImageCacheUtil.java @@ -0,0 +1,154 @@ +package com.tdkankan.Cache; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.Environment; +import android.util.Log; +import android.util.LruCache; + +import com.android.volley.toolbox.ImageLoader; +import com.tdkankan.MyApplication; +import com.tdkankan.libcore.io.DiskLruCache; + +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; + +/** + * @author ZQZESS + * @date 1/7/2021. + * @file ImageCacheUtil + * GitHub:https://github.com/zqzess + * 不会停止运行的app不是好app w(゚Д゚)w + */ +public class ImageCacheUtil implements ImageLoader.ImageCache { + /** + * 图片缓存帮助类 + * + * 包含内存缓存LruCache和磁盘缓存DiskLruCache + * + * + */ + private String TAG=ImageCacheUtil.this.getClass().getSimpleName(); + + //缓存类 + private static LruCache mLruCache; + private static DiskLruCache mDiskLruCache; + + //磁盘缓存大小 + private static final int DISKMAXSIZE = 10 * 1024 * 1024; + + public ImageCacheUtil() { + // 获取应用可占内存的1/8作为缓存 + int maxSize = (int) (Runtime.getRuntime().maxMemory() / 8); + // 实例化LruCaceh对象 + mLruCache = new LruCache(maxSize) { + @Override + protected int sizeOf(String key, Bitmap bitmap) { + return bitmap.getRowBytes() * bitmap.getHeight(); + } + }; + try { + // 获取DiskLruCahce对象 + mDiskLruCache = DiskLruCache.open(getDiskCacheDir(MyApplication.newInstance(), "Rabbit"), getAppVersion(MyApplication.newInstance()), 1, DISKMAXSIZE); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * 从缓存(内存缓存,磁盘缓存)中获取Bitmap + */ + @Override + public Bitmap getBitmap(final String url) { + if (mLruCache.get(url) != null) { + // 从LruCache缓存中取 + Log.i(TAG,"从LruCahce获取"); + return mLruCache.get(url); + } else { + final String key = MD5Utils.md5(url); + try { + if (mDiskLruCache.get(key) != null) { + // 从DiskLruCahce取 + DiskLruCache.Snapshot snapshot = mDiskLruCache.get(key); + Bitmap bitmap = null; + if (snapshot != null) { + bitmap = BitmapFactory.decodeStream(snapshot.getInputStream(0)); + // 存入LruCache缓存 + mLruCache.put(url, bitmap); + Log.i(TAG,"从DiskLruCahce获取"); + } + return bitmap; + } + } catch (IOException e) { + e.printStackTrace(); + } + } + return null; + } + + /** + * 存入缓存(内存缓存,磁盘缓存) + */ + @Override + public void putBitmap(String url, Bitmap bitmap) { + // 存入LruCache缓存 + mLruCache.put(url, bitmap); + // 判断是否存在DiskLruCache缓存,若没有存入 + String key = MD5Utils.md5(url); + try { + if (mDiskLruCache.get(key) == null) { + + DiskLruCache.Editor editor = mDiskLruCache.edit(key); + if (editor != null) { + OutputStream outputStream = editor.newOutputStream(0); + if (bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)) { + editor.commit(); + } else { + editor.abort(); + } + } + + } + } catch (IOException e) { + e.printStackTrace(); + } + + } + + /** + * 该方法会判断当前sd卡是否存在,然后选择缓存地址 + * + * @param context + * @param uniqueName + * @return + */ + public static File getDiskCacheDir(Context context, String uniqueName) { + String cachePath; + if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) || !Environment.isExternalStorageRemovable()) { + cachePath = context.getExternalCacheDir().getPath(); + } else { + cachePath = context.getCacheDir().getPath(); + } + return new File(cachePath + File.separator + uniqueName); + } + + /** + * 获取应用版本号 + * + * @param context + * @return + */ + public int getAppVersion(Context context) { + try { + PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); + return info.versionCode; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + return 1; + } +} diff --git a/app/src/main/java/com/tdkankan/Cache/MD5Utils.java b/app/src/main/java/com/tdkankan/Cache/MD5Utils.java new file mode 100644 index 0000000..408a642 --- /dev/null +++ b/app/src/main/java/com/tdkankan/Cache/MD5Utils.java @@ -0,0 +1,34 @@ +package com.tdkankan.Cache; + +import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * @author ZQZESS + * @date 1/7/2021. + * @file MD5Utils + * GitHub:https://github.com/zqzess + * 不会停止运行的app不是好app w(゚Д゚)w + */ +public class MD5Utils { + /** + * 9 * 使用md5的算法进行加密 + * 10 + */ + public static String md5(String plainText) { + byte[] secretBytes = null; + try { + secretBytes = MessageDigest.getInstance("md5").digest( + plainText.getBytes()); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("没有md5这个算法!"); + } + String md5code = new BigInteger(1, secretBytes).toString(16);// 16进制数字 + // 如果生成数字未满32位,需要前面补0 + for (int i = 0; i < 32 - md5code.length(); i++) { + md5code = "0" + md5code; + } + return md5code; + } +} diff --git a/app/src/main/java/com/tdkankan/Cache/VolleyRequestQueueManager.java b/app/src/main/java/com/tdkankan/Cache/VolleyRequestQueueManager.java new file mode 100644 index 0000000..f6cac46 --- /dev/null +++ b/app/src/main/java/com/tdkankan/Cache/VolleyRequestQueueManager.java @@ -0,0 +1,39 @@ +package com.tdkankan.Cache; + +import com.android.volley.Request; +import com.android.volley.RequestQueue; +import com.android.volley.toolbox.Volley; +import com.tdkankan.MainActivity; +import com.tdkankan.MyApplication; + +/** + * @author ZQZESS + * @date 1/7/2021. + * @file VolleyRequestQueueManager + * GitHub:https://github.com/zqzess + * 不会停止运行的app不是好app w(゚Д゚)w + */ +public class VolleyRequestQueueManager { + /** + * 请求队列处理类 + * 获取RequestQueue对象 + */ + // 获取请求队列类 + public static RequestQueue mRequestQueue = Volley.newRequestQueue(MyApplication.newInstance()); + + //添加任务进任务队列 + public static void addRequest(Request request, Object tag) { + if (tag != null) { + request.setTag(tag); + } + mRequestQueue.add(request); + } + + //取消任务 + public static void cancelRequest(Object tag){ + mRequestQueue.cancelAll(tag); + } + + + +} diff --git a/app/src/main/java/com/tdkankan/Data/BitmapUtils.java b/app/src/main/java/com/tdkankan/Data/BitmapUtils.java new file mode 100644 index 0000000..5f63582 --- /dev/null +++ b/app/src/main/java/com/tdkankan/Data/BitmapUtils.java @@ -0,0 +1,171 @@ +package com.tdkankan.Data; + +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.PixelFormat; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; + +import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; + +/** + * @author ZQZESS + * @date 12/9/2020. + * @file BitmapUtils + * GitHub:https://github.com/zqzess + * 不会停止运行的app不是好app w(゚Д゚)w + */ +public class BitmapUtils { + /* + * + * Bitmap缓存类 + * + */ + + /* + * + * 保存 + */ + public static void writeBitmapToFile(String filePath, String filePath2,Bitmap b, int quality) { + try { + fileIsExist(filePath); + File desFile = new File(filePath2); + FileOutputStream fos = new FileOutputStream(desFile); + BufferedOutputStream bos = new BufferedOutputStream(fos); + b.compress(Bitmap.CompressFormat.JPEG, quality, bos); + bos.flush(); + bos.close(); + } catch (IOException e) { + e.printStackTrace(); + + } + + + } + + /* + *压缩 + */ + public static Bitmap compressImage(Bitmap image) { + if (image == null) { + return null; + } + ByteArrayOutputStream baos = null; + try { + baos = new ByteArrayOutputStream(); + image.compress(Bitmap.CompressFormat.JPEG, 50, baos); + byte[] bytes = baos.toByteArray(); + ByteArrayInputStream isBm = new ByteArrayInputStream(bytes); + Bitmap bitmap = BitmapFactory.decodeStream(isBm); + return bitmap; + } catch (OutOfMemoryError e) { + } finally { + try { + if (baos != null) { + baos.close(); + } + } catch (IOException e) { + } + } + return null; + } + + /* + *缩放 + */ + /** + * 根据scale生成一张图片 + * + * @param bitmap + * @param scale 等比缩放值 + * @return + */ + public static Bitmap bitmapScale(Bitmap bitmap, float scale) { + Matrix matrix = new Matrix(); + matrix.postScale(scale, scale); // 长和宽放大缩小的比例 + Bitmap resizeBmp = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); + return resizeBmp; + } + + /* + *Bitmap转Drawable + */ + public static Drawable bitmapToDrawable(Resources resources, Bitmap bm) { + Drawable drawable = new BitmapDrawable(resources, bm); + return drawable; + } + + /* + *Drawable转Bitmap + */ + public static Bitmap drawableToBitmap(Drawable drawable) { + Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565); + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); + drawable.draw(canvas); + return bitmap; + } + + /* + * + * 判断指定目录是否存在 + */ + + static boolean fileIsExist(String fileName) + { + //传入指定的路径,然后判断路径是否存在 + File file=new File(fileName); + if(file.exists()) + return true; + else { + //不存在则创建文件夹 + Boolean a= file.mkdirs(); + return a; + } + } + + /** + * 获取缩放后的本地图片 + * + * @param filePath 文件路径 + * @param width 宽 + * @param height 高 + * @return + */ + public static Bitmap readBitmapFromFileDescriptor(String filePath, int width, int height) { + try { + FileInputStream fis = new FileInputStream(filePath); + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeFileDescriptor(fis.getFD(), null, options); + float srcWidth = options.outWidth; + float srcHeight = options.outHeight; + int inSampleSize = 1; + + if (srcHeight > height || srcWidth > width) { + if (srcWidth > srcHeight) { + inSampleSize = Math.round(srcHeight / height); + } else { + inSampleSize = Math.round(srcWidth / width); + } + } + options.inJustDecodeBounds = false; + options.inSampleSize = inSampleSize; + Bitmap bitmap=BitmapFactory.decodeFileDescriptor(fis.getFD(), null, options); + fis.close(); + return bitmap; + } catch (Exception ex) { + } + return null; + } + +} diff --git a/app/src/main/java/com/tdkankan/Data/Book.java b/app/src/main/java/com/tdkankan/Data/Book.java new file mode 100644 index 0000000..18f98cc --- /dev/null +++ b/app/src/main/java/com/tdkankan/Data/Book.java @@ -0,0 +1,36 @@ +package com.tdkankan.Data; + +import android.graphics.Bitmap; + +/** + * @author ZQZESS + * @date 12/13/2020. + * @file Book + * GitHub:https://github.com/zqzess + * 不会停止运行的app不是好app w(゚Д゚)w + */ +public class Book { + String name; + BookInfo bookInfo; + + public Book(String name, BookInfo bookInfo) { + this.name = name; + this.bookInfo = bookInfo; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public BookInfo getBookInfo() { + return bookInfo; + } + + public void setBookInfo(BookInfo bookInfo) { + this.bookInfo = bookInfo; + } +} diff --git a/app/src/main/java/com/tdkankan/Data/BookInfo.java b/app/src/main/java/com/tdkankan/Data/BookInfo.java new file mode 100644 index 0000000..25a208f --- /dev/null +++ b/app/src/main/java/com/tdkankan/Data/BookInfo.java @@ -0,0 +1,115 @@ +package com.tdkankan.Data; + +/** + * @author ZQZESS + * @date 12/13/2020. + * @file BookInfo + * GitHub:https://github.com/zqzess + * 不会停止运行的app不是好app w(゚Д゚)w + */ +public class BookInfo { + String name; //书名 + String author; //作者 + String link; //书链接 + String picname; //封面名字 + String piclink; //封面链接 + String info; //简介 + String lasttime; //最后更新时间 + String newchapter; //最新章节 + String newchapterlink; //最新章节链接 + int chapternum; //总章节 + String linkfrom; //书源 + + public BookInfo(String name, String author, String link, String picname, String piclink, String info, String lasttime, String newchapter, String newchapterlink, int chapternum) { + this.name = name; + this.author = author; + this.link = link; + this.picname = picname; + this.piclink = piclink; + this.info = info; + this.lasttime = lasttime; + this.newchapter = newchapter; + this.newchapterlink = newchapterlink; + this.chapternum = chapternum; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getLink() { + return link; + } + + public void setLink(String link) { + this.link = link; + } + + public String getPicname() { + return picname; + } + + public void setPicname(String picname) { + this.picname = picname; + } + + public String getPiclink() { + return piclink; + } + + public void setPiclink(String piclink) { + this.piclink = piclink; + } + + public String getInfo() { + return info; + } + + public void setInfo(String info) { + this.info = info; + } + + public String getLasttime() { + return lasttime; + } + + public void setLasttime(String lasttime) { + this.lasttime = lasttime; + } + + public String getNewchapter() { + return newchapter; + } + + public void setNewchapter(String newchapter) { + this.newchapter = newchapter; + } + + public int getChapternum() { + return chapternum; + } + + public void setChapternum(int chapternum) { + this.chapternum = chapternum; + } + + public String getNewchapterlink() { + return newchapterlink; + } + + public void setNewchapterlink(String newchapterlink) { + this.newchapterlink = newchapterlink; + } +} diff --git a/app/src/main/java/com/tdkankan/Data/GlobalConfig.java b/app/src/main/java/com/tdkankan/Data/GlobalConfig.java new file mode 100644 index 0000000..3791b9b --- /dev/null +++ b/app/src/main/java/com/tdkankan/Data/GlobalConfig.java @@ -0,0 +1,128 @@ +package com.tdkankan.Data; + +import android.app.Activity; +import android.content.ContentResolver; +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.Bitmap; +import android.net.Uri; +import android.provider.Settings; +import android.view.WindowManager; + +import com.tdkankan.greendao.model.Bookinfodb; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static android.content.Context.MODE_PRIVATE; + +/** + * @author ZQZESS + * @date 12/13/2020. + * @file GlobalConfig + * GitHub:https://github.com/zqzess + * 不会停止运行的app不是好app w(゚Д゚)w + */ +public class GlobalConfig { +// public static Map map=new HashMap(); +// public static ConcurrentHashMap map=new ConcurrentHashMap(); +// public static Map bookmap=new HashMap(); + public static Map bookmap=new ConcurrentHashMap(); + public static ConcurrentHashMap contentMap=new ConcurrentHashMap();//页对应的内容 + public static int measuredWidth=0;//控件列宽度 + public static int measuredHeigtt=0;//控件高度 + public static int screenWidth=0; // 屏幕宽 + public static int screenHeight=0; // 屏幕高 + public static int mPageLineNum = 0;// 每一页显示的行数 + public static int chapternow=0;//当前章节数 + public static Bitmap mutableBitmap; + public static int Page=0;//单章当前所在页 + public static int PageTotal=1;//单章总页数 + public static int mFontHeight = 0;// 绘制字体高度 + public static String BookUrl="";//书籍链接 + public static int chapternum=0; //书籍总章节 + public static Bitmap bitmapnull=null; + // public static int sysLight=0;//系统亮度 + public static ArrayList> list =new ArrayList>(); +// public static Map bookchapter=new HashMap(); + public static List booklist; + + /** + * 获取屏幕的亮度 + */ + public static int getScreenBrightness(Context context) { + int nowBrightnessValue = 0; + ContentResolver resolver = context.getContentResolver(); + try { + nowBrightnessValue = android.provider.Settings.System.getInt(resolver, Settings.System.SCREEN_BRIGHTNESS); + } catch (Exception e) { + e.printStackTrace(); + } + return nowBrightnessValue; + } + /** + * 设置当前Activity显示时的亮度 + * 屏幕亮度最大数值一般为255,各款手机有所不同 + * screenBrightness 的取值范围在[0,1]之间 + */ + public static void setBrightness(Activity activity, int brightness) { + WindowManager.LayoutParams lp = activity.getWindow().getAttributes(); + lp.screenBrightness = Float.valueOf(brightness) * (1f / 255f); + activity.getWindow().setAttributes(lp); + ReadConfig.appLight=brightness; + } + /** + * 保存亮度设置状态,退出app也能保持设置状态 + * 修改系统亮度 + */ + public static void saveBrightness(Context context, int brightness) { + ContentResolver resolver = context.getContentResolver(); + Uri uri = android.provider.Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS); + android.provider.Settings.System.putInt(resolver, Settings.System.SCREEN_BRIGHTNESS, brightness); + resolver.notifyChange(uri, null); + } + public static void SaveReadSetting(Context context) + { + SharedPreferences sp=context.getSharedPreferences(BookUrl.replace("/",""),MODE_PRIVATE); + SharedPreferences.Editor edit = sp.edit(); + edit.putInt("Page",Page); + edit.putInt("PageTotal",PageTotal); + edit.putInt("chapternow",chapternow); + edit.commit(); + } + + public static void GetReadSetting(Context context) + { + SharedPreferences sp=context.getSharedPreferences(BookUrl.replace("/",""),MODE_PRIVATE); + Page=sp.getInt("Page",0); + PageTotal=sp.getInt("PageTotal",1); + chapternow=sp.getInt("chapternow",0); + } + public static String PicLinkCheck(String url) + { + String url2=url.substring(0,2); + String url3=""; + String regEx="http.*"; + Pattern pattern= Pattern.compile(regEx); + Matcher matcher = pattern.matcher(url); + boolean rs = matcher.find(); + if(url2.equals("//")) + { + url3="https:"+url; + return url3; + }else if(rs==true) + { + return url; + } + else + { + url3="https://www.biqugeu.net"+url; + return url3; + } + } +} diff --git a/app/src/main/java/com/tdkankan/Data/Picture.java b/app/src/main/java/com/tdkankan/Data/Picture.java new file mode 100644 index 0000000..34ddd3b --- /dev/null +++ b/app/src/main/java/com/tdkankan/Data/Picture.java @@ -0,0 +1,36 @@ +package com.tdkankan.Data; + +import android.graphics.Bitmap; + +/** + * @author ZQZESS + * @date 12/13/2020. + * @file Picture + * GitHub:https://github.com/zqzess + * 不会停止运行的app不是好app w(゚Д゚)w + */ +public class Picture { + String name; + Bitmap bitmap; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Bitmap getBitmap() { + return bitmap; + } + + public void setBitmap(Bitmap bitmap) { + this.bitmap = bitmap; + } + + public Picture(String name, Bitmap bitmap) { + this.name = name; + this.bitmap = bitmap; + } +} diff --git a/app/src/main/java/com/tdkankan/Data/ReadConfig.java b/app/src/main/java/com/tdkankan/Data/ReadConfig.java new file mode 100644 index 0000000..fa07d1c --- /dev/null +++ b/app/src/main/java/com/tdkankan/Data/ReadConfig.java @@ -0,0 +1,57 @@ +package com.tdkankan.Data; + +import android.content.Context; +import android.content.SharedPreferences; + +import com.tdkankan.R; + +import static android.content.Context.MODE_PRIVATE; + +/** + * @author ZQZESS + * @date 1/6/2021. + * @file ReadConfig + * GitHub:https://github.com/zqzess + * 不会停止运行的app不是好app w(゚Д゚)w + */ +public class ReadConfig { + public static int FontSize; //字体 + public static int bgColor; //背景色 + public static int fontColor; //字体颜色 + public static Boolean isDownload; //是否缓存本书 + public static Boolean isDark; //是否夜间模式打开 + public static Boolean isSystemLight; //是否系统亮度 + public static Boolean isFavourite; //是否加入书架 + public static boolean isSydLight; //是否系统亮度 + public static int appLight; //app亮度 + + public static void SaveSetting(Context context) + { + SharedPreferences sp=context.getSharedPreferences("setting",MODE_PRIVATE); + SharedPreferences.Editor edit = sp.edit(); + edit.putInt("Fontsize",FontSize); + edit.putInt("bgColor",bgColor); + edit.putInt("fontcolor",fontColor); + edit.putBoolean("isDownload",isDownload); + edit.putBoolean("isDark",isDark); + edit.putBoolean("isSystemLight",isSystemLight); + edit.putBoolean("isFavourite",isFavourite); + edit.putBoolean("isSydLight",isSydLight); + edit.putInt("appLight",appLight); + edit.commit(); + } + + public static void ReadSetting(Context context) + { + SharedPreferences sp=context.getSharedPreferences("setting",MODE_PRIVATE); + FontSize=sp.getInt("Fontsize",62); + bgColor=sp.getInt("bgColor",R.color.default_read_color); + fontColor=sp.getInt("fontcolor", R.color.default_font_color); + isDownload=sp.getBoolean("isDownload",false); + isDark=sp.getBoolean("isDark",false); + isSystemLight=sp.getBoolean("isSystemLight",false); + isFavourite=sp.getBoolean("isFavourite",false); + isSydLight=sp.getBoolean("isSydLight",false); + appLight=sp.getInt("appLight",0); + } +} diff --git a/app/src/main/java/com/tdkankan/Data/TabItem.java b/app/src/main/java/com/tdkankan/Data/TabItem.java new file mode 100644 index 0000000..5498fd6 --- /dev/null +++ b/app/src/main/java/com/tdkankan/Data/TabItem.java @@ -0,0 +1,91 @@ +package com.tdkankan.Data; + +import android.content.Context; +import android.graphics.Color; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.fragment.app.Fragment; + +import com.tdkankan.R; + +/** + * @author ZQZESS + * @date 12/8/2020. + * @file TabItem + * GitHub:https://github.com/zqzess + * 不会停止运行的app不是好app w(゚Д゚)w + */ +public class TabItem { + private final int SelectTextColor; + private ImageView imageviewTab; + /** + * 正常状态的图片 + */ + private int imageNormal; + + /** + * 选中状态的图片 + */ + private int imageSelected; + + private TextView textviewTab; + /** + * 文字 + */ + private String tabText; + + /** + * Fragment + */ + private Class fragmentClass; + + private View mTabView; + + public TabItem(int imageNormal, int imageSelected, String text, Class fragmentClass, int selectTextcolor) { + this.imageNormal = imageNormal; + this.imageSelected = imageSelected; + this.tabText = text; + this.fragmentClass = fragmentClass; + SelectTextColor = selectTextcolor; + } + + public Class getFragmentClass() { + return fragmentClass; + } + + /** + * 获取 tab 上的文字 + * + * @return tab 上的文字 + */ + public String getTabText() { + return tabText; + } + + /** + * 设置选中 + * + * @param checked 是否选中 + */ + public void setChecked(boolean checked) { + if (checked) { + textviewTab.setTextColor(SelectTextColor); + imageviewTab.setImageResource(imageSelected); + } else { + textviewTab.setTextColor(Color.WHITE); + imageviewTab.setImageResource(imageNormal); + } + } + + public View getTabView(Context context) { + mTabView = View.inflate(context, R.layout.view_table, null); + imageviewTab = (ImageView) mTabView.findViewById(R.id.iv_tab); + textviewTab = (TextView) mTabView.findViewById(R.id.tv_tab); + //mTvNewMsg = (TextView) mTabView.findViewById(R.id.tv_new_msg); + imageviewTab.setImageResource(imageNormal); + textviewTab.setText(tabText); + return mTabView; + } +} diff --git a/app/src/main/java/com/tdkankan/MainActivity.java b/app/src/main/java/com/tdkankan/MainActivity.java new file mode 100644 index 0000000..a3eda40 --- /dev/null +++ b/app/src/main/java/com/tdkankan/MainActivity.java @@ -0,0 +1,119 @@ +package com.tdkankan; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.fragment.app.FragmentTabHost; + +import android.app.Activity; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.Bundle; +import android.os.StrictMode; +import android.widget.TabHost; + +import com.tdkankan.Data.GlobalConfig; +import com.tdkankan.Data.TabItem; +import com.tdkankan.UI.BookCityFragment; +import com.tdkankan.UI.BookShelfFragment; +import com.tdkankan.UI.SettingFragment; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author ZQZESS + * @date 12/8/2020-9:29 PM + * @file MainActivity.java + * GitHub:https://github.com/zqzess + *不会停止运行的app不是好app w(゚Д゚)w + */ +public class MainActivity extends AppCompatActivity { + public static final int TAB_APPROVAL = 0; + public static final int TAB_SEARCH = 1; + public static final int TAB_CLASS = 2; + + private List mFragmentList; + + private FragmentTabHost mFragmentTabHost; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_mainview); + getSupportActionBar().hide(); + StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build()); + initTabItemData(); + GlobalConfig.bitmapnull=getBitmapFromRes(this,R.drawable.nonepic); + } + + private void initTabItemData() { + mFragmentList = new ArrayList<>(); + mFragmentList.add(new TabItem( + R.mipmap.ic_launcher_shujia, + R.mipmap.ic_launcher_shujia_select, + "书架", + BookShelfFragment.class, R.color.courseTable3 + )); + + mFragmentList.add(new TabItem( + R.mipmap.ic_launcher_bookcity, + R.mipmap.ic_launcher_bookcity_select, + "书城", + BookCityFragment.class, R.color.courseTable3 + )); + + mFragmentList.add(new TabItem( + R.mipmap.ic_launcher_setting, + R.mipmap.ic_launcher_setting_select, + "设置", + SettingFragment.class, R.color.courseTable3 + )); + + mFragmentTabHost = (FragmentTabHost) findViewById(android.R.id.tabhost); + // 绑定 FragmentManager + mFragmentTabHost.setup(this, getSupportFragmentManager(), android.R.id.tabcontent); + // 删除分割线 +// mFragmentTabHost.getTabWidget().setDividerDrawable(null); + + for (int i = 0; i < mFragmentList.size(); i++) { + TabItem tabItem = mFragmentList.get(i); + // 创建 tab + TabHost.TabSpec tabSpec = mFragmentTabHost.newTabSpec( + tabItem.getTabText()). + setIndicator(tabItem.getTabView(MainActivity.this)); + // 将创建的 tab 添加到底部 tab 栏中( @android:id/tabs ) + // 将 Fragment 添加到页面中( @android:id/tabcontent ) + mFragmentTabHost.addTab(tabSpec, tabItem.getFragmentClass(), null); + // 底部 tab 栏设置背景图片 + //mFragmentTabHost.getTabWidget().setBackgroundResource(R.drawable.bottom_bar); + mFragmentTabHost.getTabWidget().setBackgroundResource(R.color.courseTable6); + + // 默认选中第一个 tab + if (i == 0) { + tabItem.setChecked(true); + } else { + tabItem.setChecked(false); + } + } + + // 切换 tab 时,回调此方法 + mFragmentTabHost.setOnTabChangedListener(new TabHost.OnTabChangeListener() { + @Override + public void onTabChanged(String tabId) { + for (int i = 0; i < mFragmentList.size(); i++) { + TabItem tabItem = mFragmentList.get(i); + // 通过 tag 检查用户点击的是哪个 tab + if (tabId.equals(tabItem.getTabText())) { + tabItem.setChecked(true); + } else { + tabItem.setChecked(false); + } + } + } + }); + } + private Bitmap getBitmapFromRes(Activity activity, int resId) { + Resources res = activity.getResources(); + return BitmapFactory.decodeResource(res, resId); + } +} diff --git a/app/src/main/java/com/tdkankan/MyApplication.java b/app/src/main/java/com/tdkankan/MyApplication.java new file mode 100644 index 0000000..f94e016 --- /dev/null +++ b/app/src/main/java/com/tdkankan/MyApplication.java @@ -0,0 +1,28 @@ +package com.tdkankan; + +import android.app.Application; + +/** + * @author ZQZESS + * @date 1/7/2021. + * @file MyApplication + * GitHub:https://github.com/zqzess + * 不会停止运行的app不是好app w(゚Д゚)w + */ +public class MyApplication extends Application { + //Application类,提供全局上下文对象 + public static String TAG; + public static MyApplication myApplication; + + public static MyApplication newInstance() { + return myApplication; + } + + @Override + public void onCreate() { + super.onCreate(); + TAG = this.getClass().getSimpleName(); + myApplication = this; + + } +} diff --git a/app/src/main/java/com/tdkankan/Presente/BasePresente.java b/app/src/main/java/com/tdkankan/Presente/BasePresente.java new file mode 100644 index 0000000..13ffa37 --- /dev/null +++ b/app/src/main/java/com/tdkankan/Presente/BasePresente.java @@ -0,0 +1,18 @@ +package com.tdkankan.Presente; + +import android.graphics.Bitmap; + +/** + * @author ZQZESS + * @date 1/6/2021. + * @file BasePresente + * GitHub:https://github.com/zqzess + * 不会停止运行的app不是好app w(゚Д゚)w + */ +public interface BasePresente { + void showSettingView(); + void showSettingDetailView(); + void DayAndNightChange(int styleCode); + void LoadChapterContent(); + Bitmap changePageContent(int page); +} diff --git a/app/src/main/java/com/tdkankan/Presente/DialogCreater.java b/app/src/main/java/com/tdkankan/Presente/DialogCreater.java new file mode 100644 index 0000000..924337e --- /dev/null +++ b/app/src/main/java/com/tdkankan/Presente/DialogCreater.java @@ -0,0 +1,237 @@ +package com.tdkankan.Presente; + +import android.app.Dialog; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.WindowManager; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.SeekBar; +import android.widget.TextView; + +import com.tdkankan.Data.GlobalConfig; +import com.tdkankan.Data.ReadConfig; +import com.tdkankan.R; +import com.tdkankan.UI.ReadingActivity; + +/** + * @author ZQZESS + * @date 1/6/2021. + * @file DialogCreater + * GitHub:https://github.com/zqzess + * 不会停止运行的app不是好app w(゚Д゚)w + */ +public class DialogCreater { + public static Dialog createReadSetting(final ReadingActivity readingActivity, + final ReadPresenter readPresenter, + View.OnClickListener settingListener, + View.OnClickListener chapterListListener, + View.OnClickListener lastChapterListener, + View.OnClickListener nextChapterListener, + SeekBar.OnSeekBarChangeListener onSeekBarChangeListener) { + final Dialog dialog = new Dialog(readingActivity, R.style.jmui_default_dialog_style); + final View view = LayoutInflater.from(readingActivity).inflate(R.layout.dialog_read_setting, null); + + dialog.setContentView(view); + + //更多设置 + LinearLayout MoreSetting = (LinearLayout) view.findViewById(R.id.layout_more_setting); + MoreSetting.setOnClickListener(settingListener); + + + /* + 点击屏幕消失 + */ + view.findViewById(R.id.rl_title_view).setOnClickListener(null); + view.findViewById(R.id.layout_bottom_view).setOnClickListener(null); + view.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View view, MotionEvent motionEvent) { + dialog.dismiss(); + return false; + } + }); + + + + //夜间模式 + LinearLayout NightAndDayChange=(LinearLayout)view.findViewById(R.id.layout_night_and_day); + final TextView tv_isDrak=(TextView)view.findViewById(R.id.tv_night_and_day); + final ImageView iv_isDrak=(ImageView)view.findViewById(R.id.iv_night_and_day); + + if(ReadConfig.isDark) + {//isDrak默认false + iv_isDrak.setImageResource(R.mipmap.daylight); + tv_isDrak.setText("白天"); + } + NightAndDayChange.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if(tv_isDrak.getText().toString().equals("白天")) + { + ReadConfig.isDark=false; + iv_isDrak.setImageResource(R.mipmap.darkmoon); + tv_isDrak.setText("夜间"); + readPresenter.DayAndNightChange(0); + ReadConfig.SaveSetting(readingActivity);//保存设置 + }else + { + ReadConfig.isDark=true; + iv_isDrak.setImageResource(R.mipmap.daylight); + tv_isDrak.setText("白天"); + readPresenter.DayAndNightChange(1); + ReadConfig.SaveSetting(readingActivity);//保存设置 + } + } + }); + + + /* + *目录 + */ + LinearLayout layoutChapterList = (LinearLayout) view.findViewById(R.id.layout_chapter_list); + layoutChapterList.setOnClickListener(chapterListListener); + + //上一章 + TextView lastChapter=(TextView)view.findViewById(R.id.tv_last_chapter); + lastChapter.setOnClickListener(lastChapterListener); + //下一章 + TextView nextChapter=(TextView)view.findViewById(R.id.tv_next_chapter); + nextChapter.setOnClickListener(nextChapterListener); + + //章节跳转 + SeekBar sbChapterProgress = (SeekBar) view.findViewById(R.id.sb_read_chapter_progress); + sbChapterProgress.setProgress(GlobalConfig.chapternow*100/(GlobalConfig.list.size()-1)); + sbChapterProgress.setOnSeekBarChangeListener(onSeekBarChangeListener); + + dialog.setCancelable(true); + dialog.setCanceledOnTouchOutside(true); + dialog.show(); + return dialog; + } + + public static Dialog createReadDetailSetting(final ReadingActivity readingActivity,final ReadPresenter readPresenter) + { + /* + *详细设置 + */ + final Dialog dialog = new Dialog(readingActivity, R.style.jmui_default_dialog_style); + final View view = LayoutInflater.from(readingActivity).inflate(R.layout.dialog_read_setting_detail, null); + dialog.setContentView(view); + dialog.setCancelable(true); + dialog.setCanceledOnTouchOutside(true); + //触摸外部关闭 + view.findViewById(R.id.layout_bottom_view).setOnClickListener(null); + view.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View view, MotionEvent motionEvent) { + dialog.dismiss(); + return false; + } + }); + //字体大小 + TextView tvSizeReduce = (TextView) view.findViewById(R.id.tv_reduce_text_size); + TextView tvSizeIncrease = (TextView) view.findViewById(R.id.tv_increase_text_size); + final TextView tvSize = (TextView) view.findViewById(R.id.tv_text_size); + tvSize.setText(String.valueOf(setFontSizeView())); + tvSizeReduce.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if(ReadConfig.FontSize>=53) + {//字体减小,单章页面变小 + String tmp=tvSize.getText().toString(); + int tmpcount= Integer.parseInt(tmp); + tvSize.setText(String.valueOf(tmpcount-1)); + ReadConfig.FontSize-=3; + readPresenter.LoadChapterContent(); + if(GlobalConfig.Page+1>=GlobalConfig.PageTotal) + {//如何字体变小前页码大于变小后总页码 + GlobalConfig.Page=GlobalConfig.PageTotal-1; + } + readingActivity.tv_read.setImageBitmap(readPresenter.changePageContent(GlobalConfig.Page)); + ReadConfig.SaveSetting(readingActivity);//保存设置 + } + } + }); + tvSizeIncrease.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if(ReadConfig.FontSize<=77) + { + //字体增大,单章页面变多 + String tmp=tvSize.getText().toString(); + int tmpcount= Integer.parseInt(tmp); + tvSize.setText(String.valueOf(tmpcount+1)); + ReadConfig.FontSize+=3; + readPresenter.LoadChapterContent(); + readingActivity.tv_read.setImageBitmap(readPresenter.changePageContent(GlobalConfig.Page)); + ReadConfig.SaveSetting(readingActivity);//保存设置 + } + } + }); + + //亮度调节 + final SeekBar seekBar = (SeekBar) view.findViewById(R.id.sb_brightness_progress); + final TextView tvBrightFollowSystem = (TextView) view.findViewById(R.id.tv_system_brightness); + seekBar.setProgress(ReadConfig.appLight*100/255); + tvBrightFollowSystem.setSelected(ReadConfig.isSystemLight); + seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + GlobalConfig.setBrightness(readingActivity,progress*255/100); + ReadConfig.appLight=progress*255/100; + tvBrightFollowSystem.setSelected(false); + ReadConfig.SaveSetting(readingActivity);//保存设置 + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + + } + }); + tvBrightFollowSystem.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + tvBrightFollowSystem.setSelected(!tvBrightFollowSystem.isSelected());//设置未选择 + if(tvBrightFollowSystem.isSelected()) + {//跟随系统 + WindowManager.LayoutParams lp = readingActivity.getWindow().getAttributes(); + lp.screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE; + readingActivity.getWindow().setAttributes(lp); + ReadConfig.isSystemLight=true; + ReadConfig.SaveSetting(readingActivity);//保存设置 + }else + {//不跟随 +// seekBar.setProgress(GlobalConfig.appLight*100/255); + GlobalConfig.setBrightness(readingActivity,ReadConfig.appLight); + ReadConfig.isSystemLight=false; + ReadConfig.SaveSetting(readingActivity);//保存设置 + } + } + }); + dialog.show(); + return dialog; + } + + public static int setFontSizeView() + { + int[] size={50,53,56,59,62,65,68,71,74,77,80}; + int[] sizeview={20,21,22,23,24,25,26,27,28,29,30}; + int result=20; + for(int i=0;i + {//后台任务 + @Override + protected void onPreExecute() { + super.onPreExecute(); + loadingDialog=new LoadingDialog(readingActivity); + loadingDialog.show(); + } + + @Override + protected Boolean doInBackground(Void... voids) { + chapterAdapter = new ChapterAdapter(GlobalConfig.list, readingActivity); + return null; + } + + @Override + protected void onPostExecute(Boolean aBoolean) { + super.onPostExecute(aBoolean); + loadingDialog.dismiss(); + listView.setAdapter(chapterAdapter); + listView.setSelection(GlobalConfig.chapternow - 5); + } + } + public void LoadChapterContent() + {//加载一个章节 + textPaint.setTextSize(ReadConfig.FontSize); + Paint.FontMetrics fm = textPaint.getFontMetrics();// 得到系统默认字体属性 + GlobalConfig.mFontHeight = (int) (Math.ceil(fm.descent - fm.top) + 2);// 获得字体高度 + GlobalConfig.mPageLineNum = (int) (GlobalConfig.measuredHeigtt / GlobalConfig.mFontHeight);// 获得行数 + + String content = ""; + GlobalConfig.contentMap.clear(); + try { +// content = getBook.GetBookContent(GlobalConfig.list.get(GlobalConfig.chapternow).get("link")); + content= BookContentCache.getCache(GlobalConfig.list.get(GlobalConfig.chapternow).get("link")); + } catch (IndexOutOfBoundsException e) { + e.printStackTrace(); +// Toast.makeText(getApplicationContext(),"章节初始化失败",Toast.LENGTH_SHORT).show(); + } + content = getBook.splitContentFirst(content);//分段 + content = getBook.splitcontentSecond(content, ReadConfig.FontSize, GlobalConfig.measuredWidth);//段落分行 + getBook.PageSet(content, GlobalConfig.mPageLineNum, GlobalConfig.contentMap);//章节分页并存入hashmap + try{ + readingActivity.tv_title.setText(GlobalConfig.list.get(GlobalConfig.chapternow).get("title")); + }catch (Exception e) + { + e.printStackTrace(); + } + +// /* +// *设置阅读进度百分比 +// */ +// if(GlobalConfig.chapternow==0) +// { +// readingActivity.tv_foot.setText("0%"); +// }else +// { +// BigDecimal b1 = new BigDecimal(Double.toString(GlobalConfig.chapternow)); +// BigDecimal b2 = new BigDecimal(Double.toString(GlobalConfig.list.size())); +// BigDecimal b3=new BigDecimal(100.00); +//// int progress=GlobalConfig.chapternow%GlobalConfig.list.size(); +// try{ +// BigDecimal progress = b1.divide(b2,2,BigDecimal.ROUND_HALF_UP); +// progress=progress.multiply(b3); +// readingActivity.tv_foot.setText(progress+"%"); +// }catch (Exception e) +// { +// e.printStackTrace(); +// } +// } + } + + public Bitmap changePageContent(int page) { + /* + *设置阅读进度百分比 + */ + if(GlobalConfig.chapternow==0) + { + readingActivity.tv_foot.setText("0%"); + }else + { + BigDecimal b1 = new BigDecimal(Double.toString(GlobalConfig.chapternow)); + BigDecimal b2 = new BigDecimal(Double.toString(GlobalConfig.list.size())); + BigDecimal b3=new BigDecimal(100.00); +// int progress=GlobalConfig.chapternow%GlobalConfig.list.size(); + try{ + BigDecimal progress = b1.divide(b2,2,BigDecimal.ROUND_HALF_UP); + progress=progress.multiply(b3); + readingActivity.tv_foot.setText(progress+"%"); + }catch (Exception e) + { + e.printStackTrace(); + } + } + //切换页面 + textPaint.setColor(readingActivity.getResources().getColor(ReadConfig.fontColor));//字体颜色 + GlobalConfig.mutableBitmap = Bitmap.createBitmap(GlobalConfig.measuredWidth, GlobalConfig.measuredHeigtt, Bitmap.Config.RGB_565); + GlobalConfig.mutableBitmap.eraseColor(readingActivity.getResources().getColor(ReadConfig.bgColor));//背景色 + canvas = new Canvas(GlobalConfig.mutableBitmap); + + if (GlobalConfig.Page == 0) {//新章节起始,为标题 +// ArrayList> list=getBook.getChapter("http://www.biquge.com/135_135874/",508); + try { + canvas.drawText(GlobalConfig.contentMap.get(page), 5, (GlobalConfig.measuredHeigtt - GlobalConfig.mFontHeight) / 2, textPaint); + } catch (Exception e) { + e.printStackTrace(); + } + } else { + String tmpstring = GlobalConfig.contentMap.get(page); + try { + String[] arrtmp = tmpstring.split("\n"); + for (int i = 0; i < arrtmp.length; i++) { + canvas.drawText(arrtmp[i], 5, ReadConfig.FontSize + GlobalConfig.mFontHeight * i, textPaint); + } + } catch (NullPointerException e) { + e.printStackTrace(); + } + } + +// GlobalConfig.Page+=1; +// if(GlobalConfig.Page==GlobalConfig.contentMap.size()) +// { +// GlobalConfig.Page=0; +// } + return GlobalConfig.mutableBitmap; + } +} diff --git a/app/src/main/java/com/tdkankan/Reptile/GetAndRead.java b/app/src/main/java/com/tdkankan/Reptile/GetAndRead.java new file mode 100644 index 0000000..eb5c7a7 --- /dev/null +++ b/app/src/main/java/com/tdkankan/Reptile/GetAndRead.java @@ -0,0 +1,276 @@ +package com.tdkankan.Reptile; + +import android.content.Context; +import android.text.TextPaint; + +import com.tdkankan.Cache.BookContentCache; +import com.tdkankan.Data.GlobalConfig; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.util.ArrayList; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author ZQZESS + * @date 1/6/2021. + * @file GetAndRead + * GitHub:https://github.com/zqzess + * 不会停止运行的app不是好app w(゚Д゚)w + */ +public class GetAndRead { + Context mContext; + + public GetAndRead(Context mContext) { + this.mContext = mContext; + } + public static ArrayList getChapter(String url, int chapternum) + { + Document alldoc; +// ArrayList> list ; +// list=new ArrayList>(); + try + { + alldoc = Jsoup.connect(url).data("query", "Java"). + userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36") + .timeout(5000).get(); + + Elements listClass = alldoc.select("#list > dl > dd> a");//trim() 删除字符串首尾空白字符 + int i=0; + for (Element listitem:listClass) + { + ConcurrentHashMap chaptermap=new ConcurrentHashMap<>(); + if(chapternum>12) + { + i++; + if(i>=13) + { + String link=listitem.getElementsByTag("a").attr("href");//获取章节link + String title=listitem.getElementsByTag("a").text();//获取章节名 + chaptermap.put("link","https://www.biqugeu.net/"+link); + chaptermap.put("title",title); + GlobalConfig.list.add(chaptermap); + } + + }else + { + i++; + if(i>=chapternum) + { + String link=listitem.getElementsByTag("a").attr("href");//获取章节link + String title=listitem.getElementsByTag("a").text();//获取章节名 + chaptermap.put("link",link); + chaptermap.put("title",title); + GlobalConfig.list.add(chaptermap); + } + + } + } + } catch (MalformedURLException e) + { +// Toast.makeText(this.mContext,"书本链接错误,获取章节爬虫执行失败",Toast.LENGTH_SHORT).show(); + e.printStackTrace(); + } catch(IOException e) + { + e.printStackTrace(); + } + return GlobalConfig.list; + } + + public static void ReadingBackground(final int chapternow) + { +// final ArrayList> list ; +// list=new ArrayList>(); + Thread thread1=new Thread(new Runnable() { + @Override + public void run() { + int tmpcount=chapternow-2; + for(int i=0;i<5;i++) + { + tmpcount+=1; + if(tmpcount<=GlobalConfig.list.size()-1||tmpcount>=0) + { + // String tmpstring=GetBookContent(GlobalConfig.list.get(i).get("link"));//爬取章节内容 +// tmpstring=splitContentFirst(tmpstring);//分段 + try{ + BookContentCache.getCache(GlobalConfig.list.get(tmpcount).get("link"));//检查是否存在缓存 + }catch (Exception e) + { + e.printStackTrace(); + } + } + } + } + }); + thread1.start(); +// try { +// thread1.join(); +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } + } + + public static String GetBookContent(String url) + { + Document alldoc; + String content=""; + try + { + alldoc = Jsoup.connect(url).data("query", "Java"). + userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36") + .timeout(5000).get(); + content = alldoc.select("#content").text();//trim() 删除字符串首尾空白字符 +// String title = alldoc.select("#wrapper > div.content_read > div.box_con > div.bookname > h1").text().trim(); + }catch(Exception e) + { + e.printStackTrace(); +// Toast.makeText(mContext, "章节链接不完整或错误", Toast.LENGTH_SHORT).show(); + } + return content; + } + + public String splitContentFirst(String stringcontent) + { + /* + *处理文章第一步,分段落 + */ + if(stringcontent==""||stringcontent==null) + { + stringcontent="错误!可能原因:\n1.网络错误,笔趣阁网络连接超时或您的网络错误,请刷新重试\n2.内容错误,该书不存在内容,笔趣阁网站部分书籍没有内容,请等待新书源\n3.链接错误,笔趣阁已更换该书籍内容链接,请提交反馈"; + } + int count = stringcontent.length(); + int istart = 0; + String tmp2=stringcontent.substring(1,2); + String tmp=" "; + String contentstring=""; + for(int i=1;i<=count;i++) + { + if(i!=count) + { + String nowWord=stringcontent.substring(istart,i); + String nextWord=stringcontent.substring(i,i+1); + if(nowWord.equals(" ")&&nextWord.equals(" ")) + { + contentstring+=" "+" "; + istart=i+1; + } + else if(nowWord.equals(tmp)&&nextWord.equals(tmp2)) + { + contentstring+="\n \n"+" "+" "; + istart=i+1; +// mRealLine++; + } + else + { + contentstring+=(stringcontent.substring(istart,i)); + istart=i; + } + }else + { + contentstring+=stringcontent.substring(i-1,i); + } + } + return contentstring; + } + + public void PageSet(String content, int mPageLineNum, ConcurrentHashMap contentMap) + { + /* + *单章节分页,并将内容存入Hashmap + */ + String[] arrtmp=content.split("\n"); + String contenttmp=""; + int tmpcount=0;//单页行数 + int Pagecount=1;//单章页数 + try{ + contentMap.put(0,GlobalConfig.list.get(GlobalConfig.chapternow).get("title")); + }catch (IndexOutOfBoundsException e) + { + e.printStackTrace(); + } + for(int i=0;iPagecount) +// { +// for(int i=Pagecount;i<=contentMap.size()-Pagecount;i++) +// { +// contentMap.remove(i); +// } +// } + } + + public String splitcontentSecond(String content,int FontSize,int measuredWidth) + { + /* + *段落添加分隔符,自动换行 + */ + String[] arrtmp=content.split("\n"); + TextPaint textPaint2 = new TextPaint ( ); + String returntmp=""; + for(int i=0;i=measuredWidth-FontSize) + { + arrtmp[i]=arrtmp[i].substring(0,j)+"\n"+arrtmp[i].substring(j); + start=j; + } + textPaint2.reset(); + } + } + if(returntmp.isEmpty()) + { + returntmp=returntmp+arrtmp[i]; + }else + { + returntmp=returntmp+"\n"+arrtmp[i]; + } + } + return returntmp; + } +} diff --git a/app/src/main/java/com/tdkankan/Reptile/GetBook.java b/app/src/main/java/com/tdkankan/Reptile/GetBook.java new file mode 100644 index 0000000..1af240d --- /dev/null +++ b/app/src/main/java/com/tdkankan/Reptile/GetBook.java @@ -0,0 +1,382 @@ +package com.tdkankan.Reptile; + +import android.content.Context; +import android.util.Log; + +import com.tdkankan.Cache.BookInfoCache; +import com.tdkankan.Data.BookInfo; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; + + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; + +/** + * @author ZQZESS + * @date 12/9/2020. + * @file GetBook + * GitHub:https://github.com/zqzess + * 不会停止运行的app不是好app w(゚Д゚)w + */ +public class GetBook { + /*public static ArrayList fengtui() + { + ArrayList>list; + Document alldoc; + String name;//书名 + String author;//作者 + String info;//简介 + String link;//书链接 + String piclink;//封面链接 + String picname; + list=new ArrayList>(); +// BookInfoCache cache=new BookInfoCache(); + try{ +// alldoc = Jsoup.connect("http://www.biquge.com").get(); + alldoc= Jsoup.connect("http://www.biquge.com/").data("query", "Java").userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36").get(); + Elements listClass = alldoc.getElementsByAttributeValue("class", "item"); + for(Element listitem:listClass) + { + HashMap book = new HashMap(); + try { + link = listitem.getElementsByTag("a").attr("href");//获取书籍link + } catch (Exception e) { + link = ""; + } + try{ + piclink=listitem.getElementsByTag("img").attr("src");//获取书籍封面link + }catch (Exception e) + { + piclink=""; + } + try{ + name=listitem.getElementsByTag("img").attr("alt");//获取书籍名称 + }catch (Exception e) + { + name=""; + } + try{ + author=listitem.getElementsByTag("span").text().trim();//获取书籍作者 + }catch (Exception e) + { + author=""; + } + try{ + info=listitem.getElementsByTag("dd").text().trim();//获取书籍简介 + }catch (Exception e) + { + info=""; + } + + *//* + * + * 子线程爬取封面 + * + *//* + picname=link.replace("/",""); +// String[] arry=picname.split("_"); +// final String finalPicName=arry[1]; + final String finalPicName=picname; +// final String finalPiclink = piclink; + BookInfoCache.loadImage(finalPicName,piclink);//采用Haspmap缓存图片至内存 + + //边爬书籍边下载图片并保存本地 + + *//*class MyPicThread implements Runnable + { + + @Override + public void run() { + Bitmap bitmap = null; + File f=new File("/data/data/com.tdkankan/temp/images/"+finalPicName+".jpg"); + if(f.exists()) + { + Log.d("pic","图片已存在"); + }else + { + try { + //通过传入的图片地址,获取图片 + HttpURLConnection connection = (HttpURLConnection) (new URL("http:"+ finalPiclink).openConnection()); + InputStream is = connection.getInputStream(); + bitmap = BitmapFactory.decodeStream(is); + if(bitmap.getByteCount()!=0) + { + Log.d("pic","图片获取成功"); + BitmapUtils.writeBitmapToFile("/data/data/com.tdkankan/temp/images/","/data/data/com.tdkankan/temp/images/"+finalPicName+".jpg",bitmap,50); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + } + + }*//* + + *//* + * + * 书籍信息存入HashMap + * + *//* + + //new MyPicThread().run(); + + book.put("name",name); + book.put("link",link); + book.put("author",author); + book.put("info",info); + book.put("finalPicName",finalPicName); + book.put("piclink",piclink); + + Log.d("name",name); + Log.d("link",link); + Log.d("author",author); + Log.d("info",info); + Log.d("finalPicName",finalPicName); + Log.d("piclink",piclink); + + list.add(book); + +// try{ +// +// }catch (Exception e) +// { +// +// } + + } + }catch (IOException e) + { + e.printStackTrace(); + } + return list; + }*/ + + + public static ArrayList fengtui() + { + ArrayList>list; + Document alldoc; + String link;//书链接 + list=new ArrayList>(); + try{ + alldoc= Jsoup.connect("http://www.biquge.com/").data("query", "Java").userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36").get(); + Elements listClass = alldoc.getElementsByAttributeValue("class", "item"); + for(Element listitem:listClass) + { + HashMap book = new HashMap(); + + try { + link = listitem.getElementsByTag("a").attr("href");//获取书籍link + } catch (Exception e) { + link = ""; + } + + String id=link.replace("/",""); + final BookInfo bookInfo= BookInfoCache.loadBook(id); + + /* + * + * 子线程爬取封面 + * + */ + +// new Thread(new Runnable() { +// @Override +// public void run() { +// BookInfoCache.loadImage(bookInfo.getPicname(),bookInfo.getPiclink());//采用Haspmap缓存图片至内存 +// } +// }).start(); +// BookInfoCache.loadImage(bookInfo.getPicname(),bookInfo.getPiclink());//采用Haspmap缓存图片至内存 + + book.put("name",bookInfo.getName()); + book.put("author",bookInfo.getAuthor()); + book.put("link",link); + book.put("picname",bookInfo.getPicname()); + book.put("piclink",bookInfo.getPiclink()); + book.put("info",bookInfo.getInfo()); + book.put("lasttime",bookInfo.getLasttime()); + book.put("newchapter",bookInfo.getNewchapter()); + book.put("newchapterlink",bookInfo.getNewchapterlink()); + + Log.d("name",bookInfo.getName()); + Log.d("author",bookInfo.getAuthor()); + Log.d("link",link); + Log.d("picname",bookInfo.getPicname()); + Log.d("piclink",bookInfo.getPiclink()); + Log.d("info",bookInfo.getInfo()); + Log.d("lasttime",bookInfo.getLasttime()); + Log.d("newchapter",bookInfo.getNewchapter()); + Log.d("newchapterlink",bookInfo.getNewchapterlink()); + Log.d("chapternum",bookInfo.getChapternum()+""); + + list.add(book); + + } + }catch (IOException e) + { + e.printStackTrace(); + } + return list; + } + + public static ArrayList qiangtui() + { + Document alldoc; + final ArrayList>list; + list=new ArrayList>(); + try{ + alldoc= Jsoup.connect("http://www.biquge.com/").data("query", "Java").userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36").get(); +// Elements listClass=alldoc.getElementsByAttributeValue("class","r"); + Elements listClass=alldoc.select("#hotcontent > div.r > ul:nth-child(4) > li"); + for(Element listitem:listClass) { + + final String url = listitem.getElementsByTag("a").attr("href");//获取书籍link + final String id = url.replace("/", ""); + + final BookInfo bookInfo= BookInfoCache.loadBook(id); +// new Thread(new Runnable() { +// @Override +// public void run() { +// BookInfoCache.loadImage(bookInfo.getPicname(),bookInfo.getPiclink());//采用Haspmap缓存图片至内存 +// } +// }).start(); +// BookInfoCache.loadImage(bookInfo.getPicname(),bookInfo.getPiclink());//采用Haspmap缓存图片至内存 + + HashMap book = new HashMap(); + book.put("name",bookInfo.getName()); + book.put("author",bookInfo.getAuthor()); + book.put("link",url); + book.put("picname",bookInfo.getPicname()); + book.put("piclink",bookInfo.getPiclink()); + book.put("info",bookInfo.getInfo()); + book.put("lasttime",bookInfo.getLasttime()); + book.put("newchapter",bookInfo.getNewchapter()); + book.put("newchapterlink",bookInfo.getNewchapterlink()); + + list.add(book); + + Log.d("name",bookInfo.getName()); + Log.d("author",bookInfo.getAuthor()); + Log.d("link",url); + Log.d("picname",bookInfo.getPicname()); + Log.d("piclink",bookInfo.getPiclink()); + Log.d("info",bookInfo.getInfo()); + Log.d("lasttime",bookInfo.getLasttime()); + Log.d("newchapter",bookInfo.getNewchapter()); + Log.d("newchapterlink",bookInfo.getNewchapterlink()); + Log.d("chapternum",bookInfo.getChapternum()+""); + + } + + + }catch (IOException e) + { + e.printStackTrace(); + } + return list; + } + + public static ArrayList ruku() + { + Document alldoc; + ArrayList>list; + list=new ArrayList>(); + try{ + alldoc= Jsoup.connect("http://www.biquge.com/").data("query", "Java").userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36").get(); +// Elements listClass=alldoc.getElementsByAttributeValue("class","r"); + Elements listClass=alldoc.select("#newscontent > div.r > ul > li"); + for(Element listitem:listClass) + { + HashMap book = new HashMap(); + String url=listitem.getElementsByTag("a").attr("href");//获取书籍link + String id=url.replace("/",""); + BookInfo bookInfo= BookInfoCache.loadBook(id); + + book.put("name",bookInfo.getName()); + book.put("author",bookInfo.getAuthor()); + book.put("link",url); + book.put("picname",bookInfo.getPicname()); + book.put("piclink",bookInfo.getPiclink()); + book.put("info",bookInfo.getInfo()); + book.put("lasttime",bookInfo.getLasttime()); + book.put("newchapter",bookInfo.getNewchapter()); + book.put("newchapterlink",bookInfo.getNewchapterlink()); + + list.add(book); + + Log.d("name",bookInfo.getName()); + Log.d("author",bookInfo.getAuthor()); + Log.d("link",url); + Log.d("picname",bookInfo.getPicname()); + Log.d("piclink",bookInfo.getPiclink()); + Log.d("info",bookInfo.getInfo()); + Log.d("lasttime",bookInfo.getLasttime()); + Log.d("newchapter",bookInfo.getNewchapter()); + Log.d("newchapterlink",bookInfo.getNewchapterlink()); + Log.d("chapternum",bookInfo.getChapternum()+""); + + } + }catch (IOException e) + { + e.printStackTrace(); + } + return list; + } + + + public static BookInfo GetBookInfo(String url) + { + Document alldoc; + String name=""; //书名 + String author=""; //作者 +// String link=""; //书链接 + String picname=""; //封面名字 + String piclink=""; //封面链接 + String info=""; //简介 + String lasttime=""; //最后更新时间 + String newchapter=""; //最新章节 + String newchapterlink=""; //最新章节链接 + int chapternum=0; //总章节 + try{ + alldoc= Jsoup.connect("https://www.biqugeu.net/"+url+"/").data("query", "Java").userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36").get(); + name=alldoc.select("#info > h1").text().trim(); + author=alldoc.select("#info > p:nth-child(2)").text().trim().replace("作 者:",""); + lasttime=alldoc.select("#info > p:nth-child(4)").text().trim().replace("最后更新:",""); + newchapter=alldoc.select("#info > p:nth-child(5)").text().trim().replace("最新章节:",""); + newchapterlink=alldoc.select("#info > p:nth-child(5) > a").attr("href"); + info=alldoc.select("#intro").text().trim(); + picname=url.replace("/",""); + piclink=alldoc.getElementsByTag("img").attr("src"); + + Elements listClass = alldoc.select("#list > dl > dd"); + int i=0; + for(Element listitem:listClass) + { + listitem.getElementsByTag("a").attr("href");//获取书籍link + i++; + } + if(i>24) + { + chapternum=i-12; + }else if(i<=24&&i>0) + { + chapternum=i/2; + }else + { + chapternum=0; + } + }catch (IOException e) + { + e.printStackTrace(); + } + BookInfo book=new BookInfo(name,author,url,picname,piclink,info,lasttime,newchapter,newchapterlink,chapternum); + return book; + } + +} diff --git a/app/src/main/java/com/tdkankan/Reptile/SearchBook.java b/app/src/main/java/com/tdkankan/Reptile/SearchBook.java new file mode 100644 index 0000000..3bd8303 --- /dev/null +++ b/app/src/main/java/com/tdkankan/Reptile/SearchBook.java @@ -0,0 +1,123 @@ +package com.tdkankan.Reptile; + + +import android.util.Log; + +import com.tdkankan.Cache.BookInfoCache; +import com.tdkankan.Cache.ImageCacheManager; +import com.tdkankan.Data.BookInfo; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.HashMap; + +/** + * @author ZQZESS + * @date 1/6/2021. + * @file SearchBook + * GitHub:https://github.com/zqzess + * 不会停止运行的app不是好app w(゚Д゚)w + */ +public class SearchBook { + public static ArrayList SearchBookEvent(String KeyWords) + { + ArrayList>list; + Document alldoc; + String link;//书链接 + String name=""; + String author=""; + String info=""; + String Piclink=""; + String picname; + list=new ArrayList>(); + try { + alldoc = Jsoup.connect("https://www.biqugeu.net/searchbook.php?keyword="+KeyWords).data("query", "Java").userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36").get(); + Elements listClass = alldoc.getElementsByAttributeValue("class", "item"); + for(Element listitem:listClass) + { + HashMap book = new HashMap(); + + try { + link = listitem.getElementsByTag("a").attr("href");//获取书籍link + name=listitem.select("dt > a").text().trim();//获取书名 + author=listitem.getElementsByTag("span").text().trim();//获取作者名 + info=listitem.getElementsByTag("dd").text().trim();//获取简介 + Piclink = listitem.getElementsByTag("img").attr("src");//获取封面link + } catch (Exception e) { + link = ""; + } + picname=link.replace("/",""); +// final String id=link.replace("/",""); +// new Thread(new Runnable() { +// @Override +// public void run() { +// BookInfo bookInfo= BookInfoCache.loadBook(id); +// } +// }).start(); + final String finalPicname = picname; + final String finalPiclink = Piclink; +// class MyRunnable implements Runnable{ +// @Override +// public void run() { +// BookInfoCache.loadImage(finalPicname, finalPiclink);//采用Haspmap缓存图片至内存 +// } +// } +// new Thread(new MyRunnable()).start(); + + + /* + * + * 子线程爬取封面 + * + */ + +// BookInfoCache.loadImage(bookInfo.getPicname(),bookInfo.getPiclink());//采用Haspmap缓存图片至内存 + + +// book.put("name",bookInfo.getName()); +// book.put("author",bookInfo.getAuthor()); +// book.put("link",link); +// book.put("picname",bookInfo.getPicname()); +// book.put("piclink",bookInfo.getPiclink()); +// book.put("info",bookInfo.getInfo()); +// book.put("lasttime",bookInfo.getLasttime()); +// book.put("newchapter",bookInfo.getNewchapter()); +// book.put("newchapterlink",bookInfo.getNewchapterlink()); + book.put("name",name); + book.put("author",author); + book.put("link",link); + book.put("picname",picname); + book.put("piclink",Piclink); + book.put("info",info); + +// Log.d("name",bookInfo.getName()); +// Log.d("author",bookInfo.getAuthor()); +// Log.d("link",link); +// Log.d("picname",bookInfo.getPicname()); +// Log.d("piclink",bookInfo.getPiclink()); +// Log.d("info",bookInfo.getInfo()); +// Log.d("lasttime",bookInfo.getLasttime()); +// Log.d("newchapter",bookInfo.getNewchapter()); +// Log.d("newchapterlink",bookInfo.getNewchapterlink()); +// Log.d("chapternum",bookInfo.getChapternum()+""); + + list.add(book); + + } + }catch (Exception e) + { + + } + return list; + } +} diff --git a/app/src/main/java/com/tdkankan/SplashScreenActivity.java b/app/src/main/java/com/tdkankan/SplashScreenActivity.java new file mode 100644 index 0000000..716d9d3 --- /dev/null +++ b/app/src/main/java/com/tdkankan/SplashScreenActivity.java @@ -0,0 +1,70 @@ +package com.tdkankan; + +import androidx.appcompat.app.AppCompatActivity; + +import android.content.Intent; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Handler; +import android.view.WindowManager; + +import com.hb.dialog.dialog.LoadingDialog; +import com.tdkankan.Data.GlobalConfig; +import com.tdkankan.UI.BookShelfFragment; +import com.tdkankan.UI.SearchActivity; +import com.tdkankan.greendao.DaoHelper; + +/** + * @author ZQZESS + * @date 12/8/2020-9:25 PM + * @file SplashScreenActivity.java + * GitHub:https://github.com/zqzess + *不会停止运行的app不是好app w(゚Д゚)w + */ +public class SplashScreenActivity extends AppCompatActivity { + /** + * 延迟时间 + */ + private static final int DELAY_TIME = 1000; + private DaoHelper mDb; + LoadingDialog loadingDialog; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_splash_screen); + getSupportActionBar().hide(); + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);// 隐藏android系统的状态栏 + loadingDialog= new LoadingDialog(SplashScreenActivity.this); + new LoadData().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + private class LoadData extends AsyncTask + { + + @Override + protected void onPreExecute() { + super.onPreExecute(); + } + @Override + protected Boolean doInBackground(Void... voids) { + mDb=DaoHelper.getInstance(SplashScreenActivity.this); +// GlobalConfig.booklist=mDb.searchAll(); + return true; + } + + @Override + protected void onPostExecute(Boolean aBoolean) { + super.onPostExecute(aBoolean); + // 利用消息处理器实现延迟跳转到主窗口 + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + // 启动登录窗口 + startActivity(new Intent(SplashScreenActivity.this, MainActivity.class)); + overridePendingTransition(R.anim.fade_in, R.anim.fade_out); + // 关闭启动画面 + finish();//启动后销毁自身 + } + }, DELAY_TIME); + } + } +} diff --git a/app/src/main/java/com/tdkankan/UI/BookCityFragment.java b/app/src/main/java/com/tdkankan/UI/BookCityFragment.java new file mode 100644 index 0000000..9a97c72 --- /dev/null +++ b/app/src/main/java/com/tdkankan/UI/BookCityFragment.java @@ -0,0 +1,227 @@ +package com.tdkankan.UI; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentPagerAdapter; +import androidx.viewpager.widget.ViewPager; + +import android.content.Intent; +import android.graphics.Color; +import android.graphics.Matrix; +import android.os.Bundle; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.Display; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.tdkankan.R; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author ZQZESS + * @date 12/8/2020-9:41 PM + * @file BookCityFragment.java + * GitHub:https://github.com/zqzess + *不会停止运行的app不是好app w(゚Д゚)w + */ +public class BookCityFragment extends Fragment { + + private ViewPager viewPager;// 声明一个viewpager对象 + private TextView tv1; + private TextView tv2; + private TextView tv_search; + private ImageView tabline; + private List list;// 声明一个list集合存放Fragment(数据源) + + private int tabLineLength;// 1/2屏幕宽 + private int currentPage = 0;// 初始化当前页为0(第一页) + LinearLayout.LayoutParams ll; + + + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + +// requestWindowFeature(Window.FEATURE_NO_TITLE); +// setContentView(R.layout.mywx); +// // 初始化滑动条1/3 +// initTabLine(); +// +// // 初始化界面 +// initView(); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + + View view = inflater.inflate(R.layout.activity_bookcity, container, false); + // 获取控件实例 + tabline = (ImageView) view.findViewById(R.id.tabline); + viewPager = (ViewPager) view.findViewById(R.id.viewpager); + tv1 = (TextView) view.findViewById(R.id.tv1); + tv2 = (TextView) view.findViewById(R.id.tv2); + ll = (android.widget.LinearLayout.LayoutParams) tabline.getLayoutParams(); + tv_search=(TextView)view.findViewById(R.id.tv_search); + + + // 初始化滑动条1/2 + initTabLine(); + // 初始化界面 + initView(); + + tv1.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + ll.leftMargin = (int) (0* tabLineLength + 0 * tabLineLength); + tabline.setLayoutParams(ll); + tv1.setTextColor(Color.rgb(51, 153, 0)); + tv2.setTextColor(Color.BLACK); + viewPager.setCurrentItem(0); + + } + }); + + tv2.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + ll.leftMargin = (int) (1* tabLineLength + 0 * tabLineLength); + tabline.setLayoutParams(ll); + tv2.setTextColor(Color.rgb(51, 153, 0)); + tv1.setTextColor(Color.BLACK); + viewPager.setCurrentItem(1); + } + }); + + tv_search.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent=new Intent(BookCityFragment.this.getActivity(),SearchActivity.class); + startActivity(intent); + } + }); + return view; + } + + private void initTabLine() { + // 获取显示屏信息 + Display display = this.getActivity().getWindowManager().getDefaultDisplay(); + // 得到显示屏宽度 + DisplayMetrics metrics = new DisplayMetrics(); + display.getMetrics(metrics); + // 1/2屏幕宽度 + tabLineLength = metrics.widthPixels / 2; + + // 控件参数 + ViewGroup.LayoutParams lp = tabline.getLayoutParams(); + lp.width = tabLineLength; + tabline.setLayoutParams(lp); + } + + private void initView() { + // 实例化对象 + + list = new ArrayList(); + + // 设置数据源 + BookCityTopFragment fragment1 = new BookCityTopFragment(); + BookCityTypeFragment fragment2 = new BookCityTypeFragment(); + + list.add(fragment1); + list.add(fragment2); + + // 设置适配器 + FragmentPagerAdapter adapter = new FragmentPagerAdapter( + this.getChildFragmentManager()) { + + @Override + public int getCount() { + return list.size(); + } + + @Override + public Fragment getItem(int arg0) { + return list.get(arg0); + } + }; + + // 绑定适配器 + viewPager.setAdapter(adapter); + int offset=(tabLineLength-180)/2;//滚动条初始偏移量 + int one=offset*2+tabLineLength;//计算出切换一个界面时,滚动条位移量 + Matrix matrix=new Matrix(); + matrix.postTranslate(offset,0); + + // 设置滑动监听 + viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { + @Override + public void onPageScrolled(int arg0, float arg1, int positionOffsetPixels) { + Log.i("tuzi", arg0 + "," + arg1 + "," + positionOffsetPixels); + + // 取得该控件的实例 + LinearLayout.LayoutParams ll = (android.widget.LinearLayout.LayoutParams) tabline + .getLayoutParams(); + +// if (currentPage == 0) { // 0->1移动(第一页到第二页) +// ll.leftMargin = (int) (currentPage * tabLineLength + arg1 * tabLineLength); +// ll.leftMargin = (int) (0* tabLineLength + 0 * tabLineLength); +// } +// else if (currentPage == 1 && arg0 == 1) { // 1->2移动(第二页到第三页) +// ll.leftMargin = (int) (currentPage * tabLineLength + arg1 +// * tabLineLength);} +// else if (currentPage == 1) { // 1->0移动(第二页到第一页) +// ll.leftMargin = (int) (currentPage * tabLineLength - ((1 - arg1) * tabLineLength)); +// ll.leftMargin = (int) (1* tabLineLength + 0 * tabLineLength); +// } + +// else if (currentPage == 2 && arg0 == 1) { // 2->1移动(第三页到第二页) +// ll.leftMargin = (int) (currentPage * tabLineLength - (1 - arg1) +// * tabLineLength); +// } + +// tabline.setLayoutParams(ll); + + } + + @Override + public void onPageSelected(int position) { + tv1.setTextColor(Color.BLACK); + tv2.setTextColor(Color.BLACK); +// LinearLayout.LayoutParams ll = (android.widget.LinearLayout.LayoutParams) tabline.getLayoutParams(); + + // 再改变当前选择页(position)对应的textview颜色 + switch (position) { + case 0: + tv1.setTextColor(Color.rgb(51, 153, 0)); + ll.leftMargin = (int) (0* tabLineLength + 0 * tabLineLength); +// tabline.setLayoutParams(ll); + break; + case 1: + tv2.setTextColor(Color.rgb(51, 153, 0)); + ll.leftMargin = (int) (1* tabLineLength + 0 * tabLineLength); +// tabline.setLayoutParams(ll); + break; + } + + currentPage = position; + tabline.setLayoutParams(ll); + } + + @Override + public void onPageScrollStateChanged(int state) { + + } + + }); + } +} + diff --git a/app/src/main/java/com/tdkankan/UI/BookCityTopFragment.java b/app/src/main/java/com/tdkankan/UI/BookCityTopFragment.java new file mode 100644 index 0000000..3cb3ac3 --- /dev/null +++ b/app/src/main/java/com/tdkankan/UI/BookCityTopFragment.java @@ -0,0 +1,121 @@ +package com.tdkankan.UI; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; + +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Handler; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ListView; + +import com.hb.dialog.dialog.LoadingDialog; +import com.tdkankan.Adapter.BookListAdapter2; +import com.tdkankan.R; +import com.tdkankan.Reptile.GetBook; + +import java.util.ArrayList; +import java.util.HashMap; + +/** + * @author ZQZESS + * @date 12/9/2020-12:56 AM + * @file BookCityTopFragment.java + * GitHub:https://github.com/zqzess + *不会停止运行的app不是好app w(゚Д゚)w + */ +public class BookCityTopFragment extends Fragment { + ListView listView; + ListView listView2; + private ArrayList> list; + private ArrayList> list2; + private ArrayList> list3; + LoadingDialog loadingDialog; + /** + * 延迟时间 + */ + private static final int DELAY_TIME = 70; + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getContext(); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.activity_bookcity_topfragment, container, false); + + listView = (ListView)view.findViewById(R.id.listview_fengtui); + listView2 = (ListView)view.findViewById(R.id.listview_qiangtui); + loadingDialog= new LoadingDialog(BookCityTopFragment.this.getActivity()); + new FengTuiTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + new QiangTuiTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + return view; + } + + public class FengTuiTask extends AsyncTask + { + @Override + protected Boolean doInBackground(Void... voids) { + try { + list=GetBook.fengtui(); + }catch (Exception e) + { + e.printStackTrace(); + } + return true; + } + + //执行前调用 + @Override + protected void onPreExecute() { + super.onPreExecute(); + loadingDialog.setMessage("loading"); + loadingDialog.setCancelable(true); // 是否可以按“返回键”消失 + loadingDialog.setCanceledOnTouchOutside(false); // 点击加载框以外的区域 + loadingDialog.show(); + } + + //执行完成后调用 + @Override + protected void onPostExecute(Boolean aBoolean) { + super.onPostExecute(aBoolean); + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + BookListAdapter2 adapter = new BookListAdapter2(list,BookCityTopFragment.this.getActivity()); + listView.setAdapter(adapter); + } + },DELAY_TIME); + + } + } + + public class QiangTuiTask extends AsyncTask + { + + @Override + protected Boolean doInBackground(Void... voids) { + try { + list2=GetBook.qiangtui(); + }catch (Exception e) + { + e.printStackTrace(); + } + return true; + } + + @Override + protected void onPostExecute(Boolean aBoolean) { + super.onPostExecute(aBoolean); + loadingDialog.dismiss(); + BookListAdapter2 adapter = new BookListAdapter2(list2,BookCityTopFragment.this.getActivity()); + listView2.setAdapter(adapter); + } + } +} diff --git a/app/src/main/java/com/tdkankan/UI/BookCityTypeFragment.java b/app/src/main/java/com/tdkankan/UI/BookCityTypeFragment.java new file mode 100644 index 0000000..b617db1 --- /dev/null +++ b/app/src/main/java/com/tdkankan/UI/BookCityTypeFragment.java @@ -0,0 +1,33 @@ +package com.tdkankan.UI; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.tdkankan.R; +/** + * @author ZQZESS + * @date 12/9/2020-12:56 AM + * @file BookCityTopFragment.java + * GitHub:https://github.com/zqzess + *不会停止运行的app不是好app w(゚Д゚)w + */ +public class BookCityTypeFragment extends Fragment { + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.activity_bookcity_typefragment, container, false); + return view; + } +} diff --git a/app/src/main/java/com/tdkankan/UI/BookInfoDetailActivity.java b/app/src/main/java/com/tdkankan/UI/BookInfoDetailActivity.java new file mode 100644 index 0000000..55288bb --- /dev/null +++ b/app/src/main/java/com/tdkankan/UI/BookInfoDetailActivity.java @@ -0,0 +1,190 @@ +package com.tdkankan.UI; + +import androidx.appcompat.app.AppCompatActivity; + +import android.app.Activity; +import android.content.Intent; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.AsyncTask; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import com.hb.dialog.dialog.LoadingDialog; +import com.tdkankan.Cache.BookInfoCache; +import com.tdkankan.Cache.ImageCacheManager; +import com.tdkankan.Data.BookInfo; +import com.tdkankan.Data.GlobalConfig; +import com.tdkankan.R; +import com.tdkankan.Reptile.GetBook; +import com.tdkankan.greendao.DaoHelper; +import com.tdkankan.greendao.green.DaoMaster; +import com.tdkankan.greendao.model.Bookinfodb; + +/** + * @author ZQZESS + * @date 12/9/2020-9:21 PM + * @file BookInfoDetailActivity.java + * GitHub:https://github.com/zqzess + * 不会停止运行的app不是好app w(゚Д゚)w + */ +public class BookInfoDetailActivity extends AppCompatActivity { + TextView tv_title; + TextView tv_name; + TextView tv_info; + TextView tv_lasttime; + TextView tv_newchapter; + TextView tv_author; + ImageView img_pic; + Button btn_add; + Button btn_read; + String title; //书名 + String info; //简介 + String author; //作者 + String picname; //封面id或书本id,例如6_506 + String piclink; //封面链接 + String link; //书籍简链接,例如/6_506/ + String newchapter; //最新章节名 + String lasttime; //最后更新时间 + int chapternum; //总章节 + BookInfo bookInfo; + LoadingDialog loadingDialog; + DaoHelper mDb; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_bookinfodetail); + getSupportActionBar().hide(); + + findId(); +// initView(); + loadingDialog=new LoadingDialog(this); + new GetDataTask().executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); + mDb=DaoHelper.getInstance(BookInfoDetailActivity.this); + btn_read.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(BookInfoDetailActivity.this, ReadingActivity.class); + intent.putExtra("link", link); + intent.putExtra("chapternum",chapternum); + startActivity(intent); + } + }); + btn_add.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + /* + Long bookid; + String name; //书名 + String author; //作者 + String link; //书链接 + String piclink; //封面链接 + String info; //简介 + String lasttime; //最后更新时间 + String newchapter; //最新章节 + String newchapterlink; //最新章节链接 + int chapternum; //总章节 + String linkfrom; //书源 + */ +// String name=BookInfoCache.loadBook(link).getName(); + if(btn_add.getText().toString().equals("加入书架")) + {//加入书架 + Bookinfodb book=new Bookinfodb(null,title,author,link,piclink,info,lasttime,newchapter,"",chapternum,"biquge"); + mDb.insertOrReplace(book); + if(mDb.search(link)!=null) + { + Toast.makeText(BookInfoDetailActivity.this,"添加成功",Toast.LENGTH_SHORT).show(); + btn_add.setText("移出书架"); + } + }else + {//移出书架 + + } + } + }); + } + + private void GetData() + { + Intent intent = getIntent(); + title = intent.getStringExtra("name"); + info = intent.getStringExtra("info"); + link = intent.getStringExtra("link"); + author = intent.getStringExtra("author"); + picname = intent.getStringExtra("picname"); + piclink = intent.getStringExtra("piclink"); + piclink = GlobalConfig.PicLinkCheck(piclink); + preInitBookInfo(picname); + newchapter = bookInfo.getNewchapter(); + lasttime = bookInfo.getLasttime(); + chapternum=bookInfo.getChapternum(); + if(mDb.search(link)!=null) + { + btn_add.setText("移出书架"); + } + } + private void initView() { + +// Bitmap bitmap= BookInfoCache.loadImage(picname,piclink); + + tv_title.setText(title); + tv_name.setText(title); + tv_info.setText(info); + tv_author.setText(author); +// img_pic.setImageBitmap(bitmap); + tv_lasttime.setText(lasttime); + tv_newchapter.setText(newchapter); + } + + private void findId() { + tv_title = findViewById(R.id.tv_bookinfo_detail_title); + tv_name = findViewById(R.id.tv_bookinfo_detail_name); + tv_info = findViewById(R.id.tv_bookinfo_detail_info); + tv_lasttime = findViewById(R.id.tv_bookinfo_detail_lasttime); + tv_newchapter = findViewById(R.id.tv_bookinfo_detail_newchapter); + tv_author = findViewById(R.id.tv_bookinfo_detail_author); + img_pic = findViewById(R.id.img_bookinfo_detail_1); + btn_add = findViewById(R.id.btn_bookinfo_detail_add); + btn_read = findViewById(R.id.btn_bookinfo_detail_read); + } + + private Bitmap getBitmapFromRes(int resId) { + Resources res = this.getResources(); + return BitmapFactory.decodeResource(res, resId); + } + + private void preInitBookInfo(String url) { + bookInfo = BookInfoCache.loadBook(url); + } + private class GetDataTask extends AsyncTask + { + @Override + protected void onPreExecute() { + super.onPreExecute(); + loadingDialog.setMessage("加载中..."); + loadingDialog.setCancelable(true); // 是否可以按“返回键”消失 + loadingDialog.setCanceledOnTouchOutside(false); // 点击加载框以外的区域 + loadingDialog.show(); + } + + @Override + protected Boolean doInBackground(Void... voids) { + GetData(); + return null; + } + + @Override + protected void onPostExecute(Boolean aBoolean) { + super.onPostExecute(aBoolean); + loadingDialog.dismiss(); + initView(); + ImageCacheManager.loadImage(piclink, img_pic, getBitmapFromRes(R.drawable.nonepic), getBitmapFromRes(R.drawable.nonepic)); + } + } +} diff --git a/app/src/main/java/com/tdkankan/UI/BookShelfFragment.java b/app/src/main/java/com/tdkankan/UI/BookShelfFragment.java new file mode 100644 index 0000000..664067b --- /dev/null +++ b/app/src/main/java/com/tdkankan/UI/BookShelfFragment.java @@ -0,0 +1,108 @@ +package com.tdkankan.UI; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import android.content.Context; +import android.content.Intent; +import android.database.sqlite.SQLiteDatabase; +import android.os.Bundle; +import android.os.Handler; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ListView; +import android.widget.TextView; + +import com.tdkankan.Adapter.BookShelfAdapter; +import com.tdkankan.Data.GlobalConfig; +import com.tdkankan.MainActivity; +import com.tdkankan.R; +import com.tdkankan.SplashScreenActivity; +import com.tdkankan.greendao.DaoHelper; +import com.tdkankan.greendao.model.Bookinfodb; + +import java.util.List; + +/** + * @author ZQZESS + * @date 12/8/2020-9:39 PM + * @file BookShelfFragment.java + * GitHub:https://github.com/zqzess + *不会停止运行的app不是好app w(゚Д゚)w + */ +public class BookShelfFragment extends Fragment { + TextView tv_search; + private DaoHelper mDb; + ListView listView; + BookShelfAdapter adapter; + SwipeRefreshLayout refreshP; + List list; + Context context; + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.activity_bookshelf, container, false); + initView(view); + ClickEvent(); + return view; + } + private void initView(View view) + { + context=this.getActivity(); + tv_search=(TextView) view.findViewById(R.id.tv_bookshelf_search); + listView=(ListView)view.findViewById(R.id.listview_bookshelf); + refreshP=(SwipeRefreshLayout)view.findViewById(R.id.bookshelf_refresh); + mDb=DaoHelper.getInstance(context); + list=mDb.searchAll(); + adapter=new BookShelfAdapter(list,BookShelfFragment.this.getActivity()); + listView.setAdapter(adapter); + + } + private void ClickEvent() + { + tv_search.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent=new Intent(BookShelfFragment.this.getActivity(),SearchActivity.class); + startActivity(intent); + } + }); + refreshP.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh() { + Refresh(); + } + }); + } + + void Refresh() + { + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + list.clear(); + list.addAll(mDb.searchAll()); + refreshP.setRefreshing(false); + } + }, 1000); + adapter.notifyDataSetChanged(); + } + @Override + public void onStart() { + super.onStart(); + refreshP.post(new Runnable() { + @Override + public void run() { + refreshP.setRefreshing(true); + Refresh(); + } + }); + } +} diff --git a/app/src/main/java/com/tdkankan/UI/ReadingActivity.java b/app/src/main/java/com/tdkankan/UI/ReadingActivity.java new file mode 100644 index 0000000..76db1f2 --- /dev/null +++ b/app/src/main/java/com/tdkankan/UI/ReadingActivity.java @@ -0,0 +1,280 @@ +package com.tdkankan.UI; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.drawerlayout.widget.DrawerLayout; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.graphics.Bitmap; +import android.os.AsyncTask; +import android.os.BatteryManager; +import android.os.Bundle; +import android.os.StrictMode; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; +import android.view.WindowManager; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.hb.dialog.dialog.LoadingDialog; +import com.tdkankan.Data.GlobalConfig; +import com.tdkankan.Data.ReadConfig; +import com.tdkankan.Presente.ReadPresenter; +import com.tdkankan.R; +import com.tdkankan.Reptile.GetAndRead; +import com.tdkankan.ViewUitl.BatteryView; + +/** + * @author ZQZESS + * @date 1/6/2021-7:06 PM + * @file ReadingActivity.java + * GitHub:https://github.com/zqzess + *不会停止运行的app不是好app w(゚Д゚)w + */ +public class ReadingActivity extends AppCompatActivity { + public TextView tv_title; + public TextView tv_foot; + public TextView tv_battery_valuel; + public ImageView tv_read; + public LinearLayout linearLayout; + public LinearLayout layout_title; + public LinearLayout layout_foot; + public DrawerLayout drawerLayout; + public TextView tv_book_chapter; + public TextView tv_chapter_sort; + public LinearLayout layout_read_chapter_list_view; + + Bitmap bitmap; + Bitmap bitmap2; + private BatteryView mBatteryView; + public ReadPresenter mReadPresenter; + LoadingDialog loadingDialog; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getSupportActionBar().hide(); + setContentView(R.layout.activity_read); + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);// 隐藏android系统的状态栏 + StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build()); + + GlobalConfig.screenWidth = getWindowManager().getDefaultDisplay().getWidth(); // 屏幕宽 + GlobalConfig.screenHeight = getWindowManager().getDefaultDisplay().getHeight(); // 屏幕高 + + loadingDialog=new LoadingDialog(this); + findId(); +// if (!GlobalConfig.BookUrl.isEmpty()) { +// GlobalConfig.BookUrl = ""; +// } +// Intent intent = getIntent(); +// GlobalConfig.BookUrl=intent.getStringExtra("link"); +// ReadConfig.ReadSetting(this); +// initContent("https://www.biqugeu.net/"+GlobalConfig.BookUrl, 508); + new initReadTask().executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); +// mReadPresenter = new ReadPresenter(this); +// +// if (!ReadConfig.isDark) { +// intChapterStyle(R.color.default_read_color, R.color.default_font_color); +// } else { +// intChapterStyle(R.color.default_read_color, R.color.dark_font_color); +// } +// +// +// mReadPresenter.LoadChapterContent(); +// intStyle(); + + IntentFilter intentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); +//注册接收器以获取电量信息 + registerReceiver(broadcastReceiver, intentFilter); + linearLayout.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + Boolean isRight = event.getX() > (GlobalConfig.screenWidth / 3 * 2); + Boolean isLeft = event.getX() < (GlobalConfig.screenWidth / 3); + Boolean isCenter = event.getX() > (GlobalConfig.screenWidth / 3) && event.getX() < (GlobalConfig.screenWidth / 3 * 2); + if (isRight) { + GlobalConfig.Page = GlobalConfig.Page + 1; + if (GlobalConfig.chapternow == GlobalConfig.list.size() - 1 && GlobalConfig.Page == GlobalConfig.PageTotal) {//本书最后一章最后一页 + GlobalConfig.chapternow = GlobalConfig.list.size() - 1; + GlobalConfig.Page = GlobalConfig.Page - 1; + } else { + if (GlobalConfig.Page == GlobalConfig.PageTotal) { + /* + *本章末尾,切换章节标签,跳转下一章节 + */ + GlobalConfig.chapternow += 1; + mReadPresenter.LoadChapterContent(); + GlobalConfig.Page = 0; + if (!ReadConfig.isDownload) { + GetAndRead.ReadingBackground(GlobalConfig.chapternow); +// Log.d("isdownload","2"); + } + } + } + + Log.d("PageSet", "Page=" + GlobalConfig.Page + "Cahapter:" + GlobalConfig.chapternow); + bitmap2 = mReadPresenter.changePageContent(GlobalConfig.Page); + GlobalConfig.SaveReadSetting(getApplicationContext());//保存阅读进度 + tv_read.setImageBitmap(bitmap2); + try { + bitmap.recycle(); + bitmap = null; + System.gc(); + } catch (Exception e) { + e.printStackTrace(); + } +// Toast.makeText(getApplicationContext(), "右:X="+event.getX()+"Y="+event.getY(), Toast.LENGTH_SHORT).show(); + } + /* + *左侧 + */ + if (isLeft) { + GlobalConfig.Page = GlobalConfig.Page - 1; + if (GlobalConfig.Page < 0 && GlobalConfig.chapternow != 0) { + /* + *本章起始,切换章节标签,跳转上一章节 + */ + GlobalConfig.chapternow = GlobalConfig.chapternow - 1; + mReadPresenter.LoadChapterContent(); + GlobalConfig.Page = GlobalConfig.PageTotal - 1; + } else if (GlobalConfig.Page <= 0 && GlobalConfig.chapternow == 0) { + GlobalConfig.chapternow = 0; + mReadPresenter.LoadChapterContent(); + GlobalConfig.Page = 0; + } + Log.d("PageSet", "Page=" + GlobalConfig.Page + "Cahapter:" + GlobalConfig.chapternow); + bitmap = mReadPresenter.changePageContent(GlobalConfig.Page); + GlobalConfig.SaveReadSetting(getApplicationContext());//保存阅读进度 + tv_read.setImageBitmap(bitmap); + try { + bitmap2.recycle(); + bitmap2 = null; + System.gc(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /* + *中央 + */ + if (isCenter) { + mReadPresenter.showSettingView(); +// Toast.makeText(getApplicationContext(), "中:X="+event.getX()+"Y="+event.getY(), Toast.LENGTH_SHORT).show(); + } + return false; + } + }); + } + + public void intStyle() { + linearLayout.setBackgroundResource(ReadConfig.bgColor); + layout_foot.setBackgroundResource(ReadConfig.bgColor); + layout_title.setBackgroundResource(ReadConfig.bgColor); + + bitmap = mReadPresenter.changePageContent(GlobalConfig.Page); + tv_read.setImageBitmap(bitmap); + } + + public void intChapterStyle(int color, int fontColor) { + layout_read_chapter_list_view.setBackgroundResource(color); + tv_chapter_sort.setTextColor(getResources().getColor(fontColor)); + tv_book_chapter.setTextColor(getResources().getColor(fontColor)); + } + + private void findId() { + tv_title = findViewById(R.id.tv_title); + tv_foot = findViewById(R.id.tv_foot); + tv_read = findViewById(R.id.tv_read); + tv_battery_valuel = findViewById(R.id.tv_battery_value); + linearLayout = findViewById(R.id.layout_read); + layout_title = findViewById(R.id.layout_read_title); + layout_foot = findViewById(R.id.layout_read_foot); + mBatteryView = (BatteryView) findViewById(R.id.tv_battery); + drawerLayout = findViewById(R.id.dl_read_activity); + tv_book_chapter = findViewById(R.id.tv_book_chapter); + tv_chapter_sort = findViewById(R.id.tv_chapter_sort); + layout_read_chapter_list_view = findViewById(R.id.layout_read_chapter_list_view); + } + + + private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + //获取当前电量,如未获取具体数值,则默认为0 + int batteryLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0); + //获取最大电量,如未获取到具体数值,则默认为100 + int batteryScale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100); + //显示电量 + tv_battery_valuel.setText((batteryLevel * 100 / batteryScale) + " % "); + } + }; + + public void initContent(String url, int chapternum) { + //初始化数据 + GlobalConfig.measuredWidth = GlobalConfig.screenWidth;//控件列宽度 + GlobalConfig.measuredHeigtt = GlobalConfig.screenHeight;//控件高度 + if (GlobalConfig.list.size() > 0) { + GlobalConfig.list.clear(); + } + + if (GlobalConfig.contentMap.size() > 0) { + GlobalConfig.contentMap.clear(); + } + + GlobalConfig.GetReadSetting(getApplicationContext());//读取阅读进度 + if (!ReadConfig.isDownload) {//isDownload默认未下载,isDownload==true返回false + GetAndRead.getChapter(url, chapternum); + GetAndRead.ReadingBackground(GlobalConfig.chapternow); + } + } + private class initReadTask extends AsyncTask + { + @Override + protected void onPreExecute() { + super.onPreExecute(); + loadingDialog.setMessage("加载中..."); + loadingDialog.setCancelable(true); // 是否可以按“返回键”消失 + loadingDialog.setCanceledOnTouchOutside(false); // 点击加载框以外的区域 + loadingDialog.show(); + } + + @Override + protected Boolean doInBackground(Void... voids) { + if (!GlobalConfig.BookUrl.isEmpty()) { + GlobalConfig.BookUrl = ""; + } + Intent intent = getIntent(); + GlobalConfig.BookUrl=intent.getStringExtra("link"); + GlobalConfig.chapternum=intent.getIntExtra("chapternum",0); + ReadConfig.ReadSetting(ReadingActivity.this); + initContent("https://www.biqugeu.net/"+GlobalConfig.BookUrl, GlobalConfig.chapternum); + mReadPresenter = new ReadPresenter(ReadingActivity.this); +// if (!ReadConfig.isDark) { +// intChapterStyle(R.color.default_read_color, R.color.default_font_color); +// } else { +// intChapterStyle(R.color.default_read_color, R.color.dark_font_color); +// } + mReadPresenter.LoadChapterContent(); + return null; + } + + @Override + protected void onPostExecute(Boolean aBoolean) { + super.onPostExecute(aBoolean); +// mReadPresenter = new ReadPresenter(ReadingActivity.this); + if (!ReadConfig.isDark) { + intChapterStyle(R.color.default_read_color, R.color.default_font_color); + } else { + intChapterStyle(R.color.default_read_color, R.color.dark_font_color); + } +// mReadPresenter.LoadChapterContent(); + loadingDialog.dismiss(); + intStyle(); + } + } +} diff --git a/app/src/main/java/com/tdkankan/UI/SearchActivity.java b/app/src/main/java/com/tdkankan/UI/SearchActivity.java new file mode 100644 index 0000000..d897c4b --- /dev/null +++ b/app/src/main/java/com/tdkankan/UI/SearchActivity.java @@ -0,0 +1,91 @@ +package com.tdkankan.UI; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; + +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.view.View; +import android.widget.EditText; +import android.widget.ListView; +import android.widget.TextView; + +import com.hb.dialog.dialog.LoadingDialog; +import com.tdkankan.Adapter.SearchListAdapter; +import com.tdkankan.Cache.ImageCacheManager; +import com.tdkankan.R; +import com.tdkankan.Reptile.SearchBook; + +import java.util.ArrayList; +import java.util.HashMap; + +public class SearchActivity extends AppCompatActivity { + ListView listView; + private ArrayList> list=new ArrayList<>(); + EditText editText; + TextView textView; + TextView tv_dearch_hinit; + String stringtmp; + LoadingDialog loadingDialog; + SearchListAdapter adapter; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_search); + getSupportActionBar().hide(); + listView = findViewById(R.id.listview_search); + editText=findViewById(R.id.edittext_search); + textView=findViewById(R.id.tv_search_btn); + tv_dearch_hinit=findViewById(R.id.tv_search_hinit); + tv_dearch_hinit.setVisibility(View.GONE); + loadingDialog= new LoadingDialog(SearchActivity.this); + textView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + stringtmp=editText.getText().toString(); + new SearchTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + }); + } + public class SearchTask extends AsyncTask + { + @Override + protected void onPreExecute() { + super.onPreExecute(); + loadingDialog.setMessage("loading"); + loadingDialog.setCancelable(true); // 是否可以按“返回键”消失 + loadingDialog.setCanceledOnTouchOutside(false); // 点击加载框以外的区域 + loadingDialog.show(); + } + + @Override + protected Boolean doInBackground(Void... voids) { + list= SearchBook.SearchBookEvent(stringtmp); + adapter = new SearchListAdapter(list,SearchActivity.this); + return true; + } + + @Override + protected void onPostExecute(Boolean aBoolean) { + super.onPostExecute(aBoolean); + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + loadingDialog.dismiss(); + if(list.size()==0) + { + tv_dearch_hinit.setVisibility(View.VISIBLE); + listView.setVisibility(View.GONE); + }else { + tv_dearch_hinit.setVisibility(View.GONE); + listView.setVisibility(View.VISIBLE); + listView.setAdapter(adapter); + } + } + },2000); + } + } + +} diff --git a/app/src/main/java/com/tdkankan/UI/SettingFragment.java b/app/src/main/java/com/tdkankan/UI/SettingFragment.java new file mode 100644 index 0000000..981399d --- /dev/null +++ b/app/src/main/java/com/tdkankan/UI/SettingFragment.java @@ -0,0 +1,33 @@ +package com.tdkankan.UI; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.tdkankan.R; + +/** + * @author ZQZESS + * @date 12/8/2020-9:42 PM + * @file SettingFragment.java + * GitHub:https://github.com/zqzess + *不会停止运行的app不是好app w(゚Д゚)w + */ +public class SettingFragment extends Fragment { + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.activity_setting, container, false); + return view; + } +} diff --git a/app/src/main/java/com/tdkankan/ViewUitl/BatteryView.java b/app/src/main/java/com/tdkankan/ViewUitl/BatteryView.java new file mode 100644 index 0000000..3956678 --- /dev/null +++ b/app/src/main/java/com/tdkankan/ViewUitl/BatteryView.java @@ -0,0 +1,137 @@ +package com.tdkankan.ViewUitl; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.RectF; +import android.os.BatteryManager; +import android.util.AttributeSet; +import android.view.View; + +/** + * @author ZQZESS + * @date 1/6/2021. + * @file BatteryView + * GitHub:https://github.com/zqzess + * 不会停止运行的app不是好app w(゚Д゚)w + */ +public class BatteryView extends View { + private int mMargin = 5; //电池内芯与边框的距离 + private int mBoder = 4; //电池外框的宽带 + private int mWidth = 70; //总长 + private int mHeight = 40; //总高 + private int mHeadWidth = 6; + private int mHeadHeight = 10; + + private RectF mMainRect; + private RectF mHeadRect; + private float mRadius = 4f; //圆角 + private float mPower; + + private boolean mIsCharging; //是否在充电 + + + public BatteryView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initView(); + } + + public BatteryView(Context context, AttributeSet attrs) { + super(context, attrs); + initView(); + } + + public BatteryView(Context context) { + super(context); + initView(); + } + + private void initView() { + mHeadRect = new RectF(0, (mHeight - mHeadHeight)/2, mHeadWidth, (mHeight + mHeadHeight)/2); + + float left = mHeadRect.width(); + float top = mBoder; + float right = mWidth-mBoder; + float bottom = mHeight-mBoder; + mMainRect = new RectF(left, top, right, bottom); + + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + Paint paint1 = new Paint(); + + //画电池头 + paint1.setStyle(Paint.Style.FILL); //实心 + paint1.setColor(Color.WHITE); + canvas.drawRect(mHeadRect, paint1); + + //画外框 + paint1.setStyle(Paint.Style.STROKE); //设置空心矩形 + paint1.setStrokeWidth(mBoder); //设置边框宽度 + paint1.setColor(Color.WHITE); + canvas.drawRoundRect(mMainRect, mRadius, mRadius, paint1); + + //画电池芯 + Paint paint = new Paint(); + if (mIsCharging) { + paint.setColor(Color.GREEN); + } else { + if (mPower < 0.1) { + paint.setColor(Color.RED); + } else { + paint.setColor(Color.WHITE); + } + } + + int width = (int) (mPower * (mMainRect.width() - mMargin*2)); + int left = (int) (mMainRect.right - mMargin - width); + int right = (int) (mMainRect.right - mMargin); + int top = (int) (mMainRect.top + mMargin); + int bottom = (int) (mMainRect.bottom - mMargin); + Rect rect = new Rect(left,top,right, bottom); + canvas.drawRect(rect, paint); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setMeasuredDimension(mWidth, mHeight); + } + + private void setPower(float power) { + mPower = power; + invalidate(); + } + + private BroadcastReceiver mPowerConnectionReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1); + mIsCharging = status == BatteryManager.BATTERY_STATUS_CHARGING || + status == BatteryManager.BATTERY_STATUS_FULL; + + int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); + int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1); + + setPower(((float) level)/scale); + } + }; + + @Override + protected void onAttachedToWindow() { + getContext().registerReceiver(mPowerConnectionReceiver,new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + super.onAttachedToWindow(); + } + + @Override + protected void onDetachedFromWindow() { + getContext().unregisterReceiver(mPowerConnectionReceiver); + super.onDetachedFromWindow(); + } +} diff --git a/app/src/main/java/com/tdkankan/ViewUitl/BookItem.java b/app/src/main/java/com/tdkankan/ViewUitl/BookItem.java new file mode 100644 index 0000000..83b4192 --- /dev/null +++ b/app/src/main/java/com/tdkankan/ViewUitl/BookItem.java @@ -0,0 +1,109 @@ +package com.tdkankan.ViewUitl; + +import android.content.Context; +import android.graphics.Bitmap; +import android.util.AttributeSet; +import android.view.View; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.tdkankan.Cache.ImageCacheManager; +import com.tdkankan.R; + +/** + * @author ZQZESS + * @date 12/9/2020. + * @file BookItem + * GitHub:https://github.com/zqzess + * 不会停止运行的app不是好app w(゚Д゚)w + */ +public class BookItem extends RelativeLayout { + private MyItemClicked myItemClicked; + private RelativeLayout relativeLayout1;// 容器包含项目 + private TextView tv_name;// 书名 + private TextView tv_info;// 简介 + private TextView tv_author;// 作者 + private ImageView img_pic;//封面 + + private String name; + private String info; + private String author; + private String pic; + + + // private Boolean isSelected = false;// 是否被选中 + public BookItem(Context context) { + super(context); + } + + public BookItem(Context context, AttributeSet attrs) { + super(context, attrs); + View.inflate(context, R.layout.bookitem,this); + relativeLayout1 = (RelativeLayout) findViewById(R.id.relativeLayout1); + tv_name=(TextView)findViewById(R.id.tv_bookitem_fengtui_name_1); + tv_info=(TextView)findViewById(R.id.tv_bookitem_fengtui_info_1); + tv_author=(TextView)findViewById(R.id.tv_bookitem_fengtui_author_1); + img_pic=(ImageView)findViewById(R.id.img_bookitem_fengtui_1); + relativeLayout1.setOnClickListener(new MyOnClick()); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + tv_name.setText(name); + } + + public String getInfo() { + return info; + } + + public void setInfo(String info) { + this.info = info; + tv_info.setText(info); + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + tv_author.setText(author); + } + + public String getPic() { + return pic; + } + + public void setPic(String pic,Bitmap bitmap) { + this.pic = pic; + ImageCacheManager.loadImage(pic,img_pic,bitmap,bitmap); +// img_pic.setImageBitmap(pic); + } + + private class MyOnClick implements OnClickListener { + + @Override + public void onClick(View v) { + /* if (!isSelected) { + relativeLayout1.setBackgroundResource(R.drawable.selectedborder); + myItemClicked.myItemClicked(); + } else { + relativeLayout1.setBackgroundResource(R.drawable.border); + myItemClicked.myItemClicked(); + }*/ + myItemClicked.myItemClicked(); + } + } + public interface MyItemClicked { + public void myItemClicked(); + } + + public void setMyItemClickedListener(MyItemClicked myItemClicked) { + this.myItemClicked = myItemClicked; + } +} diff --git a/app/src/main/java/com/tdkankan/ViewUitl/BookItemTypeThree.java b/app/src/main/java/com/tdkankan/ViewUitl/BookItemTypeThree.java new file mode 100644 index 0000000..3979957 --- /dev/null +++ b/app/src/main/java/com/tdkankan/ViewUitl/BookItemTypeThree.java @@ -0,0 +1,101 @@ +package com.tdkankan.ViewUitl; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.util.AttributeSet; +import android.view.View; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.tdkankan.Cache.ImageCacheManager; +import com.tdkankan.MyApplication; +import com.tdkankan.R; + +/** + * @author ZQZESS + * @date 2/19/2021. + * @file BookItemTypeThree + * GitHub:https://github.com/zqzess + * 不会停止运行的app不是好app w(゚Д゚)w + */ +public class BookItemTypeThree extends RelativeLayout { + private BookItemTypeThree.MyItemClicked myItemClicked; + private RelativeLayout relativeLayout1;// 容器包含项目 + private TextView tv_name;// 书名 + public ImageView img_pic;//封面 + + private String name; +// private Bitmap pic; + private Bitmap pic; + // private Boolean isSelected = false;// 是否被选中 + public BookItemTypeThree(Context context) { + super(context); + } + + public BookItemTypeThree(Context context, AttributeSet attrs) { + super(context, attrs); + View.inflate(context, R.layout.bookitem3,this); + relativeLayout1 = (RelativeLayout) findViewById(R.id.relativeLayout_bookshelf); + tv_name=(TextView)findViewById(R.id.tv_bookshelf_bookname); + img_pic=(ImageView)findViewById(R.id.img_bookshelf_book); + relativeLayout1.setOnClickListener(new BookItemTypeThree.MyOnClick()); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + tv_name.setText(name); + } + + +// public Bitmap getPic() { +// return pic; +// } +// +// public void setPic(Bitmap pic) { +// this.pic = pic; +// img_pic.setImageBitmap(pic); +// } + + + public Bitmap getPic() { + return pic; + } + + public void setPic(Bitmap pic) { + this.pic = pic; + img_pic.setImageBitmap(pic); + } + + private class MyOnClick implements OnClickListener { + + @Override + public void onClick(View v) { + /* if (!isSelected) { + relativeLayout1.setBackgroundResource(R.drawable.selectedborder); + myItemClicked.myItemClicked(); + } else { + relativeLayout1.setBackgroundResource(R.drawable.border); + myItemClicked.myItemClicked(); + }*/ + myItemClicked.myItemClicked(); + } + } + public interface MyItemClicked { + public void myItemClicked(); + } + + public void setMyItemClickedListener(BookItemTypeThree.MyItemClicked myItemClicked) { + this.myItemClicked = myItemClicked; + } +// private Bitmap getBitmapFromRes(int resId) { +// Resources res = MyApplication.myApplication.getResources(); +// return BitmapFactory.decodeResource(res, resId); +// } +} diff --git a/app/src/main/java/com/tdkankan/ViewUitl/BookItemTypeTwo.java b/app/src/main/java/com/tdkankan/ViewUitl/BookItemTypeTwo.java new file mode 100644 index 0000000..8f3c23e --- /dev/null +++ b/app/src/main/java/com/tdkankan/ViewUitl/BookItemTypeTwo.java @@ -0,0 +1,116 @@ +package com.tdkankan.ViewUitl; + +import android.app.Activity; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.util.AttributeSet; +import android.view.View; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.tdkankan.Cache.ImageCacheManager; +import com.tdkankan.MyApplication; +import com.tdkankan.R; + +/** + * @author ZQZESS + * @date 1/7/2021. + * @file BookItemTypeTwo + * GitHub:https://github.com/zqzess + * 不会停止运行的app不是好app w(゚Д゚)w + */ +public class BookItemTypeTwo extends RelativeLayout { + private BookItemTypeTwo.MyItemClicked myItemClicked; + private RelativeLayout relativeLayout1;// 容器包含项目 + private TextView tv_name;// 书名 + private TextView tv_info;// 简介 + private TextView tv_author;// 作者 + public ImageView img_pic;//封面 + + private String name; + private String info; + private String author; + private Bitmap pic; + + // private Boolean isSelected = false;// 是否被选中 + public BookItemTypeTwo(Context context) { + super(context); + } + + public BookItemTypeTwo(Context context, AttributeSet attrs) { + super(context, attrs); + View.inflate(context, R.layout.bookitem2,this); + relativeLayout1 = (RelativeLayout) findViewById(R.id.relativeLayout2); + tv_name=(TextView)findViewById(R.id.tv_bookitem_fengtui_name_2); + tv_info=(TextView)findViewById(R.id.tv_bookitem_fengtui_info_2); + tv_author=(TextView)findViewById(R.id.tv_bookitem_fengtui_author_2); + img_pic=(ImageView)findViewById(R.id.img_bookitem_fengtui_2); + relativeLayout1.setOnClickListener(new BookItemTypeTwo.MyOnClick()); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + tv_name.setText(name); + } + + public String getInfo() { + return info; + } + + public void setInfo(String info) { + this.info = info; + tv_info.setText(info); + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + tv_author.setText(author); + } + + public Bitmap getPic() { + return pic; + } + + public void setPic(Bitmap pic) { + this.pic = pic; + img_pic.setImageBitmap(pic); + } + + private class MyOnClick implements OnClickListener { + + @Override + public void onClick(View v) { + /* if (!isSelected) { + relativeLayout1.setBackgroundResource(R.drawable.selectedborder); + myItemClicked.myItemClicked(); + } else { + relativeLayout1.setBackgroundResource(R.drawable.border); + myItemClicked.myItemClicked(); + }*/ + myItemClicked.myItemClicked(); + } + } + public interface MyItemClicked { + public void myItemClicked(); + } + + public void setMyItemClickedListener(BookItemTypeTwo.MyItemClicked myItemClicked) { + this.myItemClicked = myItemClicked; + } + private Bitmap getBitmapFromRes(int resId) { + Resources res = MyApplication.myApplication.getResources(); + return BitmapFactory.decodeResource(res, resId); + + } +} diff --git a/app/src/main/java/com/tdkankan/greendao/DaoHelper.java b/app/src/main/java/com/tdkankan/greendao/DaoHelper.java new file mode 100644 index 0000000..5647e91 --- /dev/null +++ b/app/src/main/java/com/tdkankan/greendao/DaoHelper.java @@ -0,0 +1,95 @@ +package com.tdkankan.greendao; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; + +import com.tdkankan.greendao.green.BookinfodbDao; +import com.tdkankan.greendao.green.DaoMaster; +import com.tdkankan.greendao.green.DaoSession; +import com.tdkankan.greendao.model.Bookinfodb; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author ZQZESS + * @date 2021/5/23. + * @file DaoHelper + * GitHub:https://github.com/zqzess + * 不会停止运行的app不是好app w(゚Д゚)w + */ +public class DaoHelper { + //数据库名称 + private static final String DATABASE_NAME = "booklist.db"; + //用来获取Dao的 + private static DaoSession daoSession; + private static DaoHelper mDaoHelper; + private BookinfodbDao bookinfodbDao; + + public DaoHelper(Context context) { +// init(context); + //使用自定义的OpenHelper的到SQLiteDatabase + MyOpenHelper helper = new MyOpenHelper(context, DATABASE_NAME, null); + SQLiteDatabase db = helper.getWritableDatabase(); + DaoMaster daoMaster = new DaoMaster(db); + daoSession = daoMaster.newSession(); + bookinfodbDao=daoSession.getBookinfodbDao(); + } + +// public static void init(Context context) { +// //使用自定义的OpenHelper的到SQLiteDatabase +// MyOpenHelper helper = new MyOpenHelper(context, DATABASE_NAME, null); +// SQLiteDatabase db = helper.getWritableDatabase(); +// DaoMaster daoMaster = new DaoMaster(db); +// daoSession = daoMaster.newSession(); +// } + public static DaoSession getDaoSession() { + return daoSession; + } + + //单例模式 + public static DaoHelper getInstance(Context context){ + if (mDaoHelper == null){ + synchronized (DaoHelper.class){ + if (mDaoHelper == null) { + mDaoHelper = new DaoHelper(context); + } + } + } + return mDaoHelper; + } + //插入 + public Long insert(Bookinfodb book) + { + return bookinfodbDao.insert(book); + } + public Long insertOrReplace(Bookinfodb book) + { + return bookinfodbDao.insertOrReplace(book); + } + //删除 + public void delete(Long bookid) + { + bookinfodbDao.queryBuilder().where(BookinfodbDao.Properties.Bookid.eq(bookid)).buildDelete().executeDeleteWithoutDetachingEntities(); + } + //更新 + public void update(Bookinfodb book) + { + Bookinfodb old=bookinfodbDao.queryBuilder().where(BookinfodbDao.Properties.Bookid.eq(book.getBookid())).build().unique(); + if(old!=null) + { + bookinfodbDao.update(book); + } + } + //查询 + public List searchAll() + { + List book=bookinfodbDao.queryBuilder().list(); + return book; + } + public Bookinfodb search(String link) + { + Bookinfodb book=bookinfodbDao.queryBuilder().where(BookinfodbDao.Properties.Link.eq(link)).build().unique(); + return book; + } +} diff --git a/app/src/main/java/com/tdkankan/greendao/MyOpenHelper.java b/app/src/main/java/com/tdkankan/greendao/MyOpenHelper.java new file mode 100644 index 0000000..18eee37 --- /dev/null +++ b/app/src/main/java/com/tdkankan/greendao/MyOpenHelper.java @@ -0,0 +1,33 @@ +package com.tdkankan.greendao; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; + +import com.tdkankan.greendao.green.DaoMaster; + +/** + * @author ZQZESS + * @date 2021/5/23. + * @file MyOpenHelper + * GitHub:https://github.com/zqzess + * 不会停止运行的app不是好app w(゚Д゚)w + */ +public class MyOpenHelper extends DaoMaster.OpenHelper { + public MyOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) { + super(context, name, factory); + } + + /** + * 更新数据库 + * @param db + * @param oldVersion + * @param newVersion + */ + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + switch (oldVersion){ + case 1: + break; + } + } +} diff --git a/app/src/main/java/com/tdkankan/greendao/green/BookinfodbDao.java b/app/src/main/java/com/tdkankan/greendao/green/BookinfodbDao.java new file mode 100644 index 0000000..39107eb --- /dev/null +++ b/app/src/main/java/com/tdkankan/greendao/green/BookinfodbDao.java @@ -0,0 +1,247 @@ +package com.tdkankan.greendao.green; + +import android.database.Cursor; +import android.database.sqlite.SQLiteStatement; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.Property; +import org.greenrobot.greendao.internal.DaoConfig; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseStatement; + +import com.tdkankan.greendao.model.Bookinfodb; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * DAO for table "BOOKINFODB". +*/ +public class BookinfodbDao extends AbstractDao { + + public static final String TABLENAME = "BOOKINFODB"; + + /** + * Properties of entity Bookinfodb.
+ * Can be used for QueryBuilder and for referencing column names. + */ + public static class Properties { + public final static Property Bookid = new Property(0, Long.class, "bookid", true, "_id"); + public final static Property Name = new Property(1, String.class, "name", false, "NAME"); + public final static Property Author = new Property(2, String.class, "author", false, "AUTHOR"); + public final static Property Link = new Property(3, String.class, "link", false, "LINK"); + public final static Property Piclink = new Property(4, String.class, "piclink", false, "PICLINK"); + public final static Property Info = new Property(5, String.class, "info", false, "INFO"); + public final static Property Lasttime = new Property(6, String.class, "lasttime", false, "LASTTIME"); + public final static Property Newchapter = new Property(7, String.class, "newchapter", false, "NEWCHAPTER"); + public final static Property Newchapterlink = new Property(8, String.class, "newchapterlink", false, "NEWCHAPTERLINK"); + public final static Property Chapternum = new Property(9, int.class, "chapternum", false, "CHAPTERNUM"); + public final static Property Linkfrom = new Property(10, String.class, "linkfrom", false, "LINKFROM"); + } + + + public BookinfodbDao(DaoConfig config) { + super(config); + } + + public BookinfodbDao(DaoConfig config, DaoSession daoSession) { + super(config, daoSession); + } + + /** Creates the underlying database table. */ + public static void createTable(Database db, boolean ifNotExists) { + String constraint = ifNotExists? "IF NOT EXISTS ": ""; + db.execSQL("CREATE TABLE " + constraint + "\"BOOKINFODB\" (" + // + "\"_id\" INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: bookid + "\"NAME\" TEXT," + // 1: name + "\"AUTHOR\" TEXT," + // 2: author + "\"LINK\" TEXT," + // 3: link + "\"PICLINK\" TEXT," + // 4: piclink + "\"INFO\" TEXT," + // 5: info + "\"LASTTIME\" TEXT," + // 6: lasttime + "\"NEWCHAPTER\" TEXT," + // 7: newchapter + "\"NEWCHAPTERLINK\" TEXT," + // 8: newchapterlink + "\"CHAPTERNUM\" INTEGER NOT NULL ," + // 9: chapternum + "\"LINKFROM\" TEXT);"); // 10: linkfrom + } + + /** Drops the underlying database table. */ + public static void dropTable(Database db, boolean ifExists) { + String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"BOOKINFODB\""; + db.execSQL(sql); + } + + @Override + protected final void bindValues(DatabaseStatement stmt, Bookinfodb entity) { + stmt.clearBindings(); + + Long bookid = entity.getBookid(); + if (bookid != null) { + stmt.bindLong(1, bookid); + } + + String name = entity.getName(); + if (name != null) { + stmt.bindString(2, name); + } + + String author = entity.getAuthor(); + if (author != null) { + stmt.bindString(3, author); + } + + String link = entity.getLink(); + if (link != null) { + stmt.bindString(4, link); + } + + String piclink = entity.getPiclink(); + if (piclink != null) { + stmt.bindString(5, piclink); + } + + String info = entity.getInfo(); + if (info != null) { + stmt.bindString(6, info); + } + + String lasttime = entity.getLasttime(); + if (lasttime != null) { + stmt.bindString(7, lasttime); + } + + String newchapter = entity.getNewchapter(); + if (newchapter != null) { + stmt.bindString(8, newchapter); + } + + String newchapterlink = entity.getNewchapterlink(); + if (newchapterlink != null) { + stmt.bindString(9, newchapterlink); + } + stmt.bindLong(10, entity.getChapternum()); + + String linkfrom = entity.getLinkfrom(); + if (linkfrom != null) { + stmt.bindString(11, linkfrom); + } + } + + @Override + protected final void bindValues(SQLiteStatement stmt, Bookinfodb entity) { + stmt.clearBindings(); + + Long bookid = entity.getBookid(); + if (bookid != null) { + stmt.bindLong(1, bookid); + } + + String name = entity.getName(); + if (name != null) { + stmt.bindString(2, name); + } + + String author = entity.getAuthor(); + if (author != null) { + stmt.bindString(3, author); + } + + String link = entity.getLink(); + if (link != null) { + stmt.bindString(4, link); + } + + String piclink = entity.getPiclink(); + if (piclink != null) { + stmt.bindString(5, piclink); + } + + String info = entity.getInfo(); + if (info != null) { + stmt.bindString(6, info); + } + + String lasttime = entity.getLasttime(); + if (lasttime != null) { + stmt.bindString(7, lasttime); + } + + String newchapter = entity.getNewchapter(); + if (newchapter != null) { + stmt.bindString(8, newchapter); + } + + String newchapterlink = entity.getNewchapterlink(); + if (newchapterlink != null) { + stmt.bindString(9, newchapterlink); + } + stmt.bindLong(10, entity.getChapternum()); + + String linkfrom = entity.getLinkfrom(); + if (linkfrom != null) { + stmt.bindString(11, linkfrom); + } + } + + @Override + public Long readKey(Cursor cursor, int offset) { + return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0); + } + + @Override + public Bookinfodb readEntity(Cursor cursor, int offset) { + Bookinfodb entity = new Bookinfodb( // + cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // bookid + cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1), // name + cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2), // author + cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3), // link + cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4), // piclink + cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5), // info + cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6), // lasttime + cursor.isNull(offset + 7) ? null : cursor.getString(offset + 7), // newchapter + cursor.isNull(offset + 8) ? null : cursor.getString(offset + 8), // newchapterlink + cursor.getInt(offset + 9), // chapternum + cursor.isNull(offset + 10) ? null : cursor.getString(offset + 10) // linkfrom + ); + return entity; + } + + @Override + public void readEntity(Cursor cursor, Bookinfodb entity, int offset) { + entity.setBookid(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0)); + entity.setName(cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1)); + entity.setAuthor(cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2)); + entity.setLink(cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3)); + entity.setPiclink(cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4)); + entity.setInfo(cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5)); + entity.setLasttime(cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6)); + entity.setNewchapter(cursor.isNull(offset + 7) ? null : cursor.getString(offset + 7)); + entity.setNewchapterlink(cursor.isNull(offset + 8) ? null : cursor.getString(offset + 8)); + entity.setChapternum(cursor.getInt(offset + 9)); + entity.setLinkfrom(cursor.isNull(offset + 10) ? null : cursor.getString(offset + 10)); + } + + @Override + protected final Long updateKeyAfterInsert(Bookinfodb entity, long rowId) { + entity.setBookid(rowId); + return rowId; + } + + @Override + public Long getKey(Bookinfodb entity) { + if(entity != null) { + return entity.getBookid(); + } else { + return null; + } + } + + @Override + public boolean hasKey(Bookinfodb entity) { + return entity.getBookid() != null; + } + + @Override + protected final boolean isEntityUpdateable() { + return true; + } + +} diff --git a/app/src/main/java/com/tdkankan/greendao/green/DaoMaster.java b/app/src/main/java/com/tdkankan/greendao/green/DaoMaster.java new file mode 100644 index 0000000..dc4f378 --- /dev/null +++ b/app/src/main/java/com/tdkankan/greendao/green/DaoMaster.java @@ -0,0 +1,96 @@ +package com.tdkankan.greendao.green; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteDatabase.CursorFactory; +import android.util.Log; + +import org.greenrobot.greendao.AbstractDaoMaster; +import org.greenrobot.greendao.database.StandardDatabase; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseOpenHelper; +import org.greenrobot.greendao.identityscope.IdentityScopeType; + + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * Master of DAO (schema version 1): knows all DAOs. + */ +public class DaoMaster extends AbstractDaoMaster { + public static final int SCHEMA_VERSION = 1; + + /** Creates underlying database table using DAOs. */ + public static void createAllTables(Database db, boolean ifNotExists) { + BookinfodbDao.createTable(db, ifNotExists); + } + + /** Drops underlying database table using DAOs. */ + public static void dropAllTables(Database db, boolean ifExists) { + BookinfodbDao.dropTable(db, ifExists); + } + + /** + * WARNING: Drops all table on Upgrade! Use only during development. + * Convenience method using a {@link DevOpenHelper}. + */ + public static DaoSession newDevSession(Context context, String name) { + Database db = new DevOpenHelper(context, name).getWritableDb(); + DaoMaster daoMaster = new DaoMaster(db); + return daoMaster.newSession(); + } + + public DaoMaster(SQLiteDatabase db) { + this(new StandardDatabase(db)); + } + + public DaoMaster(Database db) { + super(db, SCHEMA_VERSION); + registerDaoClass(BookinfodbDao.class); + } + + public DaoSession newSession() { + return new DaoSession(db, IdentityScopeType.Session, daoConfigMap); + } + + public DaoSession newSession(IdentityScopeType type) { + return new DaoSession(db, type, daoConfigMap); + } + + /** + * Calls {@link #createAllTables(Database, boolean)} in {@link #onCreate(Database)} - + */ + public static abstract class OpenHelper extends DatabaseOpenHelper { + public OpenHelper(Context context, String name) { + super(context, name, SCHEMA_VERSION); + } + + public OpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory, SCHEMA_VERSION); + } + + @Override + public void onCreate(Database db) { + Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION); + createAllTables(db, false); + } + } + + /** WARNING: Drops all table on Upgrade! Use only during development. */ + public static class DevOpenHelper extends OpenHelper { + public DevOpenHelper(Context context, String name) { + super(context, name); + } + + public DevOpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory); + } + + @Override + public void onUpgrade(Database db, int oldVersion, int newVersion) { + Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables"); + dropAllTables(db, true); + onCreate(db); + } + } + +} diff --git a/app/src/main/java/com/tdkankan/greendao/green/DaoSession.java b/app/src/main/java/com/tdkankan/greendao/green/DaoSession.java new file mode 100644 index 0000000..1638d20 --- /dev/null +++ b/app/src/main/java/com/tdkankan/greendao/green/DaoSession.java @@ -0,0 +1,48 @@ +package com.tdkankan.greendao.green; + +import java.util.Map; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.AbstractDaoSession; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.identityscope.IdentityScopeType; +import org.greenrobot.greendao.internal.DaoConfig; + +import com.tdkankan.greendao.model.Bookinfodb; + +import com.tdkankan.greendao.green.BookinfodbDao; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. + +/** + * {@inheritDoc} + * + * @see org.greenrobot.greendao.AbstractDaoSession + */ +public class DaoSession extends AbstractDaoSession { + + private final DaoConfig bookinfodbDaoConfig; + + private final BookinfodbDao bookinfodbDao; + + public DaoSession(Database db, IdentityScopeType type, Map>, DaoConfig> + daoConfigMap) { + super(db); + + bookinfodbDaoConfig = daoConfigMap.get(BookinfodbDao.class).clone(); + bookinfodbDaoConfig.initIdentityScope(type); + + bookinfodbDao = new BookinfodbDao(bookinfodbDaoConfig, this); + + registerDao(Bookinfodb.class, bookinfodbDao); + } + + public void clear() { + bookinfodbDaoConfig.clearIdentityScope(); + } + + public BookinfodbDao getBookinfodbDao() { + return bookinfodbDao; + } + +} diff --git a/app/src/main/java/com/tdkankan/greendao/model/Bookinfodb.java b/app/src/main/java/com/tdkankan/greendao/model/Bookinfodb.java new file mode 100644 index 0000000..b886d2a --- /dev/null +++ b/app/src/main/java/com/tdkankan/greendao/model/Bookinfodb.java @@ -0,0 +1,116 @@ +package com.tdkankan.greendao.model; + +import org.greenrobot.greendao.annotation.Entity; +import org.greenrobot.greendao.annotation.Id; +import org.greenrobot.greendao.annotation.Generated; + +/** + * @author ZQZESS + * @date 2021/5/23. + * @file BookinfoDao + * GitHub:https://github.com/zqzess + * 不会停止运行的app不是好app w(゚Д゚)w + */ +@Entity +public class Bookinfodb { + @Id(autoincrement = true) + Long bookid;//数据库书籍id + + String name; //书名 + String author; //作者 + String link; //书链接 + String piclink; //封面链接 + String info; //简介 + String lasttime; //最后更新时间 + String newchapter; //最新章节 + String newchapterlink; //最新章节链接 + int chapternum; //总章节 + String linkfrom; //书源 + @Generated(hash = 1233158695) + public Bookinfodb(Long bookid, String name, String author, String link, + String piclink, String info, String lasttime, String newchapter, + String newchapterlink, int chapternum, String linkfrom) { + this.bookid = bookid; + this.name = name; + this.author = author; + this.link = link; + this.piclink = piclink; + this.info = info; + this.lasttime = lasttime; + this.newchapter = newchapter; + this.newchapterlink = newchapterlink; + this.chapternum = chapternum; + this.linkfrom = linkfrom; + } + @Generated(hash = 61057257) + public Bookinfodb() { + } + public Long getBookid() { + return this.bookid; + } + public void setBookid(Long bookid) { + this.bookid = bookid; + } + public String getName() { + return this.name; + } + public void setName(String name) { + this.name = name; + } + public String getAuthor() { + return this.author; + } + public void setAuthor(String author) { + this.author = author; + } + public String getLink() { + return this.link; + } + public void setLink(String link) { + this.link = link; + } + public String getPiclink() { + return this.piclink; + } + public void setPiclink(String piclink) { + this.piclink = piclink; + } + public String getInfo() { + return this.info; + } + public void setInfo(String info) { + this.info = info; + } + public String getLasttime() { + return this.lasttime; + } + public void setLasttime(String lasttime) { + this.lasttime = lasttime; + } + public String getNewchapter() { + return this.newchapter; + } + public void setNewchapter(String newchapter) { + this.newchapter = newchapter; + } + public String getNewchapterlink() { + return this.newchapterlink; + } + public void setNewchapterlink(String newchapterlink) { + this.newchapterlink = newchapterlink; + } + public int getChapternum() { + return this.chapternum; + } + public void setChapternum(int chapternum) { + this.chapternum = chapternum; + } + public String getLinkfrom() { + return this.linkfrom; + } + public void setLinkfrom(String linkfrom) { + this.linkfrom = linkfrom; + } + + +} diff --git a/app/src/main/java/com/tdkankan/libcore/io/DiskLruCache.java b/app/src/main/java/com/tdkankan/libcore/io/DiskLruCache.java new file mode 100644 index 0000000..fc53b45 --- /dev/null +++ b/app/src/main/java/com/tdkankan/libcore/io/DiskLruCache.java @@ -0,0 +1,943 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.tdkankan.libcore.io; + +import java.io.BufferedWriter; +import java.io.Closeable; +import java.io.EOFException; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * A cache that uses a bounded amount of space on a filesystem. Each cache + * entry has a string key and a fixed number of values. Each key must match + * the regex [a-z0-9_-]{1,120}. Values are byte sequences, + * accessible as streams or files. Each value must be between {@code 0} and + * {@code Integer.MAX_VALUE} bytes in length. + * + *

The cache stores its data in a directory on the filesystem. This + * directory must be exclusive to the cache; the cache may delete or overwrite + * files from its directory. It is an error for multiple processes to use the + * same cache directory at the same time. + * + *

This cache limits the number of bytes that it will store on the + * filesystem. When the number of stored bytes exceeds the limit, the cache will + * remove entries in the background until the limit is satisfied. The limit is + * not strict: the cache may temporarily exceed it while waiting for files to be + * deleted. The limit does not include filesystem overhead or the cache + * journal so space-sensitive applications should set a conservative limit. + * + *

Clients call {@link #edit} to create or update the values of an entry. An + * entry may have only one editor at one time; if a value is not available to be + * edited then {@link #edit} will return null. + *

    + *
  • When an entry is being created it is necessary to + * supply a full set of values; the empty value should be used as a + * placeholder if necessary. + *
  • When an entry is being edited, it is not necessary + * to supply data for every value; values default to their previous + * value. + *
+ * Every {@link #edit} call must be matched by a call to {@link Editor#commit} + * or {@link Editor#abort}. Committing is atomic: a read observes the full set + * of values as they were before or after the commit, but never a mix of values. + * + *

Clients call {@link #get} to read a snapshot of an entry. The read will + * observe the value at the time that {@link #get} was called. Updates and + * removals after the call do not impact ongoing reads. + * + *

This class is tolerant of some I/O errors. If files are missing from the + * filesystem, the corresponding entries will be dropped from the cache. If + * an error occurs while writing a cache value, the edit will fail silently. + * Callers should handle other problems by catching {@code IOException} and + * responding appropriately. + */ +public final class DiskLruCache implements Closeable { + static final String JOURNAL_FILE = "journal"; + static final String JOURNAL_FILE_TEMP = "journal.tmp"; + static final String JOURNAL_FILE_BACKUP = "journal.bkp"; + static final String MAGIC = "libcore.io.DiskLruCache"; + static final String VERSION_1 = "1"; + static final long ANY_SEQUENCE_NUMBER = -1; + static final String STRING_KEY_PATTERN = "[a-z0-9_-]{1,120}"; + static final Pattern LEGAL_KEY_PATTERN = Pattern.compile(STRING_KEY_PATTERN); + private static final String CLEAN = "CLEAN"; + private static final String DIRTY = "DIRTY"; + private static final String REMOVE = "REMOVE"; + private static final String READ = "READ"; + + /* + * This cache uses a journal file named "journal". A typical journal file + * looks like this: + * libcore.io.DiskLruCache + * 1 + * 100 + * 2 + * + * CLEAN 3400330d1dfc7f3f7f4b8d4d803dfcf6 832 21054 + * DIRTY 335c4c6028171cfddfbaae1a9c313c52 + * CLEAN 335c4c6028171cfddfbaae1a9c313c52 3934 2342 + * REMOVE 335c4c6028171cfddfbaae1a9c313c52 + * DIRTY 1ab96a171faeeee38496d8b330771a7a + * CLEAN 1ab96a171faeeee38496d8b330771a7a 1600 234 + * READ 335c4c6028171cfddfbaae1a9c313c52 + * READ 3400330d1dfc7f3f7f4b8d4d803dfcf6 + * + * The first five lines of the journal form its header. They are the + * constant string "libcore.io.DiskLruCache", the disk cache's version, + * the application's version, the value count, and a blank line. + * + * Each of the subsequent lines in the file is a record of the state of a + * cache entry. Each line contains space-separated values: a state, a key, + * and optional state-specific values. + * o DIRTY lines track that an entry is actively being created or updated. + * Every successful DIRTY action should be followed by a CLEAN or REMOVE + * action. DIRTY lines without a matching CLEAN or REMOVE indicate that + * temporary files may need to be deleted. + * o CLEAN lines track a cache entry that has been successfully published + * and may be read. A publish line is followed by the lengths of each of + * its values. + * o READ lines track accesses for LRU. + * o REMOVE lines track entries that have been deleted. + * + * The journal file is appended to as cache operations occur. The journal may + * occasionally be compacted by dropping redundant lines. A temporary file named + * "journal.tmp" will be used during compaction; that file should be deleted if + * it exists when the cache is opened. + */ + + private final File directory; + private final File journalFile; + private final File journalFileTmp; + private final File journalFileBackup; + private final int appVersion; + private long maxSize; + private final int valueCount; + private long size = 0; + private Writer journalWriter; + private final LinkedHashMap lruEntries = + new LinkedHashMap(0, 0.75f, true); + private int redundantOpCount; + + /** + * To differentiate between old and current snapshots, each entry is given + * a sequence number each time an edit is committed. A snapshot is stale if + * its sequence number is not equal to its entry's sequence number. + */ + private long nextSequenceNumber = 0; + + /** This cache uses a single background thread to evict entries. */ + final ThreadPoolExecutor executorService = + new ThreadPoolExecutor(0, 1, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue()); + private final Callable cleanupCallable = new Callable() { + public Void call() throws Exception { + synchronized (DiskLruCache.this) { + if (journalWriter == null) { + return null; // Closed. + } + trimToSize(); + if (journalRebuildRequired()) { + rebuildJournal(); + redundantOpCount = 0; + } + } + return null; + } + }; + + private DiskLruCache(File directory, int appVersion, int valueCount, long maxSize) { + this.directory = directory; + this.appVersion = appVersion; + this.journalFile = new File(directory, JOURNAL_FILE); + this.journalFileTmp = new File(directory, JOURNAL_FILE_TEMP); + this.journalFileBackup = new File(directory, JOURNAL_FILE_BACKUP); + this.valueCount = valueCount; + this.maxSize = maxSize; + } + + /** + * Opens the cache in {@code directory}, creating a cache if none exists + * there. + * + * @param directory a writable directory + * @param valueCount the number of values per cache entry. Must be positive. + * @param maxSize the maximum number of bytes this cache should use to store + * @throws IOException if reading or writing the cache directory fails + */ + public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize) + throws IOException { + if (maxSize <= 0) { + throw new IllegalArgumentException("maxSize <= 0"); + } + if (valueCount <= 0) { + throw new IllegalArgumentException("valueCount <= 0"); + } + + // If a bkp file exists, use it instead. + File backupFile = new File(directory, JOURNAL_FILE_BACKUP); + if (backupFile.exists()) { + File journalFile = new File(directory, JOURNAL_FILE); + // If journal file also exists just delete backup file. + if (journalFile.exists()) { + backupFile.delete(); + } else { + renameTo(backupFile, journalFile, false); + } + } + + // Prefer to pick up where we left off. + DiskLruCache cache = new DiskLruCache(directory, appVersion, valueCount, maxSize); + if (cache.journalFile.exists()) { + try { + cache.readJournal(); + cache.processJournal(); + return cache; + } catch (IOException journalIsCorrupt) { + System.out + .println("DiskLruCache " + + directory + + " is corrupt: " + + journalIsCorrupt.getMessage() + + ", removing"); + cache.delete(); + } + } + + // Create a new empty cache. + directory.mkdirs(); + cache = new DiskLruCache(directory, appVersion, valueCount, maxSize); + cache.rebuildJournal(); + return cache; + } + + private void readJournal() throws IOException { + StrictLineReader reader = new StrictLineReader(new FileInputStream(journalFile), Util.US_ASCII); + try { + String magic = reader.readLine(); + String version = reader.readLine(); + String appVersionString = reader.readLine(); + String valueCountString = reader.readLine(); + String blank = reader.readLine(); + if (!MAGIC.equals(magic) + || !VERSION_1.equals(version) + || !Integer.toString(appVersion).equals(appVersionString) + || !Integer.toString(valueCount).equals(valueCountString) + || !"".equals(blank)) { + throw new IOException("unexpected journal header: [" + magic + ", " + version + ", " + + valueCountString + ", " + blank + "]"); + } + + int lineCount = 0; + while (true) { + try { + readJournalLine(reader.readLine()); + lineCount++; + } catch (EOFException endOfJournal) { + break; + } + } + redundantOpCount = lineCount - lruEntries.size(); + + // If we ended on a truncated line, rebuild the journal before appending to it. + if (reader.hasUnterminatedLine()) { + rebuildJournal(); + } else { + journalWriter = new BufferedWriter(new OutputStreamWriter( + new FileOutputStream(journalFile, true), Util.US_ASCII)); + } + } finally { + Util.closeQuietly(reader); + } + } + + private void readJournalLine(String line) throws IOException { + int firstSpace = line.indexOf(' '); + if (firstSpace == -1) { + throw new IOException("unexpected journal line: " + line); + } + + int keyBegin = firstSpace + 1; + int secondSpace = line.indexOf(' ', keyBegin); + final String key; + if (secondSpace == -1) { + key = line.substring(keyBegin); + if (firstSpace == REMOVE.length() && line.startsWith(REMOVE)) { + lruEntries.remove(key); + return; + } + } else { + key = line.substring(keyBegin, secondSpace); + } + + Entry entry = lruEntries.get(key); + if (entry == null) { + entry = new Entry(key); + lruEntries.put(key, entry); + } + + if (secondSpace != -1 && firstSpace == CLEAN.length() && line.startsWith(CLEAN)) { + String[] parts = line.substring(secondSpace + 1).split(" "); + entry.readable = true; + entry.currentEditor = null; + entry.setLengths(parts); + } else if (secondSpace == -1 && firstSpace == DIRTY.length() && line.startsWith(DIRTY)) { + entry.currentEditor = new Editor(entry); + } else if (secondSpace == -1 && firstSpace == READ.length() && line.startsWith(READ)) { + // This work was already done by calling lruEntries.get(). + } else { + throw new IOException("unexpected journal line: " + line); + } + } + + /** + * Computes the initial size and collects garbage as a part of opening the + * cache. Dirty entries are assumed to be inconsistent and will be deleted. + */ + private void processJournal() throws IOException { + deleteIfExists(journalFileTmp); + for (Iterator i = lruEntries.values().iterator(); i.hasNext(); ) { + Entry entry = i.next(); + if (entry.currentEditor == null) { + for (int t = 0; t < valueCount; t++) { + size += entry.lengths[t]; + } + } else { + entry.currentEditor = null; + for (int t = 0; t < valueCount; t++) { + deleteIfExists(entry.getCleanFile(t)); + deleteIfExists(entry.getDirtyFile(t)); + } + i.remove(); + } + } + } + + /** + * Creates a new journal that omits redundant information. This replaces the + * current journal if it exists. + */ + private synchronized void rebuildJournal() throws IOException { + if (journalWriter != null) { + journalWriter.close(); + } + + Writer writer = new BufferedWriter( + new OutputStreamWriter(new FileOutputStream(journalFileTmp), Util.US_ASCII)); + try { + writer.write(MAGIC); + writer.write("\n"); + writer.write(VERSION_1); + writer.write("\n"); + writer.write(Integer.toString(appVersion)); + writer.write("\n"); + writer.write(Integer.toString(valueCount)); + writer.write("\n"); + writer.write("\n"); + + for (Entry entry : lruEntries.values()) { + if (entry.currentEditor != null) { + writer.write(DIRTY + ' ' + entry.key + '\n'); + } else { + writer.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n'); + } + } + } finally { + writer.close(); + } + + if (journalFile.exists()) { + renameTo(journalFile, journalFileBackup, true); + } + renameTo(journalFileTmp, journalFile, false); + journalFileBackup.delete(); + + journalWriter = new BufferedWriter( + new OutputStreamWriter(new FileOutputStream(journalFile, true), Util.US_ASCII)); + } + + private static void deleteIfExists(File file) throws IOException { + if (file.exists() && !file.delete()) { + throw new IOException(); + } + } + + private static void renameTo(File from, File to, boolean deleteDestination) throws IOException { + if (deleteDestination) { + deleteIfExists(to); + } + if (!from.renameTo(to)) { + throw new IOException(); + } + } + + /** + * Returns a snapshot of the entry named {@code key}, or null if it doesn't + * exist is not currently readable. If a value is returned, it is moved to + * the head of the LRU queue. + */ + public synchronized Snapshot get(String key) throws IOException { + checkNotClosed(); + validateKey(key); + Entry entry = lruEntries.get(key); + if (entry == null) { + return null; + } + + if (!entry.readable) { + return null; + } + + // Open all streams eagerly to guarantee that we see a single published + // snapshot. If we opened streams lazily then the streams could come + // from different edits. + InputStream[] ins = new InputStream[valueCount]; + try { + for (int i = 0; i < valueCount; i++) { + ins[i] = new FileInputStream(entry.getCleanFile(i)); + } + } catch (FileNotFoundException e) { + // A file must have been deleted manually! + for (int i = 0; i < valueCount; i++) { + if (ins[i] != null) { + Util.closeQuietly(ins[i]); + } else { + break; + } + } + return null; + } + + redundantOpCount++; + journalWriter.append(READ + ' ' + key + '\n'); + if (journalRebuildRequired()) { + executorService.submit(cleanupCallable); + } + + return new Snapshot(key, entry.sequenceNumber, ins, entry.lengths); + } + + /** + * Returns an editor for the entry named {@code key}, or null if another + * edit is in progress. + */ + public Editor edit(String key) throws IOException { + return edit(key, ANY_SEQUENCE_NUMBER); + } + + private synchronized Editor edit(String key, long expectedSequenceNumber) throws IOException { + checkNotClosed(); + validateKey(key); + Entry entry = lruEntries.get(key); + if (expectedSequenceNumber != ANY_SEQUENCE_NUMBER && (entry == null + || entry.sequenceNumber != expectedSequenceNumber)) { + return null; // Snapshot is stale. + } + if (entry == null) { + entry = new Entry(key); + lruEntries.put(key, entry); + } else if (entry.currentEditor != null) { + return null; // Another edit is in progress. + } + + Editor editor = new Editor(entry); + entry.currentEditor = editor; + + // Flush the journal before creating files to prevent file leaks. + journalWriter.write(DIRTY + ' ' + key + '\n'); + journalWriter.flush(); + return editor; + } + + /** Returns the directory where this cache stores its data. */ + public File getDirectory() { + return directory; + } + + /** + * Returns the maximum number of bytes that this cache should use to store + * its data. + */ + public synchronized long getMaxSize() { + return maxSize; + } + + /** + * Changes the maximum number of bytes the cache can store and queues a job + * to trim the existing store, if necessary. + */ + public synchronized void setMaxSize(long maxSize) { + this.maxSize = maxSize; + executorService.submit(cleanupCallable); + } + + /** + * Returns the number of bytes currently being used to store the values in + * this cache. This may be greater than the max size if a background + * deletion is pending. + */ + public synchronized long size() { + return size; + } + + private synchronized void completeEdit(Editor editor, boolean success) throws IOException { + Entry entry = editor.entry; + if (entry.currentEditor != editor) { + throw new IllegalStateException(); + } + + // If this edit is creating the entry for the first time, every index must have a value. + if (success && !entry.readable) { + for (int i = 0; i < valueCount; i++) { + if (!editor.written[i]) { + editor.abort(); + throw new IllegalStateException("Newly created entry didn't create value for index " + i); + } + if (!entry.getDirtyFile(i).exists()) { + editor.abort(); + return; + } + } + } + + for (int i = 0; i < valueCount; i++) { + File dirty = entry.getDirtyFile(i); + if (success) { + if (dirty.exists()) { + File clean = entry.getCleanFile(i); + dirty.renameTo(clean); + long oldLength = entry.lengths[i]; + long newLength = clean.length(); + entry.lengths[i] = newLength; + size = size - oldLength + newLength; + } + } else { + deleteIfExists(dirty); + } + } + + redundantOpCount++; + entry.currentEditor = null; + if (entry.readable | success) { + entry.readable = true; + journalWriter.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n'); + if (success) { + entry.sequenceNumber = nextSequenceNumber++; + } + } else { + lruEntries.remove(entry.key); + journalWriter.write(REMOVE + ' ' + entry.key + '\n'); + } + journalWriter.flush(); + + if (size > maxSize || journalRebuildRequired()) { + executorService.submit(cleanupCallable); + } + } + + /** + * We only rebuild the journal when it will halve the size of the journal + * and eliminate at least 2000 ops. + */ + private boolean journalRebuildRequired() { + final int redundantOpCompactThreshold = 2000; + return redundantOpCount >= redundantOpCompactThreshold // + && redundantOpCount >= lruEntries.size(); + } + + /** + * Drops the entry for {@code key} if it exists and can be removed. Entries + * actively being edited cannot be removed. + * + * @return true if an entry was removed. + */ + public synchronized boolean remove(String key) throws IOException { + checkNotClosed(); + validateKey(key); + Entry entry = lruEntries.get(key); + if (entry == null || entry.currentEditor != null) { + return false; + } + + for (int i = 0; i < valueCount; i++) { + File file = entry.getCleanFile(i); + if (file.exists() && !file.delete()) { + throw new IOException("failed to delete " + file); + } + size -= entry.lengths[i]; + entry.lengths[i] = 0; + } + + redundantOpCount++; + journalWriter.append(REMOVE + ' ' + key + '\n'); + lruEntries.remove(key); + + if (journalRebuildRequired()) { + executorService.submit(cleanupCallable); + } + + return true; + } + + /** Returns true if this cache has been closed. */ + public synchronized boolean isClosed() { + return journalWriter == null; + } + + private void checkNotClosed() { + if (journalWriter == null) { + throw new IllegalStateException("cache is closed"); + } + } + + /** Force buffered operations to the filesystem. */ + public synchronized void flush() throws IOException { + checkNotClosed(); + trimToSize(); + journalWriter.flush(); + } + + /** Closes this cache. Stored values will remain on the filesystem. */ + public synchronized void close() throws IOException { + if (journalWriter == null) { + return; // Already closed. + } + for (Entry entry : new ArrayList(lruEntries.values())) { + if (entry.currentEditor != null) { + entry.currentEditor.abort(); + } + } + trimToSize(); + journalWriter.close(); + journalWriter = null; + } + + private void trimToSize() throws IOException { + while (size > maxSize) { + Map.Entry toEvict = lruEntries.entrySet().iterator().next(); + remove(toEvict.getKey()); + } + } + + /** + * Closes the cache and deletes all of its stored values. This will delete + * all files in the cache directory including files that weren't created by + * the cache. + */ + public void delete() throws IOException { + close(); + Util.deleteContents(directory); + } + + private void validateKey(String key) { + Matcher matcher = LEGAL_KEY_PATTERN.matcher(key); + if (!matcher.matches()) { + throw new IllegalArgumentException("keys must match regex " + + STRING_KEY_PATTERN + ": \"" + key + "\""); + } + } + + private static String inputStreamToString(InputStream in) throws IOException { + return Util.readFully(new InputStreamReader(in, Util.UTF_8)); + } + + /** A snapshot of the values for an entry. */ + public final class Snapshot implements Closeable { + private final String key; + private final long sequenceNumber; + private final InputStream[] ins; + private final long[] lengths; + + private Snapshot(String key, long sequenceNumber, InputStream[] ins, long[] lengths) { + this.key = key; + this.sequenceNumber = sequenceNumber; + this.ins = ins; + this.lengths = lengths; + } + + /** + * Returns an editor for this snapshot's entry, or null if either the + * entry has changed since this snapshot was created or if another edit + * is in progress. + */ + public Editor edit() throws IOException { + return DiskLruCache.this.edit(key, sequenceNumber); + } + + /** Returns the unbuffered stream with the value for {@code index}. */ + public InputStream getInputStream(int index) { + return ins[index]; + } + + /** Returns the string value for {@code index}. */ + public String getString(int index) throws IOException { + return inputStreamToString(getInputStream(index)); + } + + /** Returns the byte length of the value for {@code index}. */ + public long getLength(int index) { + return lengths[index]; + } + + public void close() { + for (InputStream in : ins) { + Util.closeQuietly(in); + } + } + } + + private static final OutputStream NULL_OUTPUT_STREAM = new OutputStream() { + @Override + public void write(int b) throws IOException { + // Eat all writes silently. Nom nom. + } + }; + + /** Edits the values for an entry. */ + public final class Editor { + private final Entry entry; + private final boolean[] written; + private boolean hasErrors; + private boolean committed; + + private Editor(Entry entry) { + this.entry = entry; + this.written = (entry.readable) ? null : new boolean[valueCount]; + } + + /** + * Returns an unbuffered input stream to read the last committed value, + * or null if no value has been committed. + */ + public InputStream newInputStream(int index) throws IOException { + synchronized (DiskLruCache.this) { + if (entry.currentEditor != this) { + throw new IllegalStateException(); + } + if (!entry.readable) { + return null; + } + try { + return new FileInputStream(entry.getCleanFile(index)); + } catch (FileNotFoundException e) { + return null; + } + } + } + + /** + * Returns the last committed value as a string, or null if no value + * has been committed. + */ + public String getString(int index) throws IOException { + InputStream in = newInputStream(index); + return in != null ? inputStreamToString(in) : null; + } + + /** + * Returns a new unbuffered output stream to write the value at + * {@code index}. If the underlying output stream encounters errors + * when writing to the filesystem, this edit will be aborted when + * {@link #commit} is called. The returned output stream does not throw + * IOExceptions. + */ + public OutputStream newOutputStream(int index) throws IOException { + if (index < 0 || index >= valueCount) { + throw new IllegalArgumentException("Expected index " + index + " to " + + "be greater than 0 and less than the maximum value count " + + "of " + valueCount); + } + synchronized (DiskLruCache.this) { + if (entry.currentEditor != this) { + throw new IllegalStateException(); + } + if (!entry.readable) { + written[index] = true; + } + File dirtyFile = entry.getDirtyFile(index); + FileOutputStream outputStream; + try { + outputStream = new FileOutputStream(dirtyFile); + } catch (FileNotFoundException e) { + // Attempt to recreate the cache directory. + directory.mkdirs(); + try { + outputStream = new FileOutputStream(dirtyFile); + } catch (FileNotFoundException e2) { + // We are unable to recover. Silently eat the writes. + return NULL_OUTPUT_STREAM; + } + } + return new FaultHidingOutputStream(outputStream); + } + } + + /** Sets the value at {@code index} to {@code value}. */ + public void set(int index, String value) throws IOException { + Writer writer = null; + try { + writer = new OutputStreamWriter(newOutputStream(index), Util.UTF_8); + writer.write(value); + } finally { + Util.closeQuietly(writer); + } + } + + /** + * Commits this edit so it is visible to readers. This releases the + * edit lock so another edit may be started on the same key. + */ + public void commit() throws IOException { + if (hasErrors) { + completeEdit(this, false); + remove(entry.key); // The previous entry is stale. + } else { + completeEdit(this, true); + } + committed = true; + } + + /** + * Aborts this edit. This releases the edit lock so another edit may be + * started on the same key. + */ + public void abort() throws IOException { + completeEdit(this, false); + } + + public void abortUnlessCommitted() { + if (!committed) { + try { + abort(); + } catch (IOException ignored) { + } + } + } + + private class FaultHidingOutputStream extends FilterOutputStream { + private FaultHidingOutputStream(OutputStream out) { + super(out); + } + + @Override public void write(int oneByte) { + try { + out.write(oneByte); + } catch (IOException e) { + hasErrors = true; + } + } + + @Override public void write(byte[] buffer, int offset, int length) { + try { + out.write(buffer, offset, length); + } catch (IOException e) { + hasErrors = true; + } + } + + @Override public void close() { + try { + out.close(); + } catch (IOException e) { + hasErrors = true; + } + } + + @Override public void flush() { + try { + out.flush(); + } catch (IOException e) { + hasErrors = true; + } + } + } + } + + private final class Entry { + private final String key; + + /** Lengths of this entry's files. */ + private final long[] lengths; + + /** True if this entry has ever been published. */ + private boolean readable; + + /** The ongoing edit or null if this entry is not being edited. */ + private Editor currentEditor; + + /** The sequence number of the most recently committed edit to this entry. */ + private long sequenceNumber; + + private Entry(String key) { + this.key = key; + this.lengths = new long[valueCount]; + } + + public String getLengths() throws IOException { + StringBuilder result = new StringBuilder(); + for (long size : lengths) { + result.append(' ').append(size); + } + return result.toString(); + } + + /** Set lengths using decimal numbers like "10123". */ + private void setLengths(String[] strings) throws IOException { + if (strings.length != valueCount) { + throw invalidLengths(strings); + } + + try { + for (int i = 0; i < strings.length; i++) { + lengths[i] = Long.parseLong(strings[i]); + } + } catch (NumberFormatException e) { + throw invalidLengths(strings); + } + } + + private IOException invalidLengths(String[] strings) throws IOException { + throw new IOException("unexpected journal line: " + java.util.Arrays.toString(strings)); + } + + public File getCleanFile(int i) { + return new File(directory, key + "." + i); + } + + public File getDirtyFile(int i) { + return new File(directory, key + "." + i + ".tmp"); + } + } +} diff --git a/app/src/main/java/com/tdkankan/libcore/io/StrictLineReader.java b/app/src/main/java/com/tdkankan/libcore/io/StrictLineReader.java new file mode 100644 index 0000000..2175ede --- /dev/null +++ b/app/src/main/java/com/tdkankan/libcore/io/StrictLineReader.java @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.tdkankan.libcore.io; + +import java.io.ByteArrayOutputStream; +import java.io.Closeable; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; + +/** + * Buffers input from an {@link InputStream} for reading lines. + * + *

This class is used for buffered reading of lines. For purposes of this class, a line ends + * with "\n" or "\r\n". End of input is reported by throwing {@code EOFException}. Unterminated + * line at end of input is invalid and will be ignored, the caller may use {@code + * hasUnterminatedLine()} to detect it after catching the {@code EOFException}. + * + *

This class is intended for reading input that strictly consists of lines, such as line-based + * cache entries or cache journal. Unlike the {@link java.io.BufferedReader} which in conjunction + * with {@link java.io.InputStreamReader} provides similar functionality, this class uses different + * end-of-input reporting and a more restrictive definition of a line. + * + *

This class supports only charsets that encode '\r' and '\n' as a single byte with value 13 + * and 10, respectively, and the representation of no other character contains these values. + * We currently check in constructor that the charset is one of US-ASCII, UTF-8 and ISO-8859-1. + * The default charset is US_ASCII. + */ +class StrictLineReader implements Closeable { + private static final byte CR = (byte) '\r'; + private static final byte LF = (byte) '\n'; + + private final InputStream in; + private final Charset charset; + + /* + * Buffered data is stored in {@code buf}. As long as no exception occurs, 0 <= pos <= end + * and the data in the range [pos, end) is buffered for reading. At end of input, if there is + * an unterminated line, we set end == -1, otherwise end == pos. If the underlying + * {@code InputStream} throws an {@code IOException}, end may remain as either pos or -1. + */ + private byte[] buf; + private int pos; + private int end; + + /** + * Constructs a new {@code LineReader} with the specified charset and the default capacity. + * + * @param in the {@code InputStream} to read data from. + * @param charset the charset used to decode data. Only US-ASCII, UTF-8 and ISO-8859-1 are + * supported. + * @throws NullPointerException if {@code in} or {@code charset} is null. + * @throws IllegalArgumentException if the specified charset is not supported. + */ + public StrictLineReader(InputStream in, Charset charset) { + this(in, 8192, charset); + } + + /** + * Constructs a new {@code LineReader} with the specified capacity and charset. + * + * @param in the {@code InputStream} to read data from. + * @param capacity the capacity of the buffer. + * @param charset the charset used to decode data. Only US-ASCII, UTF-8 and ISO-8859-1 are + * supported. + * @throws NullPointerException if {@code in} or {@code charset} is null. + * @throws IllegalArgumentException if {@code capacity} is negative or zero + * or the specified charset is not supported. + */ + public StrictLineReader(InputStream in, int capacity, Charset charset) { + if (in == null || charset == null) { + throw new NullPointerException(); + } + if (capacity < 0) { + throw new IllegalArgumentException("capacity <= 0"); + } + if (!(charset.equals(Util.US_ASCII))) { + throw new IllegalArgumentException("Unsupported encoding"); + } + + this.in = in; + this.charset = charset; + buf = new byte[capacity]; + } + + /** + * Closes the reader by closing the underlying {@code InputStream} and + * marking this reader as closed. + * + * @throws IOException for errors when closing the underlying {@code InputStream}. + */ + public void close() throws IOException { + synchronized (in) { + if (buf != null) { + buf = null; + in.close(); + } + } + } + + /** + * Reads the next line. A line ends with {@code "\n"} or {@code "\r\n"}, + * this end of line marker is not included in the result. + * + * @return the next line from the input. + * @throws IOException for underlying {@code InputStream} errors. + * @throws EOFException for the end of source stream. + */ + public String readLine() throws IOException { + synchronized (in) { + if (buf == null) { + throw new IOException("LineReader is closed"); + } + + // Read more data if we are at the end of the buffered data. + // Though it's an error to read after an exception, we will let {@code fillBuf()} + // throw again if that happens; thus we need to handle end == -1 as well as end == pos. + if (pos >= end) { + fillBuf(); + } + // Try to find LF in the buffered data and return the line if successful. + for (int i = pos; i != end; ++i) { + if (buf[i] == LF) { + int lineEnd = (i != pos && buf[i - 1] == CR) ? i - 1 : i; + String res = new String(buf, pos, lineEnd - pos, charset.name()); + pos = i + 1; + return res; + } + } + + // Let's anticipate up to 80 characters on top of those already read. + ByteArrayOutputStream out = new ByteArrayOutputStream(end - pos + 80) { + @Override + public String toString() { + int length = (count > 0 && buf[count - 1] == CR) ? count - 1 : count; + try { + return new String(buf, 0, length, charset.name()); + } catch (UnsupportedEncodingException e) { + throw new AssertionError(e); // Since we control the charset this will never happen. + } + } + }; + + while (true) { + out.write(buf, pos, end - pos); + // Mark unterminated line in case fillBuf throws EOFException or IOException. + end = -1; + fillBuf(); + // Try to find LF in the buffered data and return the line if successful. + for (int i = pos; i != end; ++i) { + if (buf[i] == LF) { + if (i != pos) { + out.write(buf, pos, i - pos); + } + pos = i + 1; + return out.toString(); + } + } + } + } + } + + public boolean hasUnterminatedLine() { + return end == -1; + } + + /** + * Reads new input data into the buffer. Call only with pos == end or end == -1, + * depending on the desired outcome if the function throws. + */ + private void fillBuf() throws IOException { + int result = in.read(buf, 0, buf.length); + if (result == -1) { + throw new EOFException(); + } + pos = 0; + end = result; + } +} + diff --git a/app/src/main/java/com/tdkankan/libcore/io/Util.java b/app/src/main/java/com/tdkankan/libcore/io/Util.java new file mode 100644 index 0000000..1ce8457 --- /dev/null +++ b/app/src/main/java/com/tdkankan/libcore/io/Util.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.tdkankan.libcore.io; + +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.io.Reader; +import java.io.StringWriter; +import java.nio.charset.Charset; + +/** Junk drawer of utility methods. */ +final class Util { + static final Charset US_ASCII = Charset.forName("US-ASCII"); + static final Charset UTF_8 = Charset.forName("UTF-8"); + + private Util() { + } + + static String readFully(Reader reader) throws IOException { + try { + StringWriter writer = new StringWriter(); + char[] buffer = new char[1024]; + int count; + while ((count = reader.read(buffer)) != -1) { + writer.write(buffer, 0, count); + } + return writer.toString(); + } finally { + reader.close(); + } + } + + /** + * Deletes the contents of {@code dir}. Throws an IOException if any file + * could not be deleted, or if {@code dir} is not a readable directory. + */ + static void deleteContents(File dir) throws IOException { + File[] files = dir.listFiles(); + if (files == null) { + throw new IOException("not a readable directory: " + dir); + } + for (File file : files) { + if (file.isDirectory()) { + deleteContents(file); + } + if (!file.delete()) { + throw new IOException("failed to delete file: " + file); + } + } + } + + static void closeQuietly(/*Auto*/Closeable closeable) { + if (closeable != null) { + try { + closeable.close(); + } catch (RuntimeException rethrown) { + throw rethrown; + } catch (Exception ignored) { + } + } + } +} diff --git a/app/src/main/res/anim/fade_in.xml b/app/src/main/res/anim/fade_in.xml new file mode 100644 index 0000000..14c3d3d --- /dev/null +++ b/app/src/main/res/anim/fade_in.xml @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/fade_out.xml b/app/src/main/res/anim/fade_out.xml new file mode 100644 index 0000000..3e7d894 --- /dev/null +++ b/app/src/main/res/anim/fade_out.xml @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/fading_in.xml b/app/src/main/res/anim/fading_in.xml new file mode 100644 index 0000000..3730083 --- /dev/null +++ b/app/src/main/res/anim/fading_in.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/fading_out.xml b/app/src/main/res/anim/fading_out.xml new file mode 100644 index 0000000..e063f1a --- /dev/null +++ b/app/src/main/res/anim/fading_out.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-anydpi/ic_action_add_icon.xml b/app/src/main/res/drawable-anydpi/ic_action_add_icon.xml new file mode 100644 index 0000000..fa79705 --- /dev/null +++ b/app/src/main/res/drawable-anydpi/ic_action_add_icon.xml @@ -0,0 +1,11 @@ + + + diff --git a/app/src/main/res/drawable-anydpi/ic_action_bookmark.xml b/app/src/main/res/drawable-anydpi/ic_action_bookmark.xml new file mode 100644 index 0000000..530f464 --- /dev/null +++ b/app/src/main/res/drawable-anydpi/ic_action_bookmark.xml @@ -0,0 +1,11 @@ + + + diff --git a/app/src/main/res/drawable-anydpi/ic_action_play_arrow.xml b/app/src/main/res/drawable-anydpi/ic_action_play_arrow.xml new file mode 100644 index 0000000..420941a --- /dev/null +++ b/app/src/main/res/drawable-anydpi/ic_action_play_arrow.xml @@ -0,0 +1,11 @@ + + + diff --git a/app/src/main/res/drawable-anydpi/ic_action_search_icon.xml b/app/src/main/res/drawable-anydpi/ic_action_search_icon.xml new file mode 100644 index 0000000..afb0429 --- /dev/null +++ b/app/src/main/res/drawable-anydpi/ic_action_search_icon.xml @@ -0,0 +1,11 @@ + + + diff --git a/app/src/main/res/drawable-hdpi/ic_action_add_icon.png b/app/src/main/res/drawable-hdpi/ic_action_add_icon.png new file mode 100644 index 0000000..2b125f5 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_action_add_icon.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_action_bookmark.png b/app/src/main/res/drawable-hdpi/ic_action_bookmark.png new file mode 100644 index 0000000..702b318 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_action_bookmark.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_action_play_arrow.png b/app/src/main/res/drawable-hdpi/ic_action_play_arrow.png new file mode 100644 index 0000000..556c872 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_action_play_arrow.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_action_search_icon.png b/app/src/main/res/drawable-hdpi/ic_action_search_icon.png new file mode 100644 index 0000000..f9c0afe Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_action_search_icon.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_action_add_icon.png b/app/src/main/res/drawable-mdpi/ic_action_add_icon.png new file mode 100644 index 0000000..a69d739 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_action_add_icon.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_action_bookmark.png b/app/src/main/res/drawable-mdpi/ic_action_bookmark.png new file mode 100644 index 0000000..de05c1e Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_action_bookmark.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_action_play_arrow.png b/app/src/main/res/drawable-mdpi/ic_action_play_arrow.png new file mode 100644 index 0000000..2b42577 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_action_play_arrow.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_action_search_icon.png b/app/src/main/res/drawable-mdpi/ic_action_search_icon.png new file mode 100644 index 0000000..6fd5a13 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_action_search_icon.png differ diff --git a/app/src/main/res/drawable-mdpi/radius_30_white.xml b/app/src/main/res/drawable-mdpi/radius_30_white.xml new file mode 100644 index 0000000..dee1290 --- /dev/null +++ b/app/src/main/res/drawable-mdpi/radius_30_white.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..1f6bb29 --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable-xhdpi/ic_action_add_icon.png b/app/src/main/res/drawable-xhdpi/ic_action_add_icon.png new file mode 100644 index 0000000..4423088 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_action_add_icon.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_action_bookmark.png b/app/src/main/res/drawable-xhdpi/ic_action_bookmark.png new file mode 100644 index 0000000..981273d Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_action_bookmark.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_action_play_arrow.png b/app/src/main/res/drawable-xhdpi/ic_action_play_arrow.png new file mode 100644 index 0000000..7770ab2 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_action_play_arrow.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_action_search_icon.png b/app/src/main/res/drawable-xhdpi/ic_action_search_icon.png new file mode 100644 index 0000000..aad212c Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_action_search_icon.png differ diff --git a/app/src/main/res/drawable-xhdpi/setting_blue_deep_style_btn_bg.xml b/app/src/main/res/drawable-xhdpi/setting_blue_deep_style_btn_bg.xml new file mode 100644 index 0000000..03044ce --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/setting_blue_deep_style_btn_bg.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-xhdpi/setting_breen_style_btn_bg.xml b/app/src/main/res/drawable-xhdpi/setting_breen_style_btn_bg.xml new file mode 100644 index 0000000..23df42d --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/setting_breen_style_btn_bg.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-xhdpi/setting_common_style_btn_bg.xml b/app/src/main/res/drawable-xhdpi/setting_common_style_btn_bg.xml new file mode 100644 index 0000000..a055eb1 --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/setting_common_style_btn_bg.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-xhdpi/setting_leather_style_btn_bg.xml b/app/src/main/res/drawable-xhdpi/setting_leather_style_btn_bg.xml new file mode 100644 index 0000000..affb285 --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/setting_leather_style_btn_bg.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-xhdpi/setting_protect_eye_style_btn_bg.xml b/app/src/main/res/drawable-xhdpi/setting_protect_eye_style_btn_bg.xml new file mode 100644 index 0000000..37c9226 --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/setting_protect_eye_style_btn_bg.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-xhdpi/setting_style_blue_deep_circle.xml b/app/src/main/res/drawable-xhdpi/setting_style_blue_deep_circle.xml new file mode 100644 index 0000000..2825928 --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/setting_style_blue_deep_circle.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-xhdpi/setting_style_blue_deep_circle_selected.xml b/app/src/main/res/drawable-xhdpi/setting_style_blue_deep_circle_selected.xml new file mode 100644 index 0000000..4b170f2 --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/setting_style_blue_deep_circle_selected.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-xhdpi/setting_style_breen_circle.xml b/app/src/main/res/drawable-xhdpi/setting_style_breen_circle.xml new file mode 100644 index 0000000..6c0b696 --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/setting_style_breen_circle.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-xhdpi/setting_style_breen_circle_selected.xml b/app/src/main/res/drawable-xhdpi/setting_style_breen_circle_selected.xml new file mode 100644 index 0000000..d5db6a4 --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/setting_style_breen_circle_selected.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-xhdpi/setting_style_common_circle.xml b/app/src/main/res/drawable-xhdpi/setting_style_common_circle.xml new file mode 100644 index 0000000..e23c3f0 --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/setting_style_common_circle.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-xhdpi/setting_style_common_circle_selected.xml b/app/src/main/res/drawable-xhdpi/setting_style_common_circle_selected.xml new file mode 100644 index 0000000..b6a6165 --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/setting_style_common_circle_selected.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-xhdpi/setting_style_leather_circle.xml b/app/src/main/res/drawable-xhdpi/setting_style_leather_circle.xml new file mode 100644 index 0000000..f300a09 --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/setting_style_leather_circle.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-xhdpi/setting_style_leather_circle_selected.xml b/app/src/main/res/drawable-xhdpi/setting_style_leather_circle_selected.xml new file mode 100644 index 0000000..a75c56a --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/setting_style_leather_circle_selected.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-xhdpi/setting_style_protect_eye_circle.xml b/app/src/main/res/drawable-xhdpi/setting_style_protect_eye_circle.xml new file mode 100644 index 0000000..607998f --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/setting_style_protect_eye_circle.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-xhdpi/setting_style_protect_eye_circle_selected.xml b/app/src/main/res/drawable-xhdpi/setting_style_protect_eye_circle_selected.xml new file mode 100644 index 0000000..75e89fe --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/setting_style_protect_eye_circle_selected.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_add_icon.png b/app/src/main/res/drawable-xxhdpi/ic_action_add_icon.png new file mode 100644 index 0000000..94b04c8 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_action_add_icon.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_bookmark.png b/app/src/main/res/drawable-xxhdpi/ic_action_bookmark.png new file mode 100644 index 0000000..25708bb Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_action_bookmark.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_play_arrow.png b/app/src/main/res/drawable-xxhdpi/ic_action_play_arrow.png new file mode 100644 index 0000000..0e5abef Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_action_play_arrow.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_search_icon.png b/app/src/main/res/drawable-xxhdpi/ic_action_search_icon.png new file mode 100644 index 0000000..64b54ca Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_action_search_icon.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/setting_btn_bg.xml b/app/src/main/res/drawable-xxxhdpi/setting_btn_bg.xml new file mode 100644 index 0000000..4cef809 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/setting_btn_bg.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-xxxhdpi/setting_btn_bg1.xml b/app/src/main/res/drawable-xxxhdpi/setting_btn_bg1.xml new file mode 100644 index 0000000..3348b73 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/setting_btn_bg1.xml @@ -0,0 +1,13 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-xxxhdpi/setting_btn_bg2.xml b/app/src/main/res/drawable-xxxhdpi/setting_btn_bg2.xml new file mode 100644 index 0000000..2d2ea5c --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/setting_btn_bg2.xml @@ -0,0 +1,14 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-xxxhdpi/setting_btn_bg_color.xml b/app/src/main/res/drawable-xxxhdpi/setting_btn_bg_color.xml new file mode 100644 index 0000000..cec4b6e --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/setting_btn_bg_color.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-xxxhdpi/setting_circle.xml b/app/src/main/res/drawable-xxxhdpi/setting_circle.xml new file mode 100644 index 0000000..128b945 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/setting_circle.xml @@ -0,0 +1,13 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/filled_activity_bg.xml b/app/src/main/res/drawable/filled_activity_bg.xml new file mode 100644 index 0000000..0291bd6 --- /dev/null +++ b/app/src/main/res/drawable/filled_activity_bg.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/filled_box.xml b/app/src/main/res/drawable/filled_box.xml new file mode 100644 index 0000000..e776cc0 --- /dev/null +++ b/app/src/main/res/drawable/filled_box.xml @@ -0,0 +1,11 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..0d025f9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/jay_icon.JPG b/app/src/main/res/drawable/jay_icon.JPG new file mode 100644 index 0000000..ce32488 Binary files /dev/null and b/app/src/main/res/drawable/jay_icon.JPG differ diff --git a/app/src/main/res/drawable/nonepic.jpg b/app/src/main/res/drawable/nonepic.jpg new file mode 100644 index 0000000..6ef89d6 Binary files /dev/null and b/app/src/main/res/drawable/nonepic.jpg differ diff --git a/app/src/main/res/drawable/openbp.jpg b/app/src/main/res/drawable/openbp.jpg new file mode 100644 index 0000000..af360f9 Binary files /dev/null and b/app/src/main/res/drawable/openbp.jpg differ diff --git a/app/src/main/res/drawable/openbp2.jpg b/app/src/main/res/drawable/openbp2.jpg new file mode 100644 index 0000000..ad3f82e Binary files /dev/null and b/app/src/main/res/drawable/openbp2.jpg differ diff --git a/app/src/main/res/drawable/radius_30_book_bg.xml b/app/src/main/res/drawable/radius_30_book_bg.xml new file mode 100644 index 0000000..385eda0 --- /dev/null +++ b/app/src/main/res/drawable/radius_30_book_bg.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/seekbar_bg.xml b/app/src/main/res/drawable/seekbar_bg.xml new file mode 100644 index 0000000..17b4047 --- /dev/null +++ b/app/src/main/res/drawable/seekbar_bg.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_label_orange.xml b/app/src/main/res/drawable/shape_label_orange.xml new file mode 100644 index 0000000..90196fa --- /dev/null +++ b/app/src/main/res/drawable/shape_label_orange.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_bookcity.xml b/app/src/main/res/layout/activity_bookcity.xml new file mode 100644 index 0000000..0276e5c --- /dev/null +++ b/app/src/main/res/layout/activity_bookcity.xml @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_bookcity_topfragment.xml b/app/src/main/res/layout/activity_bookcity_topfragment.xml new file mode 100644 index 0000000..2a0c0ae --- /dev/null +++ b/app/src/main/res/layout/activity_bookcity_topfragment.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_bookcity_typefragment.xml b/app/src/main/res/layout/activity_bookcity_typefragment.xml new file mode 100644 index 0000000..b14ecaa --- /dev/null +++ b/app/src/main/res/layout/activity_bookcity_typefragment.xml @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_bookinfodetail.xml b/app/src/main/res/layout/activity_bookinfodetail.xml new file mode 100644 index 0000000..9d4890c --- /dev/null +++ b/app/src/main/res/layout/activity_bookinfodetail.xml @@ -0,0 +1,183 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +