From b9561d92d57af933ffbb08014c23931da5a556c2 Mon Sep 17 00:00:00 2001 From: MewX Date: Mon, 11 Jun 2018 14:01:25 +0930 Subject: [PATCH 1/6] Closes #21 Added new version checker and self-implemented notice --- .../LightNovelLibrary/app/proguard-rules.pro | 15 +- .../app/src/main/AndroidManifest.xml | 9 +- .../mewx/wenku8/activity/MainActivity.java | 195 +++++++++--- .../mewx/wenku8/fragment/ConfigFragment.java | 286 +++++++++--------- .../org/mewx/wenku8/fragment/FavFragment.java | 3 - .../fragment/NavigationDrawerFragment.java | 4 +- .../org/mewx/wenku8/global/GlobalConfig.java | 31 +- .../org/mewx/wenku8/global/api/Wenku8API.java | 8 - .../src/main/res/values-zh-rHK/strings.xml | 2 + .../src/main/res/values-zh-rTW/strings.xml | 2 + .../app/src/main/res/values/strings.xml | 1 + 11 files changed, 340 insertions(+), 216 deletions(-) diff --git a/studio-android/LightNovelLibrary/app/proguard-rules.pro b/studio-android/LightNovelLibrary/app/proguard-rules.pro index 61a7babb..a006a766 100644 --- a/studio-android/LightNovelLibrary/app/proguard-rules.pro +++ b/studio-android/LightNovelLibrary/app/proguard-rules.pro @@ -89,16 +89,15 @@ -keepclassmembers class * implements java.io.Serializable { *; } # umeng self --dontwarn com.umeng.** --keep public class * extends com.umeng.** --keep class com.umeng.** { *; } --keep class com.alimama.** { *; } --keep public class com.umeng.fb.ui.ThreadView { } - -# umeng reflection +-keep class com.umeng.** {*;} -keepclassmembers class * { - public (org.json.JSONObject); + public (org.json.JSONObject); +} +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); } + -keep public class org.mewx.wenku8.R$* { public static final int *; } diff --git a/studio-android/LightNovelLibrary/app/src/main/AndroidManifest.xml b/studio-android/LightNovelLibrary/app/src/main/AndroidManifest.xml index 9ec17da2..ad78abea 100644 --- a/studio-android/LightNovelLibrary/app/src/main/AndroidManifest.xml +++ b/studio-android/LightNovelLibrary/app/src/main/AndroidManifest.xml @@ -12,6 +12,7 @@ + @@ -31,14 +32,6 @@ - - - - = Build.VERSION_CODES.JELLY_BEAN) { + hasPermission = (ContextCompat.checkSelfPermission(this, + Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED); + if (!hasPermission) { + ActivityCompat.requestPermissions(this, + new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, REQUEST_READ_EXTERNAL); + } } // execute background action @@ -89,6 +115,9 @@ private void initialApp() { LightUserSession.aiui.execute(); GlobalConfig.loadAllSetting(); + // check new version and load notice text + Wenku8API.NoticeString = GlobalConfig.loadSavedNotice(); + // create save folder LightCache.saveFile(GlobalConfig.getFirstStoragePath() + "imgs", ".nomedia", "".getBytes(), false); LightCache.saveFile(GlobalConfig.getSecondStoragePath() + "imgs", ".nomedia", "".getBytes(), false); @@ -107,45 +136,42 @@ protected void onCreate(Bundle savedInstanceState) { initialApp(); // UIL setting - if(ImageLoader.getInstance() == null || !ImageLoader.getInstance().isInited()) { + if (ImageLoader.getInstance() == null || !ImageLoader.getInstance().isInited()) { GlobalConfig.initImageLoader(this); } // global settings GlobalConfig.initVolleyNetwork(); - // UMeng settings - OnlineConfigAgent.getInstance().updateOnlineConfig(this); + // UMeng initialization + UMConfigure.init(MyApp.getContext(), UMConfigure.DEVICE_TYPE_PHONE, null); // Update old save files ---------------- // set Toolbar - Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar_actionbar); + Toolbar mToolbar = findViewById(R.id.toolbar_actionbar); setSupportActionBar(mToolbar); // getSupportActionBar().setDisplayShowHomeEnabled(true); // set Tool button mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.fragment_drawer); - mNavigationDrawerFragment.setup(R.id.fragment_drawer, (DrawerLayout) findViewById(R.id.drawer), mToolbar); + mNavigationDrawerFragment.setup(R.id.fragment_drawer, findViewById(R.id.drawer), mToolbar); // find search box - mToolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() { - @Override - public boolean onMenuItemClick(MenuItem item) { - //Toast.makeText(MyApp.getContext(),"called button",Toast.LENGTH_SHORT).show(); - if (item.getItemId() == R.id.action_search) { - // start search activity - startActivity(new Intent(MainActivity.this, SearchActivity.class)); - overridePendingTransition(R.anim.fade_in, R.anim.hold); // fade in animation + mToolbar.setOnMenuItemClickListener(item -> { + //Toast.makeText(MyApp.getContext(),"called button",Toast.LENGTH_SHORT).show(); + if (item.getItemId() == R.id.action_search) { + // start search activity + startActivity(new Intent(MainActivity.this, SearchActivity.class)); + overridePendingTransition(R.anim.fade_in, R.anim.hold); // fade in animation - } - return true; } + return true; }); // change status bar color tint, and this require SDK16 - if (Build.VERSION.SDK_INT >= 16 ) { //&& Build.VERSION.SDK_INT <= 21) { + if (Build.VERSION.SDK_INT >= 16) { //&& Build.VERSION.SDK_INT <= 21) { // Android API 22 has more effects on status bar, so ignore // create our manager instance after the content view is set @@ -158,7 +184,7 @@ public boolean onMenuItemClick(MenuItem item) { // set all color tintManager.setTintColor(getResources().getColor(android.R.color.black)); // set Navigation bar color - if(Build.VERSION.SDK_INT >= 21) + if (Build.VERSION.SDK_INT >= 21) getWindow().setNavigationBarColor(getResources().getColor(R.color.myNavigationColor)); } } @@ -176,26 +202,29 @@ public boolean onMenuItemClick(MenuItem item) { public boolean onCreateOptionsMenu(Menu menu) { // only when the navigation draw closed, I draw the menu bar. // the menu items will be drawn automatically - if(!mNavigationDrawerFragment.isDrawerOpen()) { + if (!mNavigationDrawerFragment.isDrawerOpen()) { // change title of toolbar - switch(status){ + switch (status) { case LATEST: - if(getSupportActionBar()!=null) getSupportActionBar().setTitle(getResources().getString(R.string.main_menu_latest)); + if (getSupportActionBar() != null) + getSupportActionBar().setTitle(getResources().getString(R.string.main_menu_latest)); getMenuInflater().inflate(R.menu.menu_latest, menu); break; case RKLIST: - if(getSupportActionBar()!=null) getSupportActionBar().setTitle(getResources().getString(R.string.main_menu_rklist)); + if (getSupportActionBar() != null) + getSupportActionBar().setTitle(getResources().getString(R.string.main_menu_rklist)); break; case FAV: - if(getSupportActionBar()!=null) getSupportActionBar().setTitle(getResources().getString(R.string.main_menu_fav)); + if (getSupportActionBar() != null) + getSupportActionBar().setTitle(getResources().getString(R.string.main_menu_fav)); break; case CONFIG: - if(getSupportActionBar()!=null) getSupportActionBar().setTitle(getResources().getString(R.string.main_menu_config)); + if (getSupportActionBar() != null) + getSupportActionBar().setTitle(getResources().getString(R.string.main_menu_config)); break; } - } - else { - if(getSupportActionBar()!=null) + } else { + if (getSupportActionBar() != null) getSupportActionBar().setTitle(getResources().getString(R.string.app_name)); } @@ -210,7 +239,7 @@ public boolean onCreateOptionsMenu(Menu menu) { */ public void changeFragment(Fragment targetFragment) { // temporarily set elevation to remove rank list toolbar shadow - if(getSupportActionBar() != null) { + if (getSupportActionBar() != null) { if (status == FRAGMENT_LIST.RKLIST) getSupportActionBar().setElevation(0); else @@ -236,20 +265,29 @@ protected void onResume() { super.onResume(); MobclickAgent.onPageStart("MainActivity"); MobclickAgent.onResume(this); + + // load only the first time this activity is created + if (!NEW_VERSION_CHECKED.get()) { + NEW_VERSION_CHECKED.set(true); + new ArgsInitializer(MainActivity.this).execute(); + } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode) { - case 112: { + case REQUEST_WRITE_EXTERNAL: + case REQUEST_READ_EXTERNAL: { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { //reload my activity with permission granted or use the features what required the permission - Intent i = getBaseContext().getPackageManager().getLaunchIntentForPackage( getBaseContext().getPackageName() ); - i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(i); + Intent i = getBaseContext().getPackageManager().getLaunchIntentForPackage(getBaseContext().getPackageName()); + if (i != null) { + i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + startActivity(i); + } } else { - Toast.makeText(this, "The app was not allowed to write to your storage. Hence, it cannot function properly. Please consider granting it this permission", Toast.LENGTH_LONG).show(); + Toast.makeText(this, getResources().getText(R.string.missing_permission), Toast.LENGTH_LONG).show(); } } } @@ -285,4 +323,87 @@ public void run() { finish(); } } + + /** + * this class is used for checking new versions and new notice text, + * only when the app is loaded at the beginning + */ + private static class ArgsInitializer extends AsyncTask { + private final WeakReference contextReference; + private int newVersionCode = 0; + + ArgsInitializer(Context c) { + contextReference = new WeakReference<>(c); + } + + @Override + protected void onPreExecute() { + super.onPreExecute(); + } + + @Override + protected Void doInBackground(Void... voids) { + // load new version + byte[] codeByte = LightNetwork.LightHttpDownload(GlobalConfig.versionCheckUrl); + if (codeByte != null) { + String code = new String(codeByte); + Log.d("MewX", "version code: " + code); + if (!code.trim().isEmpty() && TextUtils.isDigitsOnly(code.trim())) { + newVersionCode = Integer.parseInt(code); + } + } + + // load parameters + codeByte = LightNetwork.LightHttpDownload( + GlobalConfig.getCurrentLang() != Wenku8API.LANG.SC ? + GlobalConfig.noticeCheckTc : GlobalConfig.noticeCheckSc + ); + if (codeByte != null) { + String notice = new String(codeByte); + Log.d("MewX", "notice text: " + notice); + if (!notice.trim().isEmpty()) { + // update the latest string + Wenku8API.NoticeString = notice; + // save to local file + GlobalConfig.writeTheNotice(notice); + } + } + + return null; + } + + @Override + protected void onPostExecute(Void v) { + Context context = contextReference.get(); + if (context == null) return; + + // check whether there's new version + try { + int current = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionCode; + Log.d("MewX", "current version code: " + current); + if (current < newVersionCode) { + // update to new version + new MaterialDialog.Builder(context) + .theme(Theme.LIGHT) + .title(R.string.system_update_found_new) + .content(R.string.system_update_jump_to_page) + .positiveText(R.string.dialog_positive_sure) + .negativeText(R.string.dialog_negative_no) + .negativeColorRes(R.color.menu_text_color) + .callback(new MaterialDialog.ButtonCallback() { + @Override + public void onPositive(MaterialDialog dialog) { + super.onPositive(dialog); + Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(GlobalConfig.blogPageUrl)); + context.startActivity(browserIntent); + } + }) + .show(); + + } + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + } + } } diff --git a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/fragment/ConfigFragment.java b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/fragment/ConfigFragment.java index f717f648..eccd270b 100644 --- a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/fragment/ConfigFragment.java +++ b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/fragment/ConfigFragment.java @@ -6,8 +6,14 @@ import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; +import android.support.annotation.NonNull; import android.support.v4.app.Fragment; +import android.text.Html; +import android.text.SpannableStringBuilder; import android.text.TextUtils; +import android.text.method.LinkMovementMethod; +import android.text.style.ClickableSpan; +import android.text.style.URLSpan; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -18,9 +24,7 @@ import com.afollestad.materialdialogs.MaterialDialog; import com.afollestad.materialdialogs.Theme; import com.umeng.analytics.MobclickAgent; -import com.umeng.onlineconfig.OnlineConfigAgent; -import org.mewx.wenku8.MyApp; import org.mewx.wenku8.R; import org.mewx.wenku8.activity.AboutActivity; import org.mewx.wenku8.activity.MainActivity; @@ -37,6 +41,7 @@ import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.List; +import java.util.Objects; public class ConfigFragment extends Fragment { @@ -54,7 +59,7 @@ public void onCreate(Bundle savedInstanceState) { } @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_config, container, false); @@ -65,85 +70,86 @@ public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // get views - Wenku8API.NoticeString = OnlineConfigAgent.getInstance().getConfigParams(MyApp.getContext(), - GlobalConfig.getCurrentLang() != Wenku8API.LANG.SC ? "wenku8_notice_tw" : "wenku8_notice"); // get each time - TextView tvNotice = (TextView) getActivity().findViewById(R.id.notice); + TextView tvNotice = Objects.requireNonNull(getActivity()).findViewById(R.id.notice); if(Wenku8API.NoticeString.equals("")) getActivity().findViewById(R.id.notice_layout).setVisibility(View.GONE); - else - tvNotice.setText("通知:\n" + Wenku8API.NoticeString); + else { + CharSequence sequence = Html.fromHtml(Wenku8API.NoticeString.trim()); + SpannableStringBuilder strBuilder = new SpannableStringBuilder(sequence); + URLSpan[] urls = strBuilder.getSpans(0, sequence.length(), URLSpan.class); + for(URLSpan span : urls) { + int start = strBuilder.getSpanStart(span); + int end = strBuilder.getSpanEnd(span); + int flags = strBuilder.getSpanFlags(span); + ClickableSpan clickable = new ClickableSpan() { + public void onClick(View view) { + // Do something with span.getURL() to handle the link click... + Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(GlobalConfig.blogPageUrl)); + Objects.requireNonNull(getContext()).startActivity(browserIntent); + } + }; + strBuilder.setSpan(clickable, start, end, flags); + strBuilder.removeSpan(span); + } + tvNotice.setText(strBuilder); + tvNotice.setMovementMethod(LinkMovementMethod.getInstance()); + } - getActivity().findViewById(R.id.btn_choose_language).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - new MaterialDialog.Builder(getActivity()) - .theme(Theme.LIGHT) - .title(R.string.config_choose_language) - .content(R.string.dialog_content_language_tip) - .items(R.array.choose_language_option) - .itemsCallback(new MaterialDialog.ListCallback() { - @Override - public void onSelection(MaterialDialog dialog, View view, int which, CharSequence text) { - switch (which) { - case 0: - // sc - if(GlobalConfig.getCurrentLang() != Wenku8API.LANG.SC) { - GlobalConfig.setCurrentLang(Wenku8API.LANG.SC); - Intent intent = new Intent(); - intent.setClass(getActivity(), MainActivity.class); - startActivity(intent); - getActivity().overridePendingTransition(R.anim.fade_in, R.anim.hold); // fade in animation - getActivity().finish(); // destroy itself - } - else - Toast.makeText(getActivity(), "Already in.", Toast.LENGTH_SHORT).show(); - break; - case 1: - // tc - if(GlobalConfig.getCurrentLang() != Wenku8API.LANG.TC) { - GlobalConfig.setCurrentLang(Wenku8API.LANG.TC); - Intent intent = new Intent(); - intent.setClass(getActivity(), MainActivity.class); - startActivity(intent); - getActivity().overridePendingTransition(R.anim.fade_in, R.anim.hold); // fade in animation - getActivity().finish(); // destroy itself - } - else - Toast.makeText(getActivity(), "Already in.", Toast.LENGTH_SHORT).show(); - break; - } + getActivity().findViewById(R.id.btn_choose_language).setOnClickListener(v -> new MaterialDialog.Builder(getActivity()) + .theme(Theme.LIGHT) + .title(R.string.config_choose_language) + .content(R.string.dialog_content_language_tip) + .items(R.array.choose_language_option) + .itemsCallback((dialog, view, which, text) -> { + switch (which) { + case 0: + // sc + if(GlobalConfig.getCurrentLang() != Wenku8API.LANG.SC) { + GlobalConfig.setCurrentLang(Wenku8API.LANG.SC); + Intent intent = new Intent(); + intent.setClass(getActivity(), MainActivity.class); + startActivity(intent); + getActivity().overridePendingTransition(R.anim.fade_in, R.anim.hold); // fade in animation + getActivity().finish(); // destroy itself } - }) - .show(); - } - }); - getActivity().findViewById(R.id.btn_clear_cache).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - new MaterialDialog.Builder(getActivity()) - .theme(Theme.LIGHT) - .title(R.string.config_clear_cache) - .items(R.array.wipe_cache_option) - .itemsCallback(new MaterialDialog.ListCallback() { - @Override - public void onSelection(MaterialDialog dialog, View view, int which, CharSequence text) { - switch (which) { - case 0: - // fast mode - AsyncDeleteFast adf = new AsyncDeleteFast(); - adf.execute(); - break; - case 1: - // slow mode - AsyncDeleteSlow ads = new AsyncDeleteSlow(); - ads.execute(); - break; - } + else + Toast.makeText(getActivity(), "Already in.", Toast.LENGTH_SHORT).show(); + break; + case 1: + // tc + if(GlobalConfig.getCurrentLang() != Wenku8API.LANG.TC) { + GlobalConfig.setCurrentLang(Wenku8API.LANG.TC); + Intent intent = new Intent(); + intent.setClass(getActivity(), MainActivity.class); + startActivity(intent); + getActivity().overridePendingTransition(R.anim.fade_in, R.anim.hold); // fade in animation + getActivity().finish(); // destroy itself } - }) - .show(); - } - }); + else + Toast.makeText(getActivity(), "Already in.", Toast.LENGTH_SHORT).show(); + break; + } + }) + .show()); + getActivity().findViewById(R.id.btn_clear_cache).setOnClickListener(v -> new MaterialDialog.Builder(getActivity()) + .theme(Theme.LIGHT) + .title(R.string.config_clear_cache) + .items(R.array.wipe_cache_option) + .itemsCallback((dialog, view, which, text) -> { + switch (which) { + case 0: + // fast mode + AsyncDeleteFast adf = new AsyncDeleteFast(); + adf.execute(); + break; + case 1: + // slow mode + AsyncDeleteSlow ads = new AsyncDeleteSlow(); + ads.execute(); + break; + } + }) + .show()); getActivity().findViewById(R.id.btn_navigation_drawer_wallpaper).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -151,66 +157,14 @@ public void onClick(View v) { startActivity(intent); } }); - getActivity().findViewById(R.id.btn_check_update).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - // alpha version does not contains auto-update function - // check for update - new AsyncTask() { - @Override - protected Integer doInBackground(String... strings) { - // return version code - byte[] codeByte = LightNetwork.LightHttpDownload(strings[0]); - if (codeByte == null) return -1; - String code = new String(codeByte); - Log.d("MewX", "version code: " + code); - if (code.trim().isEmpty() || !TextUtils.isDigitsOnly(code.trim())) return -1; - else return Integer.parseInt(code); - } - - @Override - protected void onPostExecute(Integer code) { - super.onPostExecute(code); - if (code == -1) - Toast.makeText(getActivity(), getResources().getString(R.string.system_update_timeout), Toast.LENGTH_SHORT).show(); - try { - int current = getContext().getPackageManager().getPackageInfo(getContext().getPackageName(), 0).versionCode; - Log.d("MewX", "current version code: " + current); - if (current >= code) { - Toast.makeText(getActivity(), getResources().getString(R.string.system_update_latest_version), Toast.LENGTH_SHORT).show(); - } - else { - // update to new version - new MaterialDialog.Builder(getContext()) - .theme(Theme.LIGHT) - .title(R.string.system_update_found_new) - .content(R.string.system_update_jump_to_page) - .positiveText(R.string.dialog_positive_sure) - .negativeText(R.string.dialog_negative_biao) - .callback(new MaterialDialog.ButtonCallback() { - @Override - public void onPositive(MaterialDialog dialog) { - super.onPositive(dialog); - Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://wenku8.mewx.org/")); - startActivity(browserIntent); - } - }) - .show(); - - } - } catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - } - } - }.execute("http://wenku8.mewx.org/version"); - } + getActivity().findViewById(R.id.btn_check_update).setOnClickListener(v -> { + // alpha version does not contains auto-update function + // check for update + new CheckNewVersion().execute(GlobalConfig.versionCheckUrl); }); - getActivity().findViewById(R.id.btn_about).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Intent intent = new Intent(getActivity(), AboutActivity.class); - startActivity(intent); - } + getActivity().findViewById(R.id.btn_about).setOnClickListener(v -> { + Intent intent = new Intent(getActivity(), AboutActivity.class); + startActivity(intent); }); } @@ -282,20 +236,64 @@ protected void onPostExecute(Wenku8Error.ErrorCode errorCode) { } } + private class CheckNewVersion extends AsyncTask { + @Override + protected Integer doInBackground(String... strings) { + // return version code + byte[] codeByte = LightNetwork.LightHttpDownload(strings[0]); + if (codeByte == null) return -1; + String code = new String(codeByte); + Log.d("MewX", "version code: " + code); + if (code.trim().isEmpty() || !TextUtils.isDigitsOnly(code.trim())) return -1; + else return Integer.parseInt(code); + } + + @Override + protected void onPostExecute(Integer code) { + super.onPostExecute(code); + if (code == -1) + Toast.makeText(getActivity(), getResources().getString(R.string.system_update_timeout), Toast.LENGTH_SHORT).show(); + try { + int current = getContext().getPackageManager().getPackageInfo(getContext().getPackageName(), 0).versionCode; + Log.d("MewX", "current version code: " + current); + if (current >= code) { + Toast.makeText(getActivity(), getResources().getString(R.string.system_update_latest_version), Toast.LENGTH_SHORT).show(); + } else { + // update to new version + new MaterialDialog.Builder(getContext()) + .theme(Theme.LIGHT) + .title(R.string.system_update_found_new) + .content(R.string.system_update_jump_to_page) + .positiveText(R.string.dialog_positive_sure) + .negativeText(R.string.dialog_negative_biao) + .callback(new MaterialDialog.ButtonCallback() { + @Override + public void onPositive(MaterialDialog dialog) { + super.onPositive(dialog); + Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(GlobalConfig.blogPageUrl)); + startActivity(browserIntent); + } + }) + .show(); + + } + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + } + } + private class AsyncDeleteSlow extends AsyncTask { private MaterialDialog md; private boolean isLoading = false; @Override protected void onPreExecute() { super.onPreExecute(); - md = new MaterialDialog.Builder(getActivity()) + md = new MaterialDialog.Builder(Objects.requireNonNull(getActivity())) .theme(Theme.LIGHT) - .cancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - isLoading = false; - AsyncDeleteSlow.this.cancel(true); - } + .cancelListener(dialog -> { + isLoading = false; + AsyncDeleteSlow.this.cancel(true); }) .title(R.string.config_clear_cache) .content(R.string.dialog_content_wipe_cache_slow) @@ -357,7 +355,7 @@ protected Wenku8Error.ErrorCode doInBackground(Integer... params) { if(childFile != null && childFile.length != 0) { for (File f : childFile) { if(!isLoading) return Wenku8Error.ErrorCode.USER_CANCELLED_TASK; - String[] temp = f.getAbsolutePath().split("\\/"); + String[] temp = f.getAbsolutePath().split("/"); if(temp.length != 0) { String name = temp[temp.length - 1]; if(!listPicture.contains(name)) f.delete(); diff --git a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/fragment/FavFragment.java b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/fragment/FavFragment.java index 4fdd9c37..d0ca1e5a 100644 --- a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/fragment/FavFragment.java +++ b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/fragment/FavFragment.java @@ -24,13 +24,10 @@ import com.afollestad.materialdialogs.GravityEnum; import com.afollestad.materialdialogs.MaterialDialog; import com.afollestad.materialdialogs.Theme; -import com.android.volley.ParseError; import com.umeng.analytics.MobclickAgent; -import org.apache.http.NameValuePair; import org.mewx.wenku8.MyApp; import org.mewx.wenku8.R; -import org.mewx.wenku8.activity.MainActivity; import org.mewx.wenku8.activity.NovelInfoActivity; import org.mewx.wenku8.adapter.NovelItemAdapterUpdate; import org.mewx.wenku8.global.GlobalConfig; diff --git a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/fragment/NavigationDrawerFragment.java b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/fragment/NavigationDrawerFragment.java index 892fc2d5..5561ed57 100644 --- a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/fragment/NavigationDrawerFragment.java +++ b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/fragment/NavigationDrawerFragment.java @@ -23,6 +23,7 @@ import android.widget.Toast; import com.afollestad.materialdialogs.MaterialDialog; +import com.afollestad.materialdialogs.StackingBehavior; import com.afollestad.materialdialogs.Theme; import com.makeramen.roundedimageview.RoundedImageView; import com.umeng.analytics.MobclickAgent; @@ -36,7 +37,6 @@ import org.mewx.wenku8.util.LightTool; import org.mewx.wenku8.util.LightUserSession; -//@TargetApi(16) public class NavigationDrawerFragment extends Fragment { private final String TAG = "NavigationDrawerFragment"; private View mFragmentContainerView; @@ -129,7 +129,7 @@ public void onClick(View v) { .theme(Theme.LIGHT) .title(R.string.main_menu_statement) .content(GlobalConfig.getOpensourceLicense()) - .forceStacking(true) + .stackingBehavior(StackingBehavior.ALWAYS) .positiveColorRes(R.color.dlgPositiveButtonColor) .positiveText(R.string.dialog_positive_known) .show(); diff --git a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/GlobalConfig.java b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/GlobalConfig.java index 0025e855..e69c6b7b 100644 --- a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/GlobalConfig.java +++ b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/GlobalConfig.java @@ -6,8 +6,8 @@ import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.Environment; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.support.v4.app.Fragment; import android.util.Log; import com.android.volley.Cache; @@ -43,6 +43,13 @@ @SuppressWarnings({"UnusedDeclaration"}) public class GlobalConfig { + // online arguments + public static final String blogPageUrl = "https://wenku8.mewx.org/"; + public static final String versionCheckUrl = "https://wenku8.mewx.org/version"; + public static final String noticeCheckSc = "https://wenku8.mewx.org/args/notice_sc"; + public static final String noticeCheckTc = "https://wenku8.mewx.org/args/notice_tc"; + + // constants public static final String saveFolderName = "saves"; public static final String imgsSaveFolderName = "imgs"; public static final String customFolderName = "custom"; @@ -53,6 +60,7 @@ public class GlobalConfig { private static final String saveSetting = "settings.wk8"; private static final String saveUserAccountFileName = "cert.wk8"; // certification file private static final String saveUserAvatarFileName = "avatar.jpg"; + private static final String saveNoticeString = "notice.wk8"; // the notice cache from online private static int maxSearchHistory = 20; // default // vars @@ -264,18 +272,19 @@ public static String getSecondUserAvatarSaveFilePath() { */ public static String generateImageFileNameByURL(String url) { String[] s = url.split("/"); - String result = ""; + StringBuilder result = new StringBuilder(); boolean canStart = false; for (String temp : s) { if (!canStart && temp.contains(".")) canStart = true; // judge canStart first else if (canStart) - result += temp; + result.append(temp); } - return result; + return result.toString(); } - private static String loadFullSaveFileContent(String FileName) { + @NonNull + private static String loadFullSaveFileContent(@NonNull String FileName) { // get full file in file save path String h = ""; if (LightCache.testFileExist(getFirstStoragePath() + saveFolderName + File.separator + FileName)) { @@ -300,7 +309,7 @@ private static String loadFullSaveFileContent(String FileName) { return h; } - private static boolean writeFullSaveFileContent(String FileName, String s) { + private static boolean writeFullSaveFileContent(String FileName, @NonNull String s) { // process path and filename String path = "", fileName = FileName; if (FileName.contains(File.separator)) { @@ -847,4 +856,14 @@ public static boolean isNetworkAvailable(Context context) { } return false; } + + /* notice */ + @NonNull + public static String loadSavedNotice() { + return loadFullSaveFileContent(saveNoticeString); + } + + public static void writeTheNotice(@NonNull String noticeStr) { + writeFullSaveFileContent(saveNoticeString, noticeStr); + } } diff --git a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/api/Wenku8API.java b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/api/Wenku8API.java index 5eb7e475..0ac69bd0 100644 --- a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/api/Wenku8API.java +++ b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/api/Wenku8API.java @@ -1,12 +1,7 @@ package org.mewx.wenku8.global.api; import android.content.ContentValues; -import android.util.Log; -import com.umeng.analytics.MobclickAgent; -import com.umeng.onlineconfig.OnlineConfigAgent; - -import org.mewx.wenku8.MyApp; import org.mewx.wenku8.global.GlobalConfig; import org.mewx.wenku8.util.LightBase64; import org.mewx.wenku8.util.LightNetwork; @@ -30,9 +25,6 @@ public class Wenku8API { NovelNotFinishedSC = "连载中", NovelNotFinishedTC = "連載中"; public static String getBaseURL() { - if(NoticeString.equals("") || NoticeString.equals("http://weuku8.mewx.org")) { - NoticeString = OnlineConfigAgent.getInstance().getConfigParams(MyApp.getContext(), GlobalConfig.getCurrentLang() != LANG.SC ? "wenku8_notice_tw" : "wenku8_notice"); - } return BaseURL; } diff --git a/studio-android/LightNovelLibrary/app/src/main/res/values-zh-rHK/strings.xml b/studio-android/LightNovelLibrary/app/src/main/res/values-zh-rHK/strings.xml index 32c2f5dc..5486332c 100644 --- a/studio-android/LightNovelLibrary/app/src/main/res/values-zh-rHK/strings.xml +++ b/studio-android/LightNovelLibrary/app/src/main/res/values-zh-rHK/strings.xml @@ -202,4 +202,6 @@ 段落間距 段落邊距 請在有圖的頁面點擊此按鈕看圖~ + MewX與輕小說文庫(Wenku8.com)合作的輕小說閱讀app。 + 由於歷史原因,缺少必要的權限時,app可能無法正常工作,請考慮授予相應權限 diff --git a/studio-android/LightNovelLibrary/app/src/main/res/values-zh-rTW/strings.xml b/studio-android/LightNovelLibrary/app/src/main/res/values-zh-rTW/strings.xml index 32c2f5dc..5486332c 100644 --- a/studio-android/LightNovelLibrary/app/src/main/res/values-zh-rTW/strings.xml +++ b/studio-android/LightNovelLibrary/app/src/main/res/values-zh-rTW/strings.xml @@ -202,4 +202,6 @@ 段落間距 段落邊距 請在有圖的頁面點擊此按鈕看圖~ + MewX與輕小說文庫(Wenku8.com)合作的輕小說閱讀app。 + 由於歷史原因,缺少必要的權限時,app可能無法正常工作,請考慮授予相應權限 diff --git a/studio-android/LightNovelLibrary/app/src/main/res/values/strings.xml b/studio-android/LightNovelLibrary/app/src/main/res/values/strings.xml index 28d8a776..210b9f5e 100644 --- a/studio-android/LightNovelLibrary/app/src/main/res/values/strings.xml +++ b/studio-android/LightNovelLibrary/app/src/main/res/values/strings.xml @@ -94,6 +94,7 @@ 没有Wi-Fi,臣妾不敢轻举妄动 已忽略 选择一个阅读界面引擎 + 由于历史原因,缺少必要的权限时,app可能无法正常工作,请考虑授予相应权限 停止加载 点击重新加载 没有结果 From af362bee58649314b34f6b9e15e9f2eca5052230 Mon Sep 17 00:00:00 2001 From: MewX Date: Mon, 11 Jun 2018 14:28:35 +0930 Subject: [PATCH 2/6] Closes #16 Fixed cover URL --- .../src/main/java/org/mewx/wenku8/global/api/Wenku8API.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/api/Wenku8API.java b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/api/Wenku8API.java index 0ac69bd0..e7244945 100644 --- a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/api/Wenku8API.java +++ b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/api/Wenku8API.java @@ -40,7 +40,7 @@ public static boolean hasEdited() { } public static String getCoverURL(int aid) { - return "http://img.wenku8.com/image/" + Integer.toString(aid / 1000) + return "http://img.wkcdn.com/image/" + Integer.toString(aid / 1000) + "/" + Integer.toString(aid) + "/" + Integer.toString(aid) + "s.jpg"; } @@ -283,6 +283,7 @@ private static ContentValues getEncryptedCV(String str) { public static ContentValues getNovelCover(int aid) { // get the aid, and return a "jpg" file or other, in binary + // not using this because UIL does not support post to get image return getEncryptedCV("action=book&do=cover&aid=" + aid); } From 208ab572a5d2a5e659aecaa7a53ea7556b01b64c Mon Sep 17 00:00:00 2001 From: MewX Date: Mon, 11 Jun 2018 14:30:03 +0930 Subject: [PATCH 3/6] Closes #17 Cleaned packages --- .../LightNovelLibrary/app/build.gradle | 2 +- .../adapter/NovelItemAdapterUpdate.java | 40 +++++++----------- .../LightNovelLibrary/settings.gradle | 2 +- .../systembartint-1.0.3/build.gradle | 2 - .../systembartint-1.0.3.jar | Bin 8026 -> 0 bytes 5 files changed, 18 insertions(+), 28 deletions(-) delete mode 100644 studio-android/LightNovelLibrary/systembartint-1.0.3/build.gradle delete mode 100644 studio-android/LightNovelLibrary/systembartint-1.0.3/systembartint-1.0.3.jar diff --git a/studio-android/LightNovelLibrary/app/build.gradle b/studio-android/LightNovelLibrary/app/build.gradle index 9a49dbe4..d48dd31e 100644 --- a/studio-android/LightNovelLibrary/app/build.gradle +++ b/studio-android/LightNovelLibrary/app/build.gradle @@ -64,7 +64,7 @@ dependencies { implementation 'com.android.support:recyclerview-v7:27.1.1' implementation 'com.android.support:design:27.1.1' // external libraries - implementation project(':volley') + implementation project(':volley') // DO NOT CHANGE THIS, MODIFIED VERSION implementation 'com.readystatesoftware.systembartint:systembartint:1.0.3' implementation 'com.nostra13.universalimageloader:universal-image-loader:1.9.3' implementation 'com.afollestad.material-dialogs:core:0.9.6.0' diff --git a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/adapter/NovelItemAdapterUpdate.java b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/adapter/NovelItemAdapterUpdate.java index ad6721c8..ecb23bd0 100644 --- a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/adapter/NovelItemAdapterUpdate.java +++ b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/adapter/NovelItemAdapterUpdate.java @@ -73,32 +73,24 @@ public void onBindViewHolder(final ViewHolder viewHolder, int i) { final int tempAid = i; StringRequest postRequest = new StringRequest(Request.Method.POST, Wenku8API.getBaseURL(), - new Response.Listener() - { - @Override - public void onResponse(String response) { - // response - try { - response = new String(response.getBytes(), "UTF-8"); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } - //GlobalConfig.wantDebugLog("VolleyResponse", response); - - // update info - //NovelItemInfoUpdate nuui = new NovelItemInfoUpdate(tempAid); - mDataset.set(tempAid,NovelItemInfoUpdate.parse(response)); - refreshAllContent(viewHolder, tempAid); - viewHolder.isLoading = false; + response -> { + // response + try { + response = new String(response.getBytes(), "UTF-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); } + //GlobalConfig.wantDebugLog("VolleyResponse", response); + + // update info + //NovelItemInfoUpdate nuui = new NovelItemInfoUpdate(tempAid); + mDataset.set(tempAid,NovelItemInfoUpdate.parse(response)); + refreshAllContent(viewHolder, tempAid); + viewHolder.isLoading = false; }, - new Response.ErrorListener() - { - @Override - public void onErrorResponse(VolleyError error) { - // error - viewHolder.isLoading = false; - } + error -> { + // error + viewHolder.isLoading = false; } ) { @Override diff --git a/studio-android/LightNovelLibrary/settings.gradle b/studio-android/LightNovelLibrary/settings.gradle index 9d33285d..046dc4dd 100644 --- a/studio-android/LightNovelLibrary/settings.gradle +++ b/studio-android/LightNovelLibrary/settings.gradle @@ -1 +1 @@ -include ':app', ':systembartint-1.0.3', ':volley' +include ':app', ':volley' diff --git a/studio-android/LightNovelLibrary/systembartint-1.0.3/build.gradle b/studio-android/LightNovelLibrary/systembartint-1.0.3/build.gradle deleted file mode 100644 index a9dfa70d..00000000 --- a/studio-android/LightNovelLibrary/systembartint-1.0.3/build.gradle +++ /dev/null @@ -1,2 +0,0 @@ -configurations.create("default") -artifacts.add("default", file('systembartint-1.0.3.jar')) \ No newline at end of file diff --git a/studio-android/LightNovelLibrary/systembartint-1.0.3/systembartint-1.0.3.jar b/studio-android/LightNovelLibrary/systembartint-1.0.3/systembartint-1.0.3.jar deleted file mode 100644 index 8816fdeff71931c7dd09e04e142a285bf3808ef0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8026 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 Date: Mon, 11 Jun 2018 18:07:31 +0930 Subject: [PATCH 4/6] Closes #8 Fixed missing icon on Android 4.x --- studio-android/LightNovelLibrary/.gitignore | 5 + .../LightNovelLibrary/app/build.gradle | 5 + .../mewx/wenku8/activity/AboutActivity.java | 2 +- .../MenuBackgroundSelectorActivity.java | 2 +- .../wenku8/activity/NovelChapterActivity.java | 2 +- .../wenku8/activity/NovelInfoActivity.java | 4 +- .../mewx/wenku8/activity/SearchActivity.java | 58 ++++----- .../wenku8/activity/SearchResultActivity.java | 2 +- .../wenku8/activity/UserInfoActivity.java | 2 +- .../wenku8/activity/UserLoginActivity.java | 2 +- .../activity/ViewImageDetailActivity.java | 123 ++++++++---------- .../org/mewx/wenku8/global/api/Wenku8API.java | 9 +- .../activity/Wenku8ReaderActivityV1.java | 31 +++-- .../app/src/main/res/drawable/ic_svg_back.xml | 11 ++ .../src/main/res/drawable/ic_svg_clear.xml | 11 ++ .../src/main/res/layout/toolbar_search.xml | 2 +- .../app/src/main/res/values/strings.xml | 2 +- .../mewx/wenku8/global/api/Wenku8APITest.java | 55 ++++++++ 18 files changed, 196 insertions(+), 132 deletions(-) create mode 100644 studio-android/LightNovelLibrary/app/src/main/res/drawable/ic_svg_back.xml create mode 100644 studio-android/LightNovelLibrary/app/src/main/res/drawable/ic_svg_clear.xml create mode 100644 studio-android/LightNovelLibrary/app/src/test/java/org/mewx/wenku8/global/api/Wenku8APITest.java diff --git a/studio-android/LightNovelLibrary/.gitignore b/studio-android/LightNovelLibrary/.gitignore index 35ed4154..f5d5c103 100644 --- a/studio-android/LightNovelLibrary/.gitignore +++ b/studio-android/LightNovelLibrary/.gitignore @@ -3,3 +3,8 @@ .idea/ .DS_Store /build + +# distributions +baidu/ +coolapk/ +alpha/ diff --git a/studio-android/LightNovelLibrary/app/build.gradle b/studio-android/LightNovelLibrary/app/build.gradle index d48dd31e..bb1af023 100644 --- a/studio-android/LightNovelLibrary/app/build.gradle +++ b/studio-android/LightNovelLibrary/app/build.gradle @@ -77,4 +77,9 @@ dependencies { implementation 'com.nononsenseapps:filepicker:2.2' implementation 'com.umeng.sdk:common:1.5.0' implementation 'com.umeng.sdk:analytics:7.5.0' + + testImplementation 'junit:junit:4.12' + testImplementation 'org.mockito:mockito-all:1.10.19' + testImplementation 'org.powermock:powermock-module-junit4:1.7.4' + testImplementation 'org.powermock:powermock-api-mockito:1.7.4' } diff --git a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/AboutActivity.java b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/AboutActivity.java index 37bc4cbc..1943e563 100644 --- a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/AboutActivity.java +++ b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/AboutActivity.java @@ -29,7 +29,7 @@ protected void onCreate(Bundle savedInstanceState) { // set indicator enable Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar_actionbar); setSupportActionBar(mToolbar); - final Drawable upArrow = getResources().getDrawable(R.drawable.abc_ic_ab_back_material); + final Drawable upArrow = getResources().getDrawable(R.drawable.ic_svg_back); if(getSupportActionBar() != null && upArrow != null) { getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setHomeButtonEnabled(true); diff --git a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/MenuBackgroundSelectorActivity.java b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/MenuBackgroundSelectorActivity.java index 91e9e24d..72444238 100644 --- a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/MenuBackgroundSelectorActivity.java +++ b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/MenuBackgroundSelectorActivity.java @@ -41,7 +41,7 @@ protected void onCreate(Bundle savedInstanceState) { // set indicator enable Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar_actionbar); setSupportActionBar(mToolbar); - final Drawable upArrow = getResources().getDrawable(R.drawable.abc_ic_ab_back_material); + final Drawable upArrow = getResources().getDrawable(R.drawable.ic_svg_back); if(getSupportActionBar() != null && upArrow != null) { getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setHomeButtonEnabled(true); diff --git a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/NovelChapterActivity.java b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/NovelChapterActivity.java index 50b4ff43..e408ab62 100644 --- a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/NovelChapterActivity.java +++ b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/NovelChapterActivity.java @@ -56,7 +56,7 @@ protected void onCreate(Bundle savedInstanceState) { // set indicator enable Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar_actionbar); setSupportActionBar(mToolbar); - final Drawable upArrow = getResources().getDrawable(R.drawable.abc_ic_ab_back_material); + final Drawable upArrow = getResources().getDrawable(R.drawable.ic_svg_back); if(getSupportActionBar() != null && upArrow != null) { getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setHomeButtonEnabled(true); diff --git a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/NovelInfoActivity.java b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/NovelInfoActivity.java index d5622e82..bbb35a37 100644 --- a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/NovelInfoActivity.java +++ b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/NovelInfoActivity.java @@ -99,7 +99,7 @@ protected void onCreate(Bundle savedInstanceState) { // set indicator enable Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar_actionbar); setSupportActionBar(mToolbar); - final Drawable upArrow = getResources().getDrawable(R.drawable.abc_ic_ab_back_material); + final Drawable upArrow = getResources().getDrawable(R.drawable.ic_svg_back); if(getSupportActionBar() != null && upArrow != null) { getSupportActionBar().setHomeButtonEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true); @@ -1212,7 +1212,7 @@ protected void onResume() { MobclickAgent.onResume(this); // return from search activity - final Drawable upArrow = getResources().getDrawable(R.drawable.abc_ic_ab_back_material); + final Drawable upArrow = getResources().getDrawable(R.drawable.ic_svg_back); if(getSupportActionBar() != null && upArrow != null) { getSupportActionBar().setHomeButtonEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true); diff --git a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/SearchActivity.java b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/SearchActivity.java index f42dfc0a..6699330a 100644 --- a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/SearchActivity.java +++ b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/SearchActivity.java @@ -10,12 +10,10 @@ import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; -import android.view.KeyEvent; import android.view.MenuItem; import android.view.View; import android.widget.EditText; import android.widget.ImageView; -import android.widget.TextView; import android.widget.Toast; import com.afollestad.materialdialogs.GravityEnum; @@ -51,19 +49,14 @@ protected void onCreate(Bundle savedInstanceState) { // bind views // searchContainer = (LinearLayout)findViewById(R.id.search_container); - toolbarSearchView = (EditText) findViewById(R.id.search_view); + toolbarSearchView = findViewById(R.id.search_view); View searchClearButton = findViewById(R.id.search_clear); // Clear search text when clear button is tapped - searchClearButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - toolbarSearchView.setText(""); - } - }); + searchClearButton.setOnClickListener(v -> toolbarSearchView.setText("")); // set indicator enable - Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar_actionbar); + Toolbar mToolbar = findViewById(R.id.toolbar_actionbar); setSupportActionBar(mToolbar); if(getSupportActionBar() != null) { getSupportActionBar().setDisplayHomeAsUpEnabled(true); @@ -89,14 +82,14 @@ public void onClick(View v) { } // set search clear icon color - ImageView searchClearIcon = (ImageView)findViewById(R.id.search_clear_icon); + ImageView searchClearIcon = findViewById(R.id.search_clear_icon); searchClearIcon.setColorFilter(getResources().getColor(R.color.mySearchToggleColor), PorterDuff.Mode.SRC_ATOP); // set history list LinearLayoutManager mLayoutManager = new LinearLayoutManager(this); mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); - RecyclerView mRecyclerView = (RecyclerView) this.findViewById(R.id.search_history_list); + RecyclerView mRecyclerView = this.findViewById(R.id.search_history_list); mRecyclerView.setHasFixedSize(true); // set variable size mRecyclerView.setItemAnimator(new DefaultItemAnimator()); mRecyclerView.setLayoutManager(mLayoutManager); @@ -108,27 +101,24 @@ public void onClick(View v) { mRecyclerView.setAdapter(adapter); // set search action - toolbarSearchView.setOnEditorActionListener(new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - // purify - String temp = toolbarSearchView.getText().toString().trim(); - if(temp.length()==0) return false; - - // real action - //Toast.makeText(MyApp.getContext(), temp, Toast.LENGTH_SHORT).show(); - GlobalConfig.addSearchHistory(temp); - refreshHistoryList(); - - // jump to search - Intent intent = new Intent(SearchActivity.this, SearchResultActivity.class); - intent.putExtra("key", temp); - intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); // long-press will cause repetitions - startActivity(intent); - overridePendingTransition( R.anim.fade_in, R.anim.hold); - - return false; - } + toolbarSearchView.setOnEditorActionListener((v, actionId, event) -> { + // purify + String temp = toolbarSearchView.getText().toString().trim(); + if(temp.length()==0) return false; + + // real action + //Toast.makeText(MyApp.getContext(), temp, Toast.LENGTH_SHORT).show(); + GlobalConfig.addSearchHistory(temp); + refreshHistoryList(); + + // jump to search + Intent intent = new Intent(SearchActivity.this, SearchResultActivity.class); + intent.putExtra("key", temp); + intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); // long-press will cause repetitions + startActivity(intent); + overridePendingTransition( R.anim.fade_in, R.anim.hold); + + return false; }); } @@ -138,7 +128,7 @@ protected void onResume() { MobclickAgent.onResume(this); // set back arrow icon - final Drawable upArrow = getResources().getDrawable(R.drawable.abc_ic_ab_back_material); + final Drawable upArrow = getResources().getDrawable(R.drawable.ic_svg_back); if(upArrow != null && getSupportActionBar() != null) { upArrow.setColorFilter(getResources().getColor(R.color.mySearchToggleColor), PorterDuff.Mode.SRC_ATOP); getSupportActionBar().setHomeAsUpIndicator(upArrow); diff --git a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/SearchResultActivity.java b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/SearchResultActivity.java index de943164..fefafa61 100644 --- a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/SearchResultActivity.java +++ b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/SearchResultActivity.java @@ -93,7 +93,7 @@ protected void onResume() { MobclickAgent.onResume(this); // set back arrow icon - final Drawable upArrow = getResources().getDrawable(R.drawable.abc_ic_ab_back_material); + final Drawable upArrow = getResources().getDrawable(R.drawable.ic_svg_back); if(upArrow != null && getSupportActionBar() != null) { upArrow.setColorFilter(getResources().getColor(R.color.mySearchToggleColor), PorterDuff.Mode.SRC_ATOP); getSupportActionBar().setHomeAsUpIndicator(upArrow); diff --git a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/UserInfoActivity.java b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/UserInfoActivity.java index 8d5dae66..c95f580a 100644 --- a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/UserInfoActivity.java +++ b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/UserInfoActivity.java @@ -60,7 +60,7 @@ protected void onCreate(Bundle savedInstanceState) { if(getSupportActionBar() != null) { getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setHomeButtonEnabled(true); - final Drawable upArrow = getResources().getDrawable(R.drawable.abc_ic_ab_back_material); + final Drawable upArrow = getResources().getDrawable(R.drawable.ic_svg_back); if(upArrow != null) upArrow.setColorFilter(getResources().getColor(R.color.default_white), PorterDuff.Mode.SRC_ATOP); getSupportActionBar().setHomeAsUpIndicator(upArrow); diff --git a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/UserLoginActivity.java b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/UserLoginActivity.java index c1681898..a79544ad 100644 --- a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/UserLoginActivity.java +++ b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/UserLoginActivity.java @@ -55,7 +55,7 @@ protected void onCreate(Bundle savedInstanceState) { if(getSupportActionBar() != null) { getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setHomeButtonEnabled(true); - final Drawable upArrow = getResources().getDrawable(R.drawable.abc_ic_ab_back_material); + final Drawable upArrow = getResources().getDrawable(R.drawable.ic_svg_back); if(upArrow != null) upArrow.setColorFilter(getResources().getColor(R.color.default_white), PorterDuff.Mode.SRC_ATOP); getSupportActionBar().setHomeAsUpIndicator(upArrow); diff --git a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/ViewImageDetailActivity.java b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/ViewImageDetailActivity.java index 0fe97842..5f851391 100644 --- a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/ViewImageDetailActivity.java +++ b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/ViewImageDetailActivity.java @@ -9,6 +9,7 @@ import android.os.Build; import android.os.Bundle; import android.os.Environment; +import android.support.annotation.NonNull; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.text.InputType; @@ -51,9 +52,9 @@ protected void onCreate(Bundle savedInstanceState) { path = getIntent().getStringExtra("path"); // set indicator enable - Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar_actionbar); + Toolbar mToolbar = findViewById(R.id.toolbar_actionbar); setSupportActionBar(mToolbar); - final Drawable upArrow = getResources().getDrawable(R.drawable.abc_ic_ab_back_material); + final Drawable upArrow = getResources().getDrawable(R.drawable.ic_svg_back); if(getSupportActionBar() != null && upArrow != null) { getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setHomeButtonEnabled(true); @@ -77,7 +78,7 @@ protected void onCreate(Bundle savedInstanceState) { } // set image - imageView = (SubsamplingScaleImageView) findViewById(R.id.image_scalable); + imageView = findViewById(R.id.image_scalable); imageView.setImage(ImageSource.uri(path)); imageView.setMaxScale(4.0f); imageView.setOnClickListener(new View.OnClickListener() { @@ -109,51 +110,39 @@ public void onClick(View v) { }); // set on click listeners - findViewById(R.id.btn_rotate).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - switch (imageView.getOrientation()) { - case SubsamplingScaleImageView.ORIENTATION_0: - imageView.setOrientation(SubsamplingScaleImageView.ORIENTATION_90); - break; - case SubsamplingScaleImageView.ORIENTATION_90: - imageView.setOrientation(SubsamplingScaleImageView.ORIENTATION_180); - break; - case SubsamplingScaleImageView.ORIENTATION_180: - imageView.setOrientation(SubsamplingScaleImageView.ORIENTATION_270); - break; - case SubsamplingScaleImageView.ORIENTATION_270: - imageView.setOrientation(SubsamplingScaleImageView.ORIENTATION_0); - break; - } + findViewById(R.id.btn_rotate).setOnClickListener(v -> { + switch (imageView.getOrientation()) { + case SubsamplingScaleImageView.ORIENTATION_0: + imageView.setOrientation(SubsamplingScaleImageView.ORIENTATION_90); + break; + case SubsamplingScaleImageView.ORIENTATION_90: + imageView.setOrientation(SubsamplingScaleImageView.ORIENTATION_180); + break; + case SubsamplingScaleImageView.ORIENTATION_180: + imageView.setOrientation(SubsamplingScaleImageView.ORIENTATION_270); + break; + case SubsamplingScaleImageView.ORIENTATION_270: + imageView.setOrientation(SubsamplingScaleImageView.ORIENTATION_0); + break; } }); - findViewById(R.id.btn_rotate).setOnLongClickListener(new View.OnLongClickListener() { - @Override - public boolean onLongClick(View v) { - Toast.makeText(ViewImageDetailActivity.this, getResources().getString(R.string.reader_rotate), Toast.LENGTH_SHORT).show(); - return true; - } + findViewById(R.id.btn_rotate).setOnLongClickListener(v -> { + Toast.makeText(ViewImageDetailActivity.this, getResources().getString(R.string.reader_rotate), Toast.LENGTH_SHORT).show(); + return true; }); - findViewById(R.id.btn_download).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Intent i = new Intent(ViewImageDetailActivity.this, FilePickerActivity.class); - i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false); - i.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, true); - i.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_DIR); - i.putExtra(FilePickerActivity.EXTRA_START_PATH, - GlobalConfig.pathPickedSave == null || GlobalConfig.pathPickedSave.length() == 0 ? - Environment.getExternalStorageDirectory().getPath() : GlobalConfig.pathPickedSave); - startActivityForResult(i, 0); - } + findViewById(R.id.btn_download).setOnClickListener(v -> { + Intent i = new Intent(ViewImageDetailActivity.this, FilePickerActivity.class); + i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false); + i.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, true); + i.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_DIR); + i.putExtra(FilePickerActivity.EXTRA_START_PATH, + GlobalConfig.pathPickedSave == null || GlobalConfig.pathPickedSave.length() == 0 ? + Environment.getExternalStorageDirectory().getPath() : GlobalConfig.pathPickedSave); + startActivityForResult(i, 0); }); - findViewById(R.id.btn_download).setOnLongClickListener(new View.OnLongClickListener() { - @Override - public boolean onLongClick(View v) { - Toast.makeText(ViewImageDetailActivity.this, getResources().getString(R.string.reader_download), Toast.LENGTH_SHORT).show(); - return true; - } + findViewById(R.id.btn_download).setOnLongClickListener(v -> { + Toast.makeText(ViewImageDetailActivity.this, getResources().getString(R.string.reader_download), Toast.LENGTH_SHORT).show(); + return true; }); } @@ -185,7 +174,9 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { } else { Uri uri = data.getData(); // Do something with the URI - runSaveProcedure(uri.toString()); + if (uri != null) { + runSaveProcedure(uri.toString()); + } } } } @@ -200,7 +191,7 @@ private void runSaveProcedure(String uri) { .inputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) .input( "", "", false, new MaterialDialog.InputCallback() { @Override - public void onInput(MaterialDialog dialog, final CharSequence input) { + public void onInput(@NonNull MaterialDialog dialog, final CharSequence input) { if(LightCache.testFileExist(newuri + File.separator + input + ".jpg")) { // judge force write new MaterialDialog.Builder(ViewImageDetailActivity.this) @@ -249,51 +240,45 @@ protected void onResume() { } private void hideNavigationBar() { - // set navigation bar status, remember to disable "setNavigationBarTintEnabled" - final int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; // This work only for android 4.4+ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + // set navigation bar status, remember to disable "setNavigationBarTintEnabled" + final int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; getWindow().getDecorView().setSystemUiVisibility(flags); // Code below is to handle presses of Volume up or Volume down. // Without this, after pressing volume buttons, the navigation bar will // show up and won't hide final View decorView = getWindow().getDecorView(); - decorView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() { - @Override - public void onSystemUiVisibilityChange(int visibility) { - if((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) { - decorView.setSystemUiVisibility(flags); - } + decorView.setOnSystemUiVisibilityChangeListener(visibility -> { + if((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) { + decorView.setSystemUiVisibility(flags); } }); } } private void showNavigationBar() { - // set navigation bar status, remember to disable "setNavigationBarTintEnabled" - final int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; // This work only for android 4.4+ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + // set navigation bar status, remember to disable "setNavigationBarTintEnabled" + final int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; getWindow().getDecorView().setSystemUiVisibility(flags); // Code below is to handle presses of Volume up or Volume down. // Without this, after pressing volume buttons, the navigation bar will // show up and won't hide final View decorView = getWindow().getDecorView(); - decorView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() { - @Override - public void onSystemUiVisibilityChange(int visibility) { - if((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) { - decorView.setSystemUiVisibility(flags); - } + decorView.setOnSystemUiVisibilityChangeListener(visibility -> { + if((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) { + decorView.setSystemUiVisibility(flags); } }); } diff --git a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/api/Wenku8API.java b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/api/Wenku8API.java index e7244945..f9c7b6a9 100644 --- a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/api/Wenku8API.java +++ b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/api/Wenku8API.java @@ -268,7 +268,7 @@ public static int getErrorInfo_ResId(int errNo) { * This part are the old API writing ways. * It's not efficient enough, and maybe bug-hidden. */ - private static Map getEncryptedMAP(String str) { + static Map getEncryptedMAP(String str) { Map params = new HashMap<>(); params.put("request", LightBase64.EncodeBase64(str+"&timetoken="+System.currentTimeMillis())); return params; @@ -276,8 +276,11 @@ private static Map getEncryptedMAP(String str) { private static ContentValues getEncryptedCV(String str) { ContentValues cv = new ContentValues(); - cv.put("request",LightBase64.EncodeBase64(str+"&timetoken="+System.currentTimeMillis())); -// Log.e("MewX", "request = " + LightBase64.EncodeBase64(str+"&timetoken="+System.currentTimeMillis())); + Map map = getEncryptedMAP(str); + for (String key : map.keySet()) { + // better than running encryption again + cv.put(key, map.get(key)); + } return cv; } diff --git a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/reader/activity/Wenku8ReaderActivityV1.java b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/reader/activity/Wenku8ReaderActivityV1.java index 639d691c..34a6fbae 100644 --- a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/reader/activity/Wenku8ReaderActivityV1.java +++ b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/reader/activity/Wenku8ReaderActivityV1.java @@ -95,11 +95,11 @@ protected void onCreate(Bundle savedInstanceState) { // tempNavBarHeight = LightTool.getNavigationBarSize(this).y; // set indicator enable - Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar_actionbar); + Toolbar mToolbar = findViewById(R.id.toolbar_actionbar); setSupportActionBar(mToolbar); if(getSupportActionBar() != null) { getSupportActionBar().setTitle(volumeList.volumeName); - final Drawable upArrow = getResources().getDrawable(R.drawable.abc_ic_ab_back_material); + final Drawable upArrow = getResources().getDrawable(R.drawable.ic_back); if (upArrow != null) upArrow.setColorFilter(getResources().getColor(R.color.default_white), PorterDuff.Mode.SRC_ATOP); getSupportActionBar().setDisplayHomeAsUpEnabled(true); @@ -121,8 +121,7 @@ protected void onCreate(Bundle savedInstanceState) { } // find views - mSliderHolder = (RelativeLayout) findViewById(R.id.slider_holder); -// mSlidingLayout = (SlidingLayout) findViewById(R.id.sliding_layout); + mSliderHolder = findViewById(R.id.slider_holder); // UIL setting if(ImageLoader.getInstance() == null || !ImageLoader.getInstance().isInited()) { @@ -160,14 +159,14 @@ public boolean onCreateOptionsMenu(Menu menu) { } private void hideNavigationBar() { - // set navigation bar status, remember to disable "setNavigationBarTintEnabled" - final int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; // This work only for android 4.4+ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + // set navigation bar status, remember to disable "setNavigationBarTintEnabled" + final int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; getWindow().getDecorView().setSystemUiVisibility(flags); // Code below is to handle presses of Volume up or Volume down. @@ -273,7 +272,7 @@ public View getView(View contentView, WenkuReaderPageView pageView) { contentView = getLayoutInflater().inflate(R.layout.layout_reader_swipe_page, null); // prevent memory leak - final RelativeLayout rl = (RelativeLayout) contentView.findViewById(R.id.page_holder); + final RelativeLayout rl = contentView.findViewById(R.id.page_holder); rl.removeAllViews(); ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); rl.addView(pageView, lp); @@ -520,7 +519,7 @@ public void onClick(View v) { findViewById(R.id.reader_bot_seeker).setVisibility(View.INVISIBLE); isOpen = !isOpen; - DiscreteSeekBar seeker = (DiscreteSeekBar) findViewById(R.id.reader_seekbar); + DiscreteSeekBar seeker = findViewById(R.id.reader_seekbar); seeker.setMin(1); seeker.setProgress(mSlidingPageAdapter.getCurrentFirstLineIndex() + 1); // bug here seeker.setMax(loader.getElementCount()); @@ -580,10 +579,10 @@ public void onClick(View v) { isOpen = !isOpen; // set all listeners - DiscreteSeekBar seekerFontSize = (DiscreteSeekBar) findViewById(R.id.reader_font_size_seeker), - seekerLineDistance = (DiscreteSeekBar) findViewById(R.id.reader_line_distance_seeker), - seekerParagraphDistance = (DiscreteSeekBar) findViewById(R.id.reader_paragraph_distance_seeker), - seekerParagraphEdgeDistance = (DiscreteSeekBar) findViewById(R.id.reader_paragraph_edge_distance_seeker); + DiscreteSeekBar seekerFontSize = findViewById(R.id.reader_font_size_seeker), + seekerLineDistance = findViewById(R.id.reader_line_distance_seeker), + seekerParagraphDistance = findViewById(R.id.reader_paragraph_distance_seeker), + seekerParagraphEdgeDistance = findViewById(R.id.reader_paragraph_edge_distance_seeker); seekerFontSize.setProgress(setting.getFontSize()); seekerFontSize.setOnProgressChangeListener(new DiscreteSeekBar.OnProgressChangeListener() { diff --git a/studio-android/LightNovelLibrary/app/src/main/res/drawable/ic_svg_back.xml b/studio-android/LightNovelLibrary/app/src/main/res/drawable/ic_svg_back.xml new file mode 100644 index 00000000..7f41f30e --- /dev/null +++ b/studio-android/LightNovelLibrary/app/src/main/res/drawable/ic_svg_back.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/studio-android/LightNovelLibrary/app/src/main/res/drawable/ic_svg_clear.xml b/studio-android/LightNovelLibrary/app/src/main/res/drawable/ic_svg_clear.xml new file mode 100644 index 00000000..96312bcc --- /dev/null +++ b/studio-android/LightNovelLibrary/app/src/main/res/drawable/ic_svg_clear.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/studio-android/LightNovelLibrary/app/src/main/res/layout/toolbar_search.xml b/studio-android/LightNovelLibrary/app/src/main/res/layout/toolbar_search.xml index 982596f7..a5c09eb4 100644 --- a/studio-android/LightNovelLibrary/app/src/main/res/layout/toolbar_search.xml +++ b/studio-android/LightNovelLibrary/app/src/main/res/layout/toolbar_search.xml @@ -73,7 +73,7 @@ android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" - android:src="@drawable/abc_ic_clear_material"/> + android:src="@drawable/ic_svg_clear"/> \ No newline at end of file diff --git a/studio-android/LightNovelLibrary/app/src/main/res/values/strings.xml b/studio-android/LightNovelLibrary/app/src/main/res/values/strings.xml index 210b9f5e..adc811ac 100644 --- a/studio-android/LightNovelLibrary/app/src/main/res/values/strings.xml +++ b/studio-android/LightNovelLibrary/app/src/main/res/values/strings.xml @@ -1,7 +1,7 @@ 轻小说文库 - MewX与轻小说文库(Wenku8.com)合作的轻小说阅读app。 + MewX与轻小说文库(Wenku8.com)合作的轻小说阅读app。 MewX ZERO Architect diff --git a/studio-android/LightNovelLibrary/app/src/test/java/org/mewx/wenku8/global/api/Wenku8APITest.java b/studio-android/LightNovelLibrary/app/src/test/java/org/mewx/wenku8/global/api/Wenku8APITest.java new file mode 100644 index 00000000..bb2052c3 --- /dev/null +++ b/studio-android/LightNovelLibrary/app/src/test/java/org/mewx/wenku8/global/api/Wenku8APITest.java @@ -0,0 +1,55 @@ +package org.mewx.wenku8.global.api; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mewx.wenku8.util.LightBase64; +import org.mockito.stubbing.Answer; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import java.util.Base64; +import java.util.Map; + +import static org.mockito.Matchers.any; + + +@RunWith(PowerMockRunner.class) +@PrepareForTest({System.class, LightBase64.class, Wenku8API.class}) +public class Wenku8APITest { + + private static final long CURRENT_TIME = System.currentTimeMillis(); + + @Before + public void init() { + // mock base64 because it's on Android + PowerMockito.mockStatic(LightBase64.class); + PowerMockito.when(LightBase64.EncodeBase64(any(String.class))).thenAnswer((Answer) invocation -> { + Object[] args = invocation.getArguments(); + String input = (String) args[0]; + return new String(Base64.getEncoder().encode(input.getBytes())); + }); + + // init time and make time millis fixed + PowerMockito.mockStatic(System.class); + PowerMockito.when(System.currentTimeMillis()).thenReturn(CURRENT_TIME); + + // still need to spy current object + PowerMockito.spy(Wenku8API.class); + } + + @Test + public void timeStampFixed() { + Assert.assertEquals(System.currentTimeMillis(), CURRENT_TIME); + } + + @Test + public void testGetEncryptedMAP() { + final String str = "test"; + Map map = Wenku8API.getEncryptedMAP(str); + Assert.assertEquals(map.size(), 1); + Assert.assertEquals(map.get("request"), LightBase64.EncodeBase64(str + "&timetoken=" + CURRENT_TIME)); + } +} \ No newline at end of file From bcf6ab209ea82d34b427071ae1d3f109c4435cca Mon Sep 17 00:00:00 2001 From: MewX Date: Tue, 12 Jun 2018 00:07:12 +0930 Subject: [PATCH 5/6] #18 daily push --- .../wenku8/activity/NovelChapterActivity.java | 6 +- .../wenku8/activity/NovelInfoActivity.java | 176 ++++++++---------- .../org/mewx/wenku8/global/GlobalConfig.java | 1 + .../mewx/wenku8/global/api/ReviewList.java | 98 ++++++++++ .../mewx/wenku8/global/api/Wenku8Parser.java | 7 + .../src/main/res/drawable-hdpi/ic_flag.png | Bin 1047 -> 0 bytes .../src/main/res/drawable-xhdpi/ic_flag.png | Bin 1077 -> 0 bytes .../src/main/res/drawable-xxhdpi/ic_flag.png | Bin 1137 -> 0 bytes .../app/src/main/res/drawable/ic_svg_flag.xml | 11 ++ .../src/main/res/drawable/ic_svg_forum.xml | 11 ++ .../app/src/main/res/menu/menu_novel_info.xml | 7 +- .../src/main/res/values-zh-rHK/strings.xml | 1 + .../src/main/res/values-zh-rTW/strings.xml | 1 + .../app/src/main/res/values/strings.xml | 1 + .../wenku8/global/api/Wenku8ParserTest.java | 28 +++ 15 files changed, 244 insertions(+), 104 deletions(-) create mode 100644 studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/api/ReviewList.java delete mode 100644 studio-android/LightNovelLibrary/app/src/main/res/drawable-hdpi/ic_flag.png delete mode 100644 studio-android/LightNovelLibrary/app/src/main/res/drawable-xhdpi/ic_flag.png delete mode 100644 studio-android/LightNovelLibrary/app/src/main/res/drawable-xxhdpi/ic_flag.png create mode 100644 studio-android/LightNovelLibrary/app/src/main/res/drawable/ic_svg_flag.xml create mode 100644 studio-android/LightNovelLibrary/app/src/main/res/drawable/ic_svg_forum.xml create mode 100644 studio-android/LightNovelLibrary/app/src/test/java/org/mewx/wenku8/global/api/Wenku8ParserTest.java diff --git a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/NovelChapterActivity.java b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/NovelChapterActivity.java index e408ab62..c07d63d0 100644 --- a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/NovelChapterActivity.java +++ b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/NovelChapterActivity.java @@ -54,7 +54,7 @@ protected void onCreate(Bundle savedInstanceState) { volumeList = (VolumeList) getIntent().getSerializableExtra("volume"); // set indicator enable - Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar_actionbar); + Toolbar mToolbar = findViewById(R.id.toolbar_actionbar); setSupportActionBar(mToolbar); final Drawable upArrow = getResources().getDrawable(R.drawable.ic_svg_back); if(getSupportActionBar() != null && upArrow != null) { @@ -81,14 +81,14 @@ protected void onCreate(Bundle savedInstanceState) { } // get views and set title - LinearLayout mLinearLayout = (LinearLayout) findViewById(R.id.novel_chapter_scroll); + LinearLayout mLinearLayout = findViewById(R.id.novel_chapter_scroll); getSupportActionBar().setTitle(volumeList.volumeName); for(final ChapterInfo ci : volumeList.chapterList) { // get view RelativeLayout rl = (RelativeLayout) LayoutInflater.from(NovelChapterActivity.this).inflate(R.layout.view_novel_chapter_item, null); - TextView tv = (TextView) rl.findViewById(R.id.chapter_title); + TextView tv = rl.findViewById(R.id.chapter_title); tv.setText(ci.chapterName); rl.findViewById(R.id.chapter_btn).setOnClickListener(new View.OnClickListener() { @Override diff --git a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/NovelInfoActivity.java b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/NovelInfoActivity.java index bbb35a37..cc2d317a 100644 --- a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/NovelInfoActivity.java +++ b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/NovelInfoActivity.java @@ -1,7 +1,6 @@ package org.mewx.wenku8.activity; import android.content.ContentValues; -import android.content.DialogInterface; import android.content.Intent; import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; @@ -97,7 +96,7 @@ protected void onCreate(Bundle savedInstanceState) { title = getIntent().getStringExtra("title"); // set indicator enable - Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar_actionbar); + Toolbar mToolbar = findViewById(R.id.toolbar_actionbar); setSupportActionBar(mToolbar); final Drawable upArrow = getResources().getDrawable(R.drawable.ic_svg_back); if(getSupportActionBar() != null && upArrow != null) { @@ -129,21 +128,21 @@ protected void onCreate(Bundle savedInstanceState) { } // get views - rlMask = (RelativeLayout) findViewById(R.id.white_mask); - mLinearLayout = (LinearLayout) findViewById(R.id.novel_info_scroll); - llCardLayout = (LinearLayout) findViewById(R.id.item_card); - ivNovelCover = (ImageView) findViewById(R.id.novel_cover); - tvNovelTitle = (TextView) findViewById(R.id.novel_title); - tvNovelAuthor = (TextView) findViewById(R.id.novel_author); - tvNovelStatus = (TextView) findViewById(R.id.novel_status); - tvNovelUpdate = (TextView) findViewById(R.id.novel_update); - tvNovelShortIntro = (TableRow) findViewById(R.id.novel_intro_row); - tvNovelFullIntro = (TextView) findViewById(R.id.novel_intro_full); - ibNovelOption = (ImageButton) findViewById(R.id.novel_option); - fabFavorate = (FloatingActionButton) findViewById(R.id.fab_favorate); - fabDownload = (FloatingActionButton) findViewById(R.id.fab_download); - famMenu = (FloatingActionsMenu) findViewById(R.id.multiple_actions); - spb = (SmoothProgressBar) findViewById(R.id.spb); + rlMask = findViewById(R.id.white_mask); + mLinearLayout = findViewById(R.id.novel_info_scroll); + llCardLayout = findViewById(R.id.item_card); + ivNovelCover = findViewById(R.id.novel_cover); + tvNovelTitle = findViewById(R.id.novel_title); + tvNovelAuthor = findViewById(R.id.novel_author); + tvNovelStatus = findViewById(R.id.novel_status); + tvNovelUpdate = findViewById(R.id.novel_update); + tvNovelShortIntro = findViewById(R.id.novel_intro_row); + tvNovelFullIntro = findViewById(R.id.novel_intro_full); + ibNovelOption = findViewById(R.id.novel_option); + fabFavorate = findViewById(R.id.fab_favorate); + fabDownload = findViewById(R.id.fab_download); + famMenu = findViewById(R.id.multiple_actions); + spb = findViewById(R.id.spb); // hide view and set colors tvNovelTitle.setText(title); @@ -166,15 +165,12 @@ else if(LightCache.testFileExist(GlobalConfig.getSecondStoragePath() + "imgs" + getSupportActionBar().setTitle(R.string.action_novel_info); spb.setVisibility(View.INVISIBLE); // wait for runnable Handler handler = new Handler(); - handler.postDelayed(new Runnable() { - @Override - public void run() { - spb.setVisibility(View.VISIBLE); - if (from.equals(FromLocal)) - refreshInfoFromLocal(); - else - refreshInfoFromCloud(); - } + handler.postDelayed(() -> { + spb.setVisibility(View.VISIBLE); + if (from.equals(FromLocal)) + refreshInfoFromLocal(); + else + refreshInfoFromCloud(); }, 500); @@ -190,40 +186,34 @@ public void onMenuCollapsed() { rlMask.setVisibility(View.INVISIBLE); } }); - rlMask.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - // Collapse the fam - if (famMenu.isExpanded()) - famMenu.collapse(); - } + rlMask.setOnClickListener(v -> { + // Collapse the fam + if (famMenu.isExpanded()) + famMenu.collapse(); }); if(Build.VERSION.SDK_INT >= 16) { tvNovelTitle.setBackground(getResources().getDrawable(R.drawable.btn_menu_item)); tvNovelAuthor.setBackground(getResources().getDrawable(R.drawable.btn_menu_item)); } - tvNovelTitle.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if(isLoading) { - Toast.makeText(NovelInfoActivity.this, getResources().getString(R.string.system_loading_please_wait), Toast.LENGTH_SHORT).show(); - return; - } - - // show aid: title - // Snackbar.make(mLinearLayout, aid + ": " + mNovelItemMeta.title, Snackbar.LENGTH_SHORT).show(); - new MaterialDialog.Builder(NovelInfoActivity.this) - .theme(Theme.LIGHT) - .titleColorRes(R.color.dlgTitleColor) - .backgroundColorRes(R.color.dlgBackgroundColor) - .contentColorRes(R.color.dlgContentColor) - .positiveColorRes(R.color.dlgPositiveButtonColor) - .title(R.string.dialog_content_novel_title) - .content(aid + ": " + mNovelItemMeta.title) - .contentGravity(GravityEnum.CENTER) - .positiveText(R.string.dialog_positive_known) - .show(); + tvNovelTitle.setOnClickListener(v -> { + if(isLoading) { + Toast.makeText(NovelInfoActivity.this, getResources().getString(R.string.system_loading_please_wait), Toast.LENGTH_SHORT).show(); + return; } + + // show aid: title + // Snackbar.make(mLinearLayout, aid + ": " + mNovelItemMeta.title, Snackbar.LENGTH_SHORT).show(); + new MaterialDialog.Builder(NovelInfoActivity.this) + .theme(Theme.LIGHT) + .titleColorRes(R.color.dlgTitleColor) + .backgroundColorRes(R.color.dlgBackgroundColor) + .contentColorRes(R.color.dlgContentColor) + .positiveColorRes(R.color.dlgPositiveButtonColor) + .title(R.string.dialog_content_novel_title) + .content(aid + ": " + mNovelItemMeta.title) + .contentGravity(GravityEnum.CENTER) + .positiveText(R.string.dialog_positive_known) + .show(); }); tvNovelAuthor.setOnClickListener(new View.OnClickListener() { @Override @@ -326,7 +316,7 @@ else if(!GlobalConfig.testInLocalBookshelf(aid)) { .itemsCallback(new MaterialDialog.ListCallback() { @Override public void onSelection(MaterialDialog dialog, View view, int which, CharSequence text) { - /** + /* * 0 检查更新 * 1 更新下载 * 2 覆盖下载 @@ -351,14 +341,11 @@ public void onPositive(MaterialDialog dialog) { .content(R.string.dialog_content_downloading) .progress(false, 1, true) .cancelable(true) - .cancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - isLoading = false; - auct.cancel(true); - pDialog.dismiss(); - pDialog = null; - } + .cancelListener(dialog12 -> { + isLoading = false; + auct.cancel(true); + pDialog.dismiss(); + pDialog = null; }) .show(); @@ -397,14 +384,11 @@ public void onPositive(MaterialDialog dialog) { .content(R.string.dialog_content_downloading) .progress(false, 1, true) .cancelable(true) - .cancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - isLoading = false; - auct.cancel(true); - pDialog.dismiss(); - pDialog = null; - } + .cancelListener(dialog1 -> { + isLoading = false; + auct.cancel(true); + pDialog.dismiss(); + pDialog = null; }) .show(); @@ -443,14 +427,11 @@ public void onPositive(MaterialDialog dialog) { .content(R.string.dialog_content_downloading) .progress(false, 1, true) .cancelable(true) - .cancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - isLoading = false; - auct.cancel(true); - pDialog.dismiss(); - pDialog = null; - } + .cancelListener(dialog13 -> { + isLoading = false; + auct.cancel(true); + pDialog.dismiss(); + pDialog = null; }) .show(); @@ -636,6 +617,9 @@ public void onPositive(MaterialDialog dialog) { else { Toast.makeText(this, "未发现保存的进度,可能是未读或上次读完了某卷~ 那么,开始下一卷吧~", Toast.LENGTH_SHORT).show(); } + } else if (menuItem.getItemId() == R.id.action_go_to_forum) { + // TODO: + Toast.makeText(this, "test", Toast.LENGTH_SHORT).show(); } return super.onOptionsItemSelected(menuItem); } @@ -668,7 +652,7 @@ protected Integer doInBackground(Integer... params) { try { if(fromLocal) { novelFullMeta = GlobalConfig.loadFullFileFromSaveFolder("intro", aid + "-intro.xml"); - if(novelFullMeta == null || novelFullMeta.equals("")) return -9; + if(novelFullMeta.equals("")) return -9; } else { ContentValues cv = Wenku8API.getNovelFullMeta(aid, GlobalConfig.getCurrentLang()); @@ -688,7 +672,7 @@ protected Integer doInBackground(Integer... params) { try { if(fromLocal) { novelFullIntro = GlobalConfig.loadFullFileFromSaveFolder("intro", aid + "-introfull.xml"); - if(novelFullIntro == null || novelFullIntro.equals("")) return -9; + if(novelFullIntro.equals("")) return -9; } else { ContentValues cvFullIntroRequest = Wenku8API.getNovelFullIntro(aid, GlobalConfig.getCurrentLang()); @@ -708,7 +692,7 @@ protected Integer doInBackground(Integer... params) { try { if(fromLocal) { novelFullVolume = GlobalConfig.loadFullFileFromSaveFolder("intro", aid + "-volume.xml"); - if(novelFullVolume == null || novelFullVolume.equals("")) return -9; + if(novelFullVolume.equals("")) return -9; } else { ContentValues cv = Wenku8API.getNovelIndex(aid, GlobalConfig.getCurrentLang()); @@ -792,20 +776,17 @@ else if(integer < 0) RelativeLayout rl = (RelativeLayout) LayoutInflater.from(NovelInfoActivity.this).inflate(R.layout.view_novel_chapter_item, null); // set text and listeners - TextView tv = (TextView) rl.findViewById(R.id.chapter_title); + TextView tv = rl.findViewById(R.id.chapter_title); tv.setText(vl.volumeName); if(vl.inLocal) ((TextView) rl.findViewById(R.id.chapter_status)).setText(getResources().getString(R.string.bookshelf_inlocal)); - rl.findViewById(R.id.chapter_btn).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - // jump to chapter select activity - Intent intent = new Intent(NovelInfoActivity.this, NovelChapterActivity.class); - intent.putExtra("aid", aid); - intent.putExtra("volume", vl); - intent.putExtra("from", from); - startActivity(intent); - } + rl.findViewById(R.id.chapter_btn).setOnClickListener(v -> { + // jump to chapter select activity + Intent intent = new Intent(NovelInfoActivity.this, NovelChapterActivity.class); + intent.putExtra("aid", aid); + intent.putExtra("volume", vl); + intent.putExtra("from", from); + startActivity(intent); }); // add to scroll view @@ -1079,12 +1060,7 @@ protected void onPreExecute() { .content(R.string.dialog_content_downloading) .progress(false, 1, true) .cancelable(true) - .cancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - loading = false; - } - }) + .cancelListener(dialog -> loading = false) .show(); md.setProgress(0); md.setMaxProgress(1); @@ -1106,7 +1082,7 @@ protected Wenku8Error.ErrorCode doInBackground(Integer[]... params) { // load from local first if (!loading) return Wenku8Error.ErrorCode.USER_CANCELLED_TASK; // cancel String xml = GlobalConfig.loadFullFileFromSaveFolder("novel", tempCi.cid + ".xml"); // prevent empty file - if (xml == null || xml.length() == 0 ) { + if (xml.length() == 0) { byte[] tempXml = LightNetwork.LightHttpPostConnection(Wenku8API.getBaseURL(), cv); if (tempXml == null) return Wenku8Error.ErrorCode.NETWORK_ERROR; // network error xml = new String(tempXml, "UTF-8"); diff --git a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/GlobalConfig.java b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/GlobalConfig.java index e69c6b7b..4d18f830 100644 --- a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/GlobalConfig.java +++ b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/GlobalConfig.java @@ -325,6 +325,7 @@ private static boolean writeFullSaveFileContent(String FileName, @NonNull String return true; } + @NonNull public static String loadFullFileFromSaveFolder(String subFolderName, String fileName) { return loadFullSaveFileContent(subFolderName + File.separator + fileName); diff --git a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/api/ReviewList.java b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/api/ReviewList.java new file mode 100644 index 00000000..a1f00c07 --- /dev/null +++ b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/api/ReviewList.java @@ -0,0 +1,98 @@ +package org.mewx.wenku8.global.api; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +public class ReviewList { + + public static class Review { + private int rid; // review id + private Date postTime; + private int noReplies; + private Date lastReplyTime; + private int uid; // post user + private String title; // review title + + public Review(int rid, Date postTime, int noReplies, Date lastReplyTime, int uid, String title) { + this.rid = rid; + this.postTime = postTime; + this.noReplies = noReplies; + this.lastReplyTime = lastReplyTime; + this.uid = uid; + this.title = title; + } + + public int getRid() { + return rid; + } + + public void setRid(int rid) { + this.rid = rid; + } + + public Date getPostTime() { + return postTime; + } + + public void setPostTime(Date postTime) { + this.postTime = postTime; + } + + public int getNoReplies() { + return noReplies; + } + + public void setNoReplies(int noReplies) { + this.noReplies = noReplies; + } + + public Date getLastReplyTime() { + return lastReplyTime; + } + + public void setLastReplyTime(Date lastReplyTime) { + this.lastReplyTime = lastReplyTime; + } + + public int getUid() { + return uid; + } + + public void setUid(int uid) { + this.uid = uid; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + } + + private List list = new ArrayList<>(); + private int totalPage = 1; + private int currentPage = 1; // 1-totalPage + + public List getList() { + return list; + } + + public int getTotalPage() { + return totalPage; + } + + public void setTotalPage(int totalPage) { + this.totalPage = totalPage; + } + + public int getCurrentPage() { + return currentPage; + } + + public void setCurrentPage(int currentPage) { + this.currentPage = currentPage; + } +} diff --git a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/api/Wenku8Parser.java b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/api/Wenku8Parser.java index 8ef37d8f..5113812c 100644 --- a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/api/Wenku8Parser.java +++ b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/api/Wenku8Parser.java @@ -224,4 +224,11 @@ static public ArrayList getVolumeList(String xml) { return null; } } + + static public ReviewList parseReviewList(String xml) { + ReviewList reviewList = new ReviewList(); + // TODO: + + return reviewList; + } } diff --git a/studio-android/LightNovelLibrary/app/src/main/res/drawable-hdpi/ic_flag.png b/studio-android/LightNovelLibrary/app/src/main/res/drawable-hdpi/ic_flag.png deleted file mode 100644 index 8d63dfcc9be68de1ee5bb7c27b3c351c38ab8793..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1047 zcmaJ=OK1~87~WDzAEZ!vY6a`M1s~Y#E3alrY@2M;M!Kb@fyP@myOZwH?#_01Vz#}s zR6zuh9@T>if_M_4f(H@t0Y$8yL{P+or|PBP>!jA%G)X-e7iRzYhwuCT$NY0)a$>Zj zeSbSa5FME@F^g@Vw_1Jp-}`p`G&VhGB#)+G5tU^d5W^}g05W69vmgs(b#dW2h!aHf zVLg{ed1+iwph3$XhIS1Lvk4+T=vuNe2M}2Rv$~m}wjVsANL@`((_x8~tQ64nu_YT! zEluQtcdNv5C;$S@rV zC@dEuqcNHbN20N4KgnaCVFwtV4X`mG928idtbP=ZW~)UZE2gWlu$Q1Tge-w!%H=X$ z4${z`Ww=-@#;`oY^8t(qIEyBd-GJ%z)f7bFD7J1P9h#)4C>LM}B`BQfZV84}mo=Sg zn{dMzSGE|AX1$VXKuP*P)G+F32W7!tzW)?#aYd+<3}B)fSKZ@=8gjjHFf1Hd1h#$#sA(G-WTk9DZ=4I) zP_N2W8|T6|+&WHOx3h^)NTc5gDuN{0T-MrLO z+Ptm!y6&#s_|ek2ym4s5_w4;Q|CP3({&USO{#%+bx~)BF`Ovfw==|#UZLAEv(BAZx rHnq0#%+x~YYWhI%^X11|-77>hkviV{d;I#!eebDeMkd5N$(hwZ!?R8V diff --git a/studio-android/LightNovelLibrary/app/src/main/res/drawable-xhdpi/ic_flag.png b/studio-android/LightNovelLibrary/app/src/main/res/drawable-xhdpi/ic_flag.png deleted file mode 100644 index 52a84388b6c303917dbb2f6d548d687789122838..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1077 zcmaJ=TSyd97#5TxJ88H%vpEPnKR8C-BARi z2ns@}9)li&ibxD85)v$-3qDl@OXy2V4}y{Q=1b6-b=P`m8#r^$fB3%dzn&W%@zYh6 z`zr~8sEW373B1$h+E$ML`ms9`c-x1lx@6;u^F<8*#zNlHdJ2d1BmPay^<23)@EK&q$CEYE_aNHsUeV&T8A~z zIUG+4!+nBJq?(&ZzrkVw86ciCGj#{ZjaaJJw-aOO*0L&gRwF`*6m~&2U++i>`fEXY=Vmvd|@jl27wsSpiJh| zW~I`xw3O5al4{z5C4Ur<+ehhcXvudZX4{Lrt5=U3g9qyVqF!pQl;BD*M`I#K~`1$htRK>FsCZTELp10lNHywTSyd97@pYJVzUT?(x93q3Zr%|tGhOXtL^TrxzUPj3)+nwXU^)RGiRJRwxbnY zh@dM{2=)|odFUadf(WECi9)oXBFaLnpz=WotcMZ3o$W)Q zf*@S$)MNu{h;I{QsL_(+L))5x(F9RZWgC**3J}=@npHhWed~Wnk*X4;>iuyxZbU$f zTGM5M?OnA=xvN#?6{@O|tgr=4paCS2w$`Rwf*qtXyaL`k#|%YgTu^I}nika%uOlPS z1f-u1cx9F=Bg=W3^9RcL@{Obq+YGyj@v&Z(7yP9H>m#!dg`=5DN=S&+*;v>LQY{D> z0>h-!X*yj>L$jITc%EliALH|Rv4_{{)RAO+b!$zIK?Ig;ss>V_PCATI6YM}i3M-vX zK{IA(bt_vYTrkF#42GjwC#9TYJpO-IO`GwyPy)>A{U@=N>@)zA02b^pW!$*b8Yh$? zL`)zdXeJ?S%T=+i1tMs*K!c1#GF2l>>Q!BVX={B36ORiq-9nNsgP0hkFbl1!iV%qU zqHH7-4u=B)j*FIs*wT>5^5GC4<^1JkYz`|zxkCdw%3+mRY$Pw%83)b4kwsvt`+-tz zLXFI%EvWgm@Ok;NSS7y}oJgKL7%YZyn)_F?b4PfBobAl$Vq<3bfsQBM#G`%oD!PEL z#mAT!O4{!xM>)?RTjZ|WuyQkc**ftya_>OV%`bBv?<(o@oGbi2w(a_(!tr_Iy)P@z zci-K!Ri!RnqzIS0ponc8I5NlOK9f8e>*?a;sU2JD8>dE(4K=$`3Oly!!H3ts=KefY z>3K@;JW>3k?K!u|o< + + + + diff --git a/studio-android/LightNovelLibrary/app/src/main/res/drawable/ic_svg_forum.xml b/studio-android/LightNovelLibrary/app/src/main/res/drawable/ic_svg_forum.xml new file mode 100644 index 00000000..307991b2 --- /dev/null +++ b/studio-android/LightNovelLibrary/app/src/main/res/drawable/ic_svg_forum.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/studio-android/LightNovelLibrary/app/src/main/res/menu/menu_novel_info.xml b/studio-android/LightNovelLibrary/app/src/main/res/menu/menu_novel_info.xml index ac5e71dd..553a00f5 100644 --- a/studio-android/LightNovelLibrary/app/src/main/res/menu/menu_novel_info.xml +++ b/studio-android/LightNovelLibrary/app/src/main/res/menu/menu_novel_info.xml @@ -5,6 +5,11 @@ + diff --git a/studio-android/LightNovelLibrary/app/src/main/res/values-zh-rHK/strings.xml b/studio-android/LightNovelLibrary/app/src/main/res/values-zh-rHK/strings.xml index 5486332c..fbcecb98 100644 --- a/studio-android/LightNovelLibrary/app/src/main/res/values-zh-rHK/strings.xml +++ b/studio-android/LightNovelLibrary/app/src/main/res/values-zh-rHK/strings.xml @@ -204,4 +204,5 @@ 請在有圖的頁面點擊此按鈕看圖~ MewX與輕小說文庫(Wenku8.com)合作的輕小說閱讀app。 由於歷史原因,缺少必要的權限時,app可能無法正常工作,請考慮授予相應權限 + 進入評論區 diff --git a/studio-android/LightNovelLibrary/app/src/main/res/values-zh-rTW/strings.xml b/studio-android/LightNovelLibrary/app/src/main/res/values-zh-rTW/strings.xml index 5486332c..fbcecb98 100644 --- a/studio-android/LightNovelLibrary/app/src/main/res/values-zh-rTW/strings.xml +++ b/studio-android/LightNovelLibrary/app/src/main/res/values-zh-rTW/strings.xml @@ -204,4 +204,5 @@ 請在有圖的頁面點擊此按鈕看圖~ MewX與輕小說文庫(Wenku8.com)合作的輕小說閱讀app。 由於歷史原因,缺少必要的權限時,app可能無法正常工作,請考慮授予相應權限 + 進入評論區 diff --git a/studio-android/LightNovelLibrary/app/src/main/res/values/strings.xml b/studio-android/LightNovelLibrary/app/src/main/res/values/strings.xml index adc811ac..b9f179ab 100644 --- a/studio-android/LightNovelLibrary/app/src/main/res/values/strings.xml +++ b/studio-android/LightNovelLibrary/app/src/main/res/values/strings.xml @@ -204,4 +204,5 @@ 段落间距 段落边距 请在有图的页面点击此按钮看图~ + 进入评论区 diff --git a/studio-android/LightNovelLibrary/app/src/test/java/org/mewx/wenku8/global/api/Wenku8ParserTest.java b/studio-android/LightNovelLibrary/app/src/test/java/org/mewx/wenku8/global/api/Wenku8ParserTest.java new file mode 100644 index 00000000..f0dc46b7 --- /dev/null +++ b/studio-android/LightNovelLibrary/app/src/test/java/org/mewx/wenku8/global/api/Wenku8ParserTest.java @@ -0,0 +1,28 @@ +package org.mewx.wenku8.global.api; + +import org.junit.Test; + +class Wenku8ParserTest { + @Test + void testParseReviewList() { + final String xml = "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + ""; + ReviewList reviewList = Wenku8Parser.parseReviewList(xml); + + // TODO: more tests + + } +} From 093723e24f326b5fb3035540c6eab6b1ea3627b4 Mon Sep 17 00:00:00 2001 From: MewX Date: Tue, 12 Jun 2018 23:11:07 +0930 Subject: [PATCH 6/6] #18 Added parser for review list --- .../LightNovelLibrary/app/build.gradle | 8 ++ .../app/proguard-rules-tests.pro | 15 ++++ .../LightNovelLibrary/app/proguard-rules.pro | 2 +- .../wenku8/global/api/Wenku8ParserTest.java | 66 ++++++++++++++++ .../wenku8/activity/NovelInfoActivity.java | 2 +- .../mewx/wenku8/global/api/ReviewList.java | 32 ++++++-- .../mewx/wenku8/global/api/Wenku8Parser.java | 76 ++++++++++++++++++- .../wenku8/global/api/Wenku8ParserTest.java | 28 ------- 8 files changed, 187 insertions(+), 42 deletions(-) create mode 100644 studio-android/LightNovelLibrary/app/proguard-rules-tests.pro create mode 100644 studio-android/LightNovelLibrary/app/src/androidTest/java/org/mewx/wenku8/global/api/Wenku8ParserTest.java delete mode 100644 studio-android/LightNovelLibrary/app/src/test/java/org/mewx/wenku8/global/api/Wenku8ParserTest.java diff --git a/studio-android/LightNovelLibrary/app/build.gradle b/studio-android/LightNovelLibrary/app/build.gradle index bb1af023..27e38b06 100644 --- a/studio-android/LightNovelLibrary/app/build.gradle +++ b/studio-android/LightNovelLibrary/app/build.gradle @@ -9,16 +9,19 @@ android { targetSdkVersion 27 versionCode 35 versionName "1.4" + testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner' } buildTypes { debug { debuggable true minifyEnabled true + testProguardFile 'proguard-rules-tests.pro' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } release { debuggable false minifyEnabled true + testProguardFile 'proguard-rules-tests.pro' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } @@ -78,6 +81,11 @@ dependencies { implementation 'com.umeng.sdk:common:1.5.0' implementation 'com.umeng.sdk:analytics:7.5.0' + androidTestImplementation 'com.android.support:support-annotations:27.1.1' + androidTestImplementation 'com.android.support.test:runner:1.0.2' + androidTestImplementation 'com.android.support.test:rules:1.0.2' + androidTestImplementation 'junit:junit:4.12' + testImplementation 'junit:junit:4.12' testImplementation 'org.mockito:mockito-all:1.10.19' testImplementation 'org.powermock:powermock-module-junit4:1.7.4' diff --git a/studio-android/LightNovelLibrary/app/proguard-rules-tests.pro b/studio-android/LightNovelLibrary/app/proguard-rules-tests.pro new file mode 100644 index 00000000..1b950fda --- /dev/null +++ b/studio-android/LightNovelLibrary/app/proguard-rules-tests.pro @@ -0,0 +1,15 @@ +# Proguard rules that are applied to your test apk/code. +-ignorewarnings + +-keepattributes *Annotation* + +-dontnote junit.framework.** +-dontnote junit.runner.** + +-dontwarn android.test.** +-dontwarn android.support.test.** +-dontwarn org.junit.** +-dontwarn org.hamcrest.** +-dontwarn com.squareup.javawriter.JavaWriter +# Uncomment this if you use Mockito +-dontwarn org.mockito.** diff --git a/studio-android/LightNovelLibrary/app/proguard-rules.pro b/studio-android/LightNovelLibrary/app/proguard-rules.pro index a006a766..0421fedf 100644 --- a/studio-android/LightNovelLibrary/app/proguard-rules.pro +++ b/studio-android/LightNovelLibrary/app/proguard-rules.pro @@ -17,7 +17,7 @@ #} # general --target 1.7 +-target 1.8 -optimizationpasses 5 #-dontoptimize -dontusemixedcaseclassnames diff --git a/studio-android/LightNovelLibrary/app/src/androidTest/java/org/mewx/wenku8/global/api/Wenku8ParserTest.java b/studio-android/LightNovelLibrary/app/src/androidTest/java/org/mewx/wenku8/global/api/Wenku8ParserTest.java new file mode 100644 index 00000000..db6c617c --- /dev/null +++ b/studio-android/LightNovelLibrary/app/src/androidTest/java/org/mewx/wenku8/global/api/Wenku8ParserTest.java @@ -0,0 +1,66 @@ +package org.mewx.wenku8.global.api; + +import android.support.test.filters.SmallTest; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.GregorianCalendar; + +@SmallTest +public class Wenku8ParserTest { + private final String REVIEW_LIST_XML = "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + ""; + + // TODO: more tests + + @Test + public void testParseReviewList() { + ReviewList reviewList = new ReviewList(); + Wenku8Parser.parseReviewList(reviewList, REVIEW_LIST_XML); + + Assert.assertEquals(reviewList.getTotalPage(), 12); + Assert.assertEquals(reviewList.getCurrentPage(), 1); + Assert.assertEquals(reviewList.getList().size(), 2); + ReviewList.Review review = reviewList.getList().get(0); + Assert.assertEquals(review.getRid(), 79800); + Assert.assertEquals(review.getPostTime().getTime(), + new GregorianCalendar(2013, 5, 25, 17, 16, 31).getTime().getTime()); + Assert.assertEquals(review.getNoReplies(), 1); + Assert.assertEquals(review.getLastReplyTime().getTime(), + new GregorianCalendar(2013, 5, 28, 18, 49, 16).getTime().getTime()); + Assert.assertEquals(review.getUid(), 81669); + Assert.assertEquals(review.getUserName(), "老衲0轻音"); + Assert.assertEquals(review.getTitle(), "前排……"); + + review = reviewList.getList().get(1); + Assert.assertEquals(review.getRid(), 79826); + Assert.assertEquals(review.getPostTime().getTime(), + new GregorianCalendar(2013, 5, 25, 23, 20, 2).getTime().getTime()); + Assert.assertEquals(review.getNoReplies(), 4); + Assert.assertEquals(review.getLastReplyTime().getTime(), + new GregorianCalendar(2013, 5, 27, 23, 42, 59).getTime().getTime()); + Assert.assertEquals(review.getUid(), 34924); + Assert.assertEquals(review.getUserName(), "冒险奏鸣"); + Assert.assertEquals(review.getTitle(), "有种神曲奏界的既视感"); + } + + + @Test + public void testParseReviewListPageTwo() { + // TODO + } +} diff --git a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/NovelInfoActivity.java b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/NovelInfoActivity.java index cc2d317a..a5bcd1bf 100644 --- a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/NovelInfoActivity.java +++ b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/activity/NovelInfoActivity.java @@ -619,7 +619,7 @@ public void onPositive(MaterialDialog dialog) { } } else if (menuItem.getItemId() == R.id.action_go_to_forum) { // TODO: - Toast.makeText(this, "test", Toast.LENGTH_SHORT).show(); + Toast.makeText(this, "下个版本这里就能点进评论区啦", Toast.LENGTH_SHORT).show(); } return super.onOptionsItemSelected(menuItem); } diff --git a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/api/ReviewList.java b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/api/ReviewList.java index a1f00c07..c468f9c9 100644 --- a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/api/ReviewList.java +++ b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/api/ReviewList.java @@ -1,5 +1,7 @@ package org.mewx.wenku8.global.api; +import android.support.annotation.NonNull; + import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -8,17 +10,19 @@ public class ReviewList { public static class Review { private int rid; // review id - private Date postTime; + @NonNull private Date postTime; private int noReplies; - private Date lastReplyTime; + @NonNull private Date lastReplyTime; + @NonNull private String userName; private int uid; // post user - private String title; // review title + @NonNull private String title; // review title - public Review(int rid, Date postTime, int noReplies, Date lastReplyTime, int uid, String title) { + public Review(int rid, @NonNull Date postTime, int noReplies, @NonNull Date lastReplyTime, @NonNull String userName, int uid, @NonNull String title) { this.rid = rid; this.postTime = postTime; this.noReplies = noReplies; this.lastReplyTime = lastReplyTime; + this.userName = userName; this.uid = uid; this.title = title; } @@ -31,11 +35,12 @@ public void setRid(int rid) { this.rid = rid; } + @NonNull public Date getPostTime() { return postTime; } - public void setPostTime(Date postTime) { + public void setPostTime(@NonNull Date postTime) { this.postTime = postTime; } @@ -47,11 +52,12 @@ public void setNoReplies(int noReplies) { this.noReplies = noReplies; } + @NonNull public Date getLastReplyTime() { return lastReplyTime; } - public void setLastReplyTime(Date lastReplyTime) { + public void setLastReplyTime(@NonNull Date lastReplyTime) { this.lastReplyTime = lastReplyTime; } @@ -63,18 +69,28 @@ public void setUid(int uid) { this.uid = uid; } + @NonNull public String getTitle() { return title; } - public void setTitle(String title) { + public void setTitle(@NonNull String title) { this.title = title; } + + @NonNull + public String getUserName() { + return userName; + } + + public void setUserName(@NonNull String userName) { + this.userName = userName; + } } private List list = new ArrayList<>(); private int totalPage = 1; - private int currentPage = 1; // 1-totalPage + private int currentPage = 0; // 1-totalPage, 0 means not yet loaded public List getList() { return list; diff --git a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/api/Wenku8Parser.java b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/api/Wenku8Parser.java index 5113812c..e23d0fcc 100644 --- a/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/api/Wenku8Parser.java +++ b/studio-android/LightNovelLibrary/app/src/main/java/org/mewx/wenku8/global/api/Wenku8Parser.java @@ -9,6 +9,8 @@ import java.io.StringReader; import java.util.ArrayList; +import java.util.Date; +import java.util.GregorianCalendar; import java.util.List; /** @@ -225,10 +227,76 @@ static public ArrayList getVolumeList(String xml) { } } - static public ReviewList parseReviewList(String xml) { - ReviewList reviewList = new ReviewList(); - // TODO: + /** + * save the new xsl into an existing review list + * @param reviewList the existing review list object + * @param xml the fetched xml + */ + static public void parseReviewList(ReviewList reviewList, String xml) { + reviewList.setCurrentPage(reviewList.getCurrentPage() + 1); - return reviewList; + try { + XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); + XmlPullParser xmlPullParser = factory.newPullParser(); + xmlPullParser.setInput(new StringReader(xml)); + int eventType = xmlPullParser.getEventType(); + + int rid = 0; // review id + Date postTime = new Date(); + int noReplies = 0; + Date lastReplyTime = new Date(); + String userName = ""; + int uid = 0; // post user + String title = ""; // review title + + while (eventType != XmlPullParser.END_DOCUMENT) { + switch (eventType) { + case XmlPullParser.START_DOCUMENT: + break; + + case XmlPullParser.START_TAG: + if ("page".equals(xmlPullParser.getName())) { + reviewList.setTotalPage(Integer.valueOf(xmlPullParser.getAttributeValue(null, "num"))); + } else if ("item".equals(xmlPullParser.getName())) { + rid = Integer.valueOf(xmlPullParser.getAttributeValue(null, "rid")); + noReplies = Integer.valueOf(xmlPullParser.getAttributeValue(null, "replies")); + String postTimeStr = xmlPullParser.getAttributeValue(null, "posttime"); + postTime = new GregorianCalendar( + Integer.valueOf(postTimeStr.substring(0, 2), 10), + Integer.valueOf(postTimeStr.substring(2, 4), 10), + Integer.valueOf(postTimeStr.substring(4, 6), 10), + Integer.valueOf(postTimeStr.substring(6, 8), 10), + Integer.valueOf(postTimeStr.substring(8, 10), 10), + Integer.valueOf(postTimeStr.substring(10), 10) + ).getTime(); + String replyTimeStr = xmlPullParser.getAttributeValue(null, "replytime"); + lastReplyTime = new GregorianCalendar( + Integer.valueOf(replyTimeStr.substring(0, 2), 10), + Integer.valueOf(replyTimeStr.substring(2, 4), 10), + Integer.valueOf(replyTimeStr.substring(4, 6), 10), + Integer.valueOf(replyTimeStr.substring(6, 8), 10), + Integer.valueOf(replyTimeStr.substring(8, 10), 10), + Integer.valueOf(replyTimeStr.substring(10), 10) + ).getTime(); + } else if ("user".equals(xmlPullParser.getName())) { + uid = Integer.valueOf(xmlPullParser.getAttributeValue(null, "uid")); + userName = xmlPullParser.nextText(); + } else if ("content".equals(xmlPullParser.getName())) { + title = xmlPullParser.nextText(); + } + break; + + case XmlPullParser.END_TAG: + if ("item".equals(xmlPullParser.getName())) { + reviewList.getList().add( + new ReviewList.Review(rid, postTime, noReplies, lastReplyTime, userName, uid, title)); + } + break; + } + eventType = xmlPullParser.next(); + } + } catch (Exception e) { + e.printStackTrace(); + } } } diff --git a/studio-android/LightNovelLibrary/app/src/test/java/org/mewx/wenku8/global/api/Wenku8ParserTest.java b/studio-android/LightNovelLibrary/app/src/test/java/org/mewx/wenku8/global/api/Wenku8ParserTest.java deleted file mode 100644 index f0dc46b7..00000000 --- a/studio-android/LightNovelLibrary/app/src/test/java/org/mewx/wenku8/global/api/Wenku8ParserTest.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.mewx.wenku8.global.api; - -import org.junit.Test; - -class Wenku8ParserTest { - @Test - void testParseReviewList() { - final String xml = "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - ""; - ReviewList reviewList = Wenku8Parser.parseReviewList(xml); - - // TODO: more tests - - } -}