diff --git a/.gitignore b/.gitignore index 406674caa177555d727283a5692ca9110c7adeeb..549f623f29197cb60ae84dd17eb9d4af51d72ba2 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ .cxx local.properties .androidide - +.project +.settings diff --git a/app/build.gradle b/app/build.gradle index 3b03f357796857c53b1532cfd6fbd4ac7fb5f289..c7cd197b0b307db1f84750bf504863cf4450be58 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,7 +2,7 @@ plugins { id 'com.android.application' } -int betaVer = 0 //如果为0则是正式版 +int betaVer = 2 //如果为0则是正式版 android { @@ -21,8 +21,8 @@ android { minSdk 14 //noinspection ExpiredTargetSdkVersion targetSdk 26 - versionCode 20251002 - versionName "2.9.3-fix" + versionCode 20260107 + versionName "2.10.0" if (betaVer) { versionName += "-BETA" + betaVer diff --git a/app/src/main/java/com/RobinNotBad/BiliClient/BiliTerminal.java b/app/src/main/java/com/RobinNotBad/BiliClient/BiliTerminal.java index 6193d84df599e5f2f9a4265b61e19c20a2c9f0cc..385a7613b55f6bd95be647047a007cf28e2a87d7 100644 --- a/app/src/main/java/com/RobinNotBad/BiliClient/BiliTerminal.java +++ b/app/src/main/java/com/RobinNotBad/BiliClient/BiliTerminal.java @@ -17,6 +17,7 @@ import com.RobinNotBad.BiliClient.activity.user.info.UserInfoActivity; import com.RobinNotBad.BiliClient.util.Logu; import com.RobinNotBad.BiliClient.util.SharedPreferencesUtil; import com.RobinNotBad.BiliClient.util.TerminalContext; +import com.RobinNotBad.BiliClient.util.ThemeUtils; import java.lang.ref.WeakReference; @@ -48,6 +49,7 @@ public class BiliTerminal extends Application { Logu.LOGV_ENABLED = SharedPreferencesUtil.getBoolean("dev_logv", debugBuild); Logu.LOGD_ENABLED = SharedPreferencesUtil.getBoolean("dev_logd", debugBuild); Logu.LOGI_ENABLED = SharedPreferencesUtil.getBoolean("dev_logi", debugBuild); + ThemeUtils.loadThemeData(this); } } diff --git a/app/src/main/java/com/RobinNotBad/BiliClient/activity/SplashActivity.java b/app/src/main/java/com/RobinNotBad/BiliClient/activity/SplashActivity.java index d92bab8fe5cff080f5aa8664c6552afdeeb10b6c..5c168199fafa481ffe696bc0b204d8d56353f8ad 100644 --- a/app/src/main/java/com/RobinNotBad/BiliClient/activity/SplashActivity.java +++ b/app/src/main/java/com/RobinNotBad/BiliClient/activity/SplashActivity.java @@ -24,6 +24,7 @@ import com.RobinNotBad.BiliClient.util.MsgUtil; import com.RobinNotBad.BiliClient.util.NetWorkUtil; import com.RobinNotBad.BiliClient.util.SharedPreferencesUtil; +import com.RobinNotBad.BiliClient.util.ThemeUtils; import org.json.JSONException; import org.json.JSONObject; @@ -54,8 +55,11 @@ public class SplashActivity extends Activity { super.onCreate(savedInstanceState); setTheme(R.style.Theme_BiliClient); setContentView(R.layout.activity_splash); + Log.e("debug", "进入应用"); + ThemeUtils.init(this); + splashTextView = findViewById(R.id.splashText); splashText = SharedPreferencesUtil.getString("ui_splashtext", "欢迎使用\n哔哩终端"); diff --git a/app/src/main/java/com/RobinNotBad/BiliClient/activity/base/BaseActivity.java b/app/src/main/java/com/RobinNotBad/BiliClient/activity/base/BaseActivity.java index 92033b1ec1515ee455ee93d48704ae3a8382e1d6..4973f683d20ff2dc605bd30dcd7c89508dda8236 100644 --- a/app/src/main/java/com/RobinNotBad/BiliClient/activity/base/BaseActivity.java +++ b/app/src/main/java/com/RobinNotBad/BiliClient/activity/base/BaseActivity.java @@ -5,8 +5,12 @@ import static com.RobinNotBad.BiliClient.activity.dynamic.DynamicActivity.getRel import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.drawable.BitmapDrawable; import android.os.Build; import android.os.Bundle; import android.text.TextUtils; @@ -27,6 +31,8 @@ import android.widget.TextView; import androidx.activity.result.ActivityResultLauncher; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; import androidx.core.view.ViewConfigurationCompat; import androidx.core.widget.NestedScrollView; import androidx.lifecycle.Lifecycle; @@ -41,12 +47,14 @@ import com.RobinNotBad.BiliClient.util.AsyncLayoutInflaterX; import com.RobinNotBad.BiliClient.util.Logu; import com.RobinNotBad.BiliClient.util.MsgUtil; import com.RobinNotBad.BiliClient.util.SharedPreferencesUtil; +import com.RobinNotBad.BiliClient.util.ThemeUtils; import com.RobinNotBad.BiliClient.util.ToolsUtil; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; +import java.io.File; public class BaseActivity extends AppCompatActivity { public int window_width, window_height; @@ -187,7 +195,9 @@ public class BaseActivity extends AppCompatActivity { EventBus.getDefault().register(this); eventBusInit = true; } + ThemeUtils.apply(this); } + @Override protected void onResume() { @@ -240,6 +250,7 @@ public class BaseActivity extends AppCompatActivity { setRound(); callBack.finishInflate(view, layoutId); + ThemeUtils.apply(this); }); } diff --git a/app/src/main/java/com/RobinNotBad/BiliClient/activity/settings/SettingLaboratoryActivity.java b/app/src/main/java/com/RobinNotBad/BiliClient/activity/settings/SettingLaboratoryActivity.java index f1c76a3a738f2add0570e68ee568250dd61ae320..cb908dcecb14749acf59f78371d08eff16b12062 100644 --- a/app/src/main/java/com/RobinNotBad/BiliClient/activity/settings/SettingLaboratoryActivity.java +++ b/app/src/main/java/com/RobinNotBad/BiliClient/activity/settings/SettingLaboratoryActivity.java @@ -37,6 +37,8 @@ public class SettingLaboratoryActivity extends RefreshListActivity { getString(R.string.setting_lab_splashtext), "欢迎使用\n哔哩终端")); add(new SettingSection("input_string", "缓存路径", "save_path_video", getString(R.string.setting_lab_path_video), FileUtil.getVideoDownloadPath().toString())); + add(new SettingSection("input_string", "主题路径", "theme_path", + getString(R.string.setting_lab_path_theme), "")); add(new SettingSection("input_string", "图片下载路径", "save_path_pictures", getString(R.string.setting_lab_path_pictures), FileUtil.getPicturePath().toString())); add(new SettingSection("switch", "文字跑马灯", "marquee_enable", getString(R.string.setting_lab_marquee), diff --git a/app/src/main/java/com/RobinNotBad/BiliClient/activity/settings/login/LoginActivity.java b/app/src/main/java/com/RobinNotBad/BiliClient/activity/settings/login/LoginActivity.java index 5c0627ea77d59ff65b46adbc7fabb05a08cb0b8b..497ff861bb721b79df6e76ada0e78bd63b59d090 100644 --- a/app/src/main/java/com/RobinNotBad/BiliClient/activity/settings/login/LoginActivity.java +++ b/app/src/main/java/com/RobinNotBad/BiliClient/activity/settings/login/LoginActivity.java @@ -12,6 +12,7 @@ import com.RobinNotBad.BiliClient.activity.base.BaseActivity; import com.RobinNotBad.BiliClient.adapter.viewpager.ViewPagerFragmentAdapter; import com.RobinNotBad.BiliClient.util.MsgUtil; import com.RobinNotBad.BiliClient.util.SharedPreferencesUtil; +import com.RobinNotBad.BiliClient.util.ThemeUtils; import java.util.ArrayList; import java.util.List; @@ -49,6 +50,7 @@ public class LoginActivity extends BaseActivity { MsgUtil.showMsgLong("提示:本页面可以左右滑动"); SharedPreferencesUtil.putBoolean("first_" + LoginActivity.class.getSimpleName(), false); } + ThemeUtils.apply(this); } @Override diff --git a/app/src/main/java/com/RobinNotBad/BiliClient/adapter/AnnouncementAdapter.java b/app/src/main/java/com/RobinNotBad/BiliClient/adapter/AnnouncementAdapter.java index 49e3e0bae804112ebea0b457f00c5b9ba2572b0a..43abdaa31d75da16c6210660cd85747191704859 100644 --- a/app/src/main/java/com/RobinNotBad/BiliClient/adapter/AnnouncementAdapter.java +++ b/app/src/main/java/com/RobinNotBad/BiliClient/adapter/AnnouncementAdapter.java @@ -13,6 +13,7 @@ import androidx.recyclerview.widget.RecyclerView; import com.RobinNotBad.BiliClient.R; import com.RobinNotBad.BiliClient.model.Announcement; import com.RobinNotBad.BiliClient.util.MsgUtil; +import com.RobinNotBad.BiliClient.util.ThemeUtils; import com.google.android.material.card.MaterialCardView; import java.util.ArrayList; @@ -53,6 +54,8 @@ public class AnnouncementAdapter extends RecyclerView.Adapter MsgUtil.showText(announcement.title, announcement.content)); + + ThemeUtils.apply(holder.itemView); } @Override diff --git a/app/src/main/java/com/RobinNotBad/BiliClient/adapter/DragAdapter.java b/app/src/main/java/com/RobinNotBad/BiliClient/adapter/DragAdapter.java index 4b3d438f94b54e85ab48b33699cc64c2fc3e2e41..c2a1c342800921e178080151d891972954caf38e 100644 --- a/app/src/main/java/com/RobinNotBad/BiliClient/adapter/DragAdapter.java +++ b/app/src/main/java/com/RobinNotBad/BiliClient/adapter/DragAdapter.java @@ -10,6 +10,7 @@ import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import com.RobinNotBad.BiliClient.R; +import com.RobinNotBad.BiliClient.util.ThemeUtils; import java.util.List; @@ -53,6 +54,8 @@ public class DragAdapter extends RecyclerView.Adapter { } return false; }); + + ThemeUtils.apply(holder.itemView); } @Override diff --git a/app/src/main/java/com/RobinNotBad/BiliClient/adapter/LiveCardAdapter.java b/app/src/main/java/com/RobinNotBad/BiliClient/adapter/LiveCardAdapter.java index a57b7396530cc3d87469635b2a89268bf2942ec2..26b11d09c2efef5afc86017a020203d7f25fa36e 100644 --- a/app/src/main/java/com/RobinNotBad/BiliClient/adapter/LiveCardAdapter.java +++ b/app/src/main/java/com/RobinNotBad/BiliClient/adapter/LiveCardAdapter.java @@ -17,6 +17,7 @@ import com.RobinNotBad.BiliClient.model.VideoCard; import com.RobinNotBad.BiliClient.util.StringUtil; import com.RobinNotBad.BiliClient.util.TerminalContext; +import com.RobinNotBad.BiliClient.util.ThemeUtils; import java.util.List; public class LiveCardAdapter extends RecyclerView.Adapter { @@ -63,6 +64,8 @@ public class LiveCardAdapter extends RecyclerView.Adapter { holder.showVideoCard(videoCard, context); + ThemeUtils.apply(holder.itemView); + holder.itemView .setOnClickListener(view -> TerminalContext.getInstance().enterLiveDetailPage(context, room.roomid)); diff --git a/app/src/main/java/com/RobinNotBad/BiliClient/adapter/LoginRecordAdapter.java b/app/src/main/java/com/RobinNotBad/BiliClient/adapter/LoginRecordAdapter.java index 8462807c8a609377accfb03ff840c146c718f9a5..b95c58270b9dc7ba0f842bc511363d71f78e5575 100644 --- a/app/src/main/java/com/RobinNotBad/BiliClient/adapter/LoginRecordAdapter.java +++ b/app/src/main/java/com/RobinNotBad/BiliClient/adapter/LoginRecordAdapter.java @@ -11,6 +11,7 @@ import androidx.recyclerview.widget.RecyclerView; import com.RobinNotBad.BiliClient.R; import com.RobinNotBad.BiliClient.model.LoginRecord; +import com.RobinNotBad.BiliClient.util.ThemeUtils; import java.util.List; @@ -46,6 +47,8 @@ public class LoginRecordAdapter extends RecyclerView.Adapter { if (onItemClickListener != null) onItemClickListener.onItemClick(position); }); diff --git a/app/src/main/java/com/RobinNotBad/BiliClient/adapter/QualitySelectorAdapter.java b/app/src/main/java/com/RobinNotBad/BiliClient/adapter/QualitySelectorAdapter.java index 536b8aeac50d37c82448894ac3edaec138ddf9f2..a70bba828aa27f21c1e4ce482d5a11cd0263fa3e 100644 --- a/app/src/main/java/com/RobinNotBad/BiliClient/adapter/QualitySelectorAdapter.java +++ b/app/src/main/java/com/RobinNotBad/BiliClient/adapter/QualitySelectorAdapter.java @@ -12,6 +12,8 @@ import androidx.recyclerview.widget.RecyclerView; import com.RobinNotBad.BiliClient.R; import com.RobinNotBad.BiliClient.listener.OnItemClickListener; +import com.RobinNotBad.BiliClient.util.ThemeUtils; + import com.google.android.material.button.MaterialButton; public class QualitySelectorAdapter extends RecyclerView.Adapter { @@ -67,6 +69,7 @@ public class QualitySelectorAdapter extends RecyclerView.Adapter context.startActivity(intent); }); } + ThemeUtils.apply(holder.itemView); } @Override diff --git a/app/src/main/java/com/RobinNotBad/BiliClient/adapter/SearchHistoryAdapter.java b/app/src/main/java/com/RobinNotBad/BiliClient/adapter/SearchHistoryAdapter.java index 97093e642c96738663906fe1d8cf01f859fe4c3c..2eeaccdf45141fee67b595e91238a801059f70aa 100644 --- a/app/src/main/java/com/RobinNotBad/BiliClient/adapter/SearchHistoryAdapter.java +++ b/app/src/main/java/com/RobinNotBad/BiliClient/adapter/SearchHistoryAdapter.java @@ -14,6 +14,7 @@ import com.RobinNotBad.BiliClient.listener.OnItemClickListener; import com.RobinNotBad.BiliClient.listener.OnItemLongClickListener; import com.RobinNotBad.BiliClient.util.StringUtil; +import com.RobinNotBad.BiliClient.util.ThemeUtils; import java.util.ArrayList; public class SearchHistoryAdapter extends RecyclerView.Adapter { @@ -48,6 +49,8 @@ public class SearchHistoryAdapter extends RecyclerView.Adapter= historyList.size()) return; holder.show(historyList.get(position)); + + ThemeUtils.apply(holder.itemView); holder.itemView.setOnClickListener(view -> { if (clickListener != null) { diff --git a/app/src/main/java/com/RobinNotBad/BiliClient/adapter/SearchSuggestionsAdapter.java b/app/src/main/java/com/RobinNotBad/BiliClient/adapter/SearchSuggestionsAdapter.java index 1ac59c95281a53fd252696ad9947b8aeb69bfffc..97779451bdb34f66bc4beaeb2b58ed36ff59fa36 100644 --- a/app/src/main/java/com/RobinNotBad/BiliClient/adapter/SearchSuggestionsAdapter.java +++ b/app/src/main/java/com/RobinNotBad/BiliClient/adapter/SearchSuggestionsAdapter.java @@ -12,6 +12,7 @@ import androidx.recyclerview.widget.RecyclerView; import com.RobinNotBad.BiliClient.R; import com.RobinNotBad.BiliClient.listener.OnItemClickListener; import com.RobinNotBad.BiliClient.util.StringUtil; +import com.RobinNotBad.BiliClient.util.ThemeUtils; import java.util.ArrayList; @@ -42,7 +43,7 @@ public class SearchSuggestionsAdapter extends RecyclerView.Adapter= suggestionsList.size()) return; holder.show(suggestionsList.get(position)); - + ThemeUtils.apply(holder.itemView); holder.itemView.setOnClickListener(view -> { if (clickListener != null) { clickListener.onItemClick(position); diff --git a/app/src/main/java/com/RobinNotBad/BiliClient/adapter/SettingsAdapter.java b/app/src/main/java/com/RobinNotBad/BiliClient/adapter/SettingsAdapter.java index ef4ec99c1dbe46f0179715d5a0b195a6611c9437..4668b040500ae6fc9197fe27923308e60c5d667c 100644 --- a/app/src/main/java/com/RobinNotBad/BiliClient/adapter/SettingsAdapter.java +++ b/app/src/main/java/com/RobinNotBad/BiliClient/adapter/SettingsAdapter.java @@ -18,6 +18,7 @@ import androidx.recyclerview.widget.RecyclerView; import com.RobinNotBad.BiliClient.R; import com.RobinNotBad.BiliClient.model.SettingSection; import com.RobinNotBad.BiliClient.util.SharedPreferencesUtil; +import com.RobinNotBad.BiliClient.util.ThemeUtils; import com.google.android.material.switchmaterial.SwitchMaterial; import java.util.HashMap; @@ -82,6 +83,7 @@ public class SettingsAdapter extends RecyclerView.Adapter holder.showArticleCard(articleCard, context); + ThemeUtils.apply(holder.itemView); + holder.itemView.setOnClickListener( view -> TerminalContext.getInstance().enterArticleDetailPage(context, articleCard.id)); diff --git a/app/src/main/java/com/RobinNotBad/BiliClient/adapter/article/ArticleContentAdapter.java b/app/src/main/java/com/RobinNotBad/BiliClient/adapter/article/ArticleContentAdapter.java index 98e569fdaa8a08f750d43ebc520720619cb40931..31d787f7d765b2012b91515bd312a50f9787f40e 100644 --- a/app/src/main/java/com/RobinNotBad/BiliClient/adapter/article/ArticleContentAdapter.java +++ b/app/src/main/java/com/RobinNotBad/BiliClient/adapter/article/ArticleContentAdapter.java @@ -26,6 +26,7 @@ import com.RobinNotBad.BiliClient.util.GlideUtil; import com.RobinNotBad.BiliClient.util.MsgUtil; import com.RobinNotBad.BiliClient.util.SharedPreferencesUtil; import com.RobinNotBad.BiliClient.util.StringUtil; +import com.RobinNotBad.BiliClient.util.ThemeUtils; import com.RobinNotBad.BiliClient.util.ToolsUtil; import com.bumptech.glide.Glide; import com.bumptech.glide.load.DecodeFormat; @@ -303,6 +304,7 @@ public class ArticleContentAdapter extends RecyclerView.Adapter { holder.itemView .setOnClickListener(v -> TerminalContext.getInstance().enterOpusDetailPage(context, opus.id)); } + ThemeUtils.apply(holder.itemView); } @Override diff --git a/app/src/main/java/com/RobinNotBad/BiliClient/adapter/article/OpusContentAdapter.java b/app/src/main/java/com/RobinNotBad/BiliClient/adapter/article/OpusContentAdapter.java index 9c854f720f6ae23a8f2d06f17adbd9ab13e24cbd..3d0e3ee9cfdf723365457f08c63eec51f6149755 100644 --- a/app/src/main/java/com/RobinNotBad/BiliClient/adapter/article/OpusContentAdapter.java +++ b/app/src/main/java/com/RobinNotBad/BiliClient/adapter/article/OpusContentAdapter.java @@ -27,6 +27,7 @@ import com.RobinNotBad.BiliClient.util.GlideUtil; import com.RobinNotBad.BiliClient.util.MsgUtil; import com.RobinNotBad.BiliClient.util.SharedPreferencesUtil; import com.RobinNotBad.BiliClient.util.StringUtil; +import com.RobinNotBad.BiliClient.util.ThemeUtils; import com.RobinNotBad.BiliClient.util.ToolsUtil; import com.bumptech.glide.Glide; import com.bumptech.glide.load.DecodeFormat; @@ -341,6 +342,7 @@ public class OpusContentAdapter extends RecyclerView.Adapter { if (message == null) return; holder.showMessage(message, context); + ThemeUtils.apply(holder.itemView); } @Override diff --git a/app/src/main/java/com/RobinNotBad/BiliClient/adapter/message/PrivateMsgAdapter.java b/app/src/main/java/com/RobinNotBad/BiliClient/adapter/message/PrivateMsgAdapter.java index 89b5d828e42ac7dcf5cd04befc7f745c98f59c86..f1cdbebb496f4ce9c8953a36095fbf575c5e6c7e 100644 --- a/app/src/main/java/com/RobinNotBad/BiliClient/adapter/message/PrivateMsgAdapter.java +++ b/app/src/main/java/com/RobinNotBad/BiliClient/adapter/message/PrivateMsgAdapter.java @@ -24,10 +24,7 @@ import com.RobinNotBad.BiliClient.activity.CopyTextActivity; import com.RobinNotBad.BiliClient.activity.ImageViewerActivity; import com.RobinNotBad.BiliClient.api.PrivateMsgApi; import com.RobinNotBad.BiliClient.model.PrivateMessage; -import com.RobinNotBad.BiliClient.util.CenterThreadPool; -import com.RobinNotBad.BiliClient.util.GlideUtil; -import com.RobinNotBad.BiliClient.util.SharedPreferencesUtil; -import com.RobinNotBad.BiliClient.util.TerminalContext; +import com.RobinNotBad.BiliClient.util.*; import com.bumptech.glide.Glide; import com.bumptech.glide.load.DecodeFormat; import com.bumptech.glide.load.engine.DiskCacheStrategy; @@ -239,6 +236,7 @@ public class PrivateMsgAdapter extends RecyclerView.Adapter list) { diff --git a/app/src/main/java/com/RobinNotBad/BiliClient/adapter/message/PrivateMsgSessionsAdapter.java b/app/src/main/java/com/RobinNotBad/BiliClient/adapter/message/PrivateMsgSessionsAdapter.java index 6ade2cf29c7d2b7ad596892aacea5ae3620758fe..076f72289765b12a09b7e50f989ee701faa26bb3 100644 --- a/app/src/main/java/com/RobinNotBad/BiliClient/adapter/message/PrivateMsgSessionsAdapter.java +++ b/app/src/main/java/com/RobinNotBad/BiliClient/adapter/message/PrivateMsgSessionsAdapter.java @@ -21,6 +21,7 @@ import com.RobinNotBad.BiliClient.model.PrivateMessage; import com.RobinNotBad.BiliClient.model.PrivateMsgSession; import com.RobinNotBad.BiliClient.model.UserInfo; import com.RobinNotBad.BiliClient.util.GlideUtil; +import com.RobinNotBad.BiliClient.util.ThemeUtils; import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.request.RequestOptions; @@ -114,6 +115,7 @@ public class PrivateMsgSessionsAdapter } catch (JSONException err) { Log.e("PrivateMsgUserAdapter", err.toString()); } + ThemeUtils.apply(holder.itemView); } @Override diff --git a/app/src/main/java/com/RobinNotBad/BiliClient/adapter/user/ElectricUserAdapter.java b/app/src/main/java/com/RobinNotBad/BiliClient/adapter/user/ElectricUserAdapter.java index 5db191b455e30011edebddbdda7678c065789b57..3d8f9d602a14d1817bb1c9a835e5095276f8378e 100644 --- a/app/src/main/java/com/RobinNotBad/BiliClient/adapter/user/ElectricUserAdapter.java +++ b/app/src/main/java/com/RobinNotBad/BiliClient/adapter/user/ElectricUserAdapter.java @@ -15,6 +15,7 @@ import com.RobinNotBad.BiliClient.R; import com.RobinNotBad.BiliClient.activity.user.info.UserInfoActivity; import com.RobinNotBad.BiliClient.model.ElectricUser; import com.RobinNotBad.BiliClient.util.GlideUtil; +import com.RobinNotBad.BiliClient.util.ThemeUtils; import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.request.RequestOptions; @@ -65,6 +66,7 @@ public class ElectricUserAdapter extends RecyclerView.Adapter { intent.putExtra("name", series.title); context.startActivity(intent); }); + ThemeUtils.apply(holder.itemView); } @Override diff --git a/app/src/main/java/com/RobinNotBad/BiliClient/adapter/video/UserVideoAdapter.java b/app/src/main/java/com/RobinNotBad/BiliClient/adapter/video/UserVideoAdapter.java index 65a28d479decb9afcc42f75e33f965e02c721d4f..f55abf0115b7cc0b470556bd6b04101aebd98b34 100644 --- a/app/src/main/java/com/RobinNotBad/BiliClient/adapter/video/UserVideoAdapter.java +++ b/app/src/main/java/com/RobinNotBad/BiliClient/adapter/video/UserVideoAdapter.java @@ -16,6 +16,7 @@ import com.RobinNotBad.BiliClient.activity.video.series.UserSeriesActivity; import com.RobinNotBad.BiliClient.adapter.dynamic.DynamicHolder; import com.RobinNotBad.BiliClient.model.VideoCard; import com.RobinNotBad.BiliClient.util.TerminalContext; +import com.RobinNotBad.BiliClient.util.ThemeUtils; import java.util.List; @@ -71,6 +72,7 @@ public class UserVideoAdapter extends RecyclerView.Adapter TerminalContext.getInstance().enterVideoDetailPage(context, videoCard.aid, videoCard.bvid)); } + ThemeUtils.apply(holder.itemView); } @Override diff --git a/app/src/main/java/com/RobinNotBad/BiliClient/adapter/video/VideoCardAdapter.java b/app/src/main/java/com/RobinNotBad/BiliClient/adapter/video/VideoCardAdapter.java index f10952e54d14f08c33527a4bad3eff518ea2b2fe..568c7636072ef82781b66536fd194888c0a58a98 100644 --- a/app/src/main/java/com/RobinNotBad/BiliClient/adapter/video/VideoCardAdapter.java +++ b/app/src/main/java/com/RobinNotBad/BiliClient/adapter/video/VideoCardAdapter.java @@ -12,6 +12,7 @@ import com.RobinNotBad.BiliClient.R; import com.RobinNotBad.BiliClient.listener.OnItemLongClickListener; import com.RobinNotBad.BiliClient.model.VideoCard; import com.RobinNotBad.BiliClient.util.TerminalContext; +import com.RobinNotBad.BiliClient.util.ThemeUtils; import java.util.List; @@ -51,7 +52,7 @@ public class VideoCardAdapter extends RecyclerView.Adapter { return; holder.showVideoCard(videoCard, context); - + holder.itemView.setOnClickListener(view -> { switch (videoCard.type) { case "video": @@ -70,6 +71,7 @@ public class VideoCardAdapter extends RecyclerView.Adapter { } else return false; }); + ThemeUtils.apply(holder.itemView); } @Override diff --git a/app/src/main/java/com/RobinNotBad/BiliClient/util/Theme.java b/app/src/main/java/com/RobinNotBad/BiliClient/util/Theme.java new file mode 100644 index 0000000000000000000000000000000000000000..4617416b826b2718f6f6b93ba1d27e932a2c0f4a --- /dev/null +++ b/app/src/main/java/com/RobinNotBad/BiliClient/util/Theme.java @@ -0,0 +1,104 @@ +package com.RobinNotBad.BiliClient.util; + +import android.content.Context; +import android.graphics.*; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.*; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +/** + * 主题描述类! + * @author MultiDev + */ +@SuppressWarnings("unused") +public class Theme { + private final String name; + private final String publisher; + private final String version; + private final int baseThemeColor; + private final boolean useBackgroundImage; + private final boolean isBlur; + private Drawable backgroundDrawable; + + public Theme(Context ctx, String themePath) throws IOException, JSONException { + File themeFile = new File(themePath); + + try (ZipFile zip = new ZipFile(themeFile)) { + ZipEntry configEntry = zip.getEntry("config.json"); + if (configEntry == null) { + throw new IOException("missing config.json in theme package"); + } + + StringBuilder jsonSb = new StringBuilder(); + try (InputStream is = zip.getInputStream(configEntry); + BufferedReader reader = new BufferedReader(new InputStreamReader(is))) { + String line; + while ((line = reader.readLine()) != null) { + jsonSb.append(line); + } + } + String jsonStr = jsonSb.toString(); + + JSONObject json = new JSONObject(jsonStr); + name = json.optString("name", "未命名"); + publisher = json.optString("publisher", "未知"); + version = json.optString("version", "0"); + useBackgroundImage = json.optBoolean("bg", false); + isBlur = json.optBoolean("blur", false); + String colorHex = json.optString("themeColor", "#000000"); + int parsedColor; + try { + if (!colorHex.startsWith("#")) { + colorHex = "#" + colorHex; + } + if (colorHex.length() == 4) { + char r = colorHex.charAt(1); + char g = colorHex.charAt(2); + char b = colorHex.charAt(3); + colorHex = "#" + r + r + g + g + b + b; + } + parsedColor = Color.parseColor(colorHex); + } catch (Exception e) { + Logu.w("invalid color format: " + colorHex + ", using default"); + parsedColor = Color.parseColor("#000000"); + } + baseThemeColor = parsedColor; + if (useBackgroundImage) { + ZipEntry bgEntry = zip.getEntry("bg.jpg"); + if (bgEntry != null) { + try (InputStream is = zip.getInputStream(bgEntry)) { + Bitmap backgroundBitmap = BitmapFactory.decodeStream(is); + if (isBlur) { + Bitmap resisedBitmap = Bitmap.createBitmap((int) (backgroundBitmap.getWidth() / 32f), + (int) (backgroundBitmap.getHeight() / 32f), + Bitmap.Config.ARGB_8888); + Matrix matrix = new Matrix(); + matrix.setScale(1 / 32f, 1 / 32f); + new Canvas(resisedBitmap).drawBitmap(backgroundBitmap, + matrix, + null); + backgroundBitmap = Bitmap.createScaledBitmap(resisedBitmap,backgroundBitmap.getWidth(), backgroundBitmap.getHeight(),true); + } + backgroundDrawable = new BitmapDrawable(ctx.getResources(), backgroundBitmap); + } catch (Exception e) { + Logu.w("failed to decode background image: " + e.getMessage()); + } + } + } + } + } + + public String getName() { return name; } + public String getPublisher() { return publisher; } + public String getVersion() { return version; } + public int getBaseThemeColor() { return baseThemeColor; } + public boolean isUseBackgroundImage() { return useBackgroundImage; } + public boolean isBlur() { return isBlur; } + public Drawable getBackground() { return backgroundDrawable; } +} diff --git a/app/src/main/java/com/RobinNotBad/BiliClient/util/ThemeUtils.java b/app/src/main/java/com/RobinNotBad/BiliClient/util/ThemeUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..14aff7d5468c9fde70a1c94a26c220f8ff733ece --- /dev/null +++ b/app/src/main/java/com/RobinNotBad/BiliClient/util/ThemeUtils.java @@ -0,0 +1,112 @@ +package com.RobinNotBad.BiliClient.util; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.widget.TextView; + +import androidx.core.content.ContextCompat; +import android.content.pm.PackageManager; +import androidx.core.app.ActivityCompat; +import com.google.android.material.button.MaterialButton; +import com.google.android.material.card.MaterialCardView; + +import java.util.ArrayDeque; +import java.util.Deque; + +public class ThemeUtils { + private static Theme sCurrentTheme; + + public static void loadThemeData(Context ctx) { + String path = SharedPreferencesUtil.getString("theme_path", ""); + if (path.isEmpty()) { + Logu.d("no theme path saved"); + sCurrentTheme = null; + return; + } + try { + sCurrentTheme = new Theme(ctx, path); + } catch (Exception e) { + Logu.e("theme load failed: " + e.getMessage()); + MsgUtil.err("unable to load theme", e); + sCurrentTheme = null; + } + } + + public static void apply(Activity activity) { + if (sCurrentTheme == null) return; + // set bg + Window window = activity.getWindow(); + window.setStatusBarColor(sCurrentTheme.getBaseThemeColor()); + window.setNavigationBarColor(sCurrentTheme.getBaseThemeColor()); + if (sCurrentTheme.isUseBackgroundImage()) { + window.setBackgroundDrawable(sCurrentTheme.getBackground()); + } else { + window.setBackgroundDrawable(new ColorDrawable(sCurrentTheme.getBaseThemeColor())); + } + + View rootView = activity.getWindow().getDecorView().findViewById(android.R.id.content); + apply(rootView); + } + + public static void apply(View rootView) { + if (sCurrentTheme == null) return; + // set color + int baseColor = sCurrentTheme.getBaseThemeColor(); + float r = Color.red(baseColor) / 255f; + float g = Color.green(baseColor) / 255f; + float b = Color.blue(baseColor) / 255f; + float luminance = 0.2126f * r + 0.7152f * g + 0.0722f * b; + boolean isTooLight = luminance > 0.7f; + int highlightColor; + if (isTooLight) { + highlightColor = Color.rgb( + (int)(Color.red(baseColor) * 0.85f), + (int)(Color.green(baseColor) * 0.85f), + (int)(Color.blue(baseColor) * 0.85f) + ); + } + else { + highlightColor = Color.rgb( + (int)(Color.red(baseColor) * 1.15f), + (int)(Color.green(baseColor) * 1.15f), + (int)(Color.blue(baseColor) * 1.15f) + ); + } + Deque stack = new ArrayDeque<>(); + stack.push(rootView); + while (!stack.isEmpty()) { + View view = stack.pop(); + if (view instanceof MaterialCardView) { + ((MaterialCardView) view).setCardBackgroundColor(highlightColor); + } + if (view instanceof MaterialButton) { + view.setBackgroundColor(highlightColor); + } + if (isTooLight && view instanceof TextView) { + ((TextView) view).setTextColor(Color.BLACK); + } + if (view instanceof ViewGroup) { + ViewGroup group = (ViewGroup) view; + for (int i = group.getChildCount() - 1; i >= 0; i--) { + stack.push(group.getChildAt(i)); + } + } + } + + } + public static void init(Activity a) { + if (ContextCompat.checkSelfPermission(a, android.Manifest.permission.READ_EXTERNAL_STORAGE) + != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(a, + new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE}, + 9999); + } + if (SharedPreferencesUtil.getString("theme_path", "").isEmpty()) return; + if (sCurrentTheme != null)loadThemeData(a); + } +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3481177642471a453c793b9eba880efb5ba25390..93b4f1690212b3bd10258ac2a942b1ef1d53c9d1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -29,6 +29,7 @@ !此功能将不再继续进行改进,除非开发者有时间!\n开启选项后,软件将会变为横屏,部分列表会变为三列,更适合平板等默认横屏的设备\n*注意:部分页面仍为单列式,可能有一些页面适配不佳,电视请移步官方电视版本或使用其他第三方软件。 开启开关将会使用表冠适配方案。下面的三项若非0则滚动距离会乘以该值。\n请从1.0开始上下调节,直至你自己满意为止。打开新页面才能生效。 缓存的视频将会保存到这个位置,若文件夹不存在会自动创建。之前缓存的视频请用文件管理器手动移动到新文件夹内。\n不保证会不会出现奇怪的问题。 + 填写主题包路径即可,正在开发\n不保证可用。 下载的图片将会保存到这个位置,若文件夹不存在会自动创建。之前下载的图片请用文件管理器手动移动到新文件夹内。\n不保证会不会出现奇怪的问题。 关闭此开关后,将会全局禁用文字跑马灯,可能会提升性能但会导致部分文字显示不全。 若后台下载在你的设备上有问题,请打开此选项以换回旧版的前台下载器! diff --git a/brotlij/src/androidTest/java/com/wolfcstech/brotlij/ExampleInstrumentedTest.java b/brotlij/src/androidTest/java/com/wolfcstech/brotlij/ExampleInstrumentedTest.java deleted file mode 100644 index 7866f40c3d31d38bbba7f9e0f1d0125392b8bf3b..0000000000000000000000000000000000000000 --- a/brotlij/src/androidTest/java/com/wolfcstech/brotlij/ExampleInstrumentedTest.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.wolfcstech.brotlij; - -import android.content.Context; -import android.support.test.InstrumentationRegistry; -import android.support.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import static org.junit.Assert.*; - -/** - * Instrumentation test, which will execute on an Android device. - * - * @see Testing documentation - */ -@RunWith(AndroidJUnit4.class) -public class ExampleInstrumentedTest { - @Test - public void useAppContext() throws Exception { - // Context of the app under test. - Context appContext = InstrumentationRegistry.getTargetContext(); - - assertEquals("com.wolfcstech.brotlij.test", appContext.getPackageName()); - } -} diff --git a/brotlij/src/test/java/com/wolfcstech/brotlij/ExampleUnitTest.java b/brotlij/src/test/java/com/wolfcstech/brotlij/ExampleUnitTest.java deleted file mode 100644 index 64cefcbcba653b32dd091a0dcc9f631c55bd0f0f..0000000000000000000000000000000000000000 --- a/brotlij/src/test/java/com/wolfcstech/brotlij/ExampleUnitTest.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.wolfcstech.brotlij; - -import org.junit.Test; - -import static org.junit.Assert.*; - -/** - * Example local unit test, which will execute on the development machine (host). - * - * @see Testing documentation - */ -public class ExampleUnitTest { - @Test - public void addition_isCorrect() throws Exception { - assertEquals(4, 2 + 2); - } -} \ No newline at end of file