Skip to content

Commit

Permalink
feat: 自定义首页顶部Tab
Browse files Browse the repository at this point in the history
  • Loading branch information
CLOUDERHEM committed Jun 17, 2024
1 parent e676864 commit 630c6a2
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 66 deletions.
4 changes: 2 additions & 2 deletions app/src/main/java/com/shatyuka/zhiliao/Hooks.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import android.widget.Toast;

import com.shatyuka.zhiliao.hooks.ActivityInfoAd;
import com.shatyuka.zhiliao.hooks.AnswerAd;
import com.shatyuka.zhiliao.hooks.AnswerListAd;
import com.shatyuka.zhiliao.hooks.Article;
Expand Down Expand Up @@ -33,6 +32,7 @@
import com.shatyuka.zhiliao.hooks.StatusBar;
import com.shatyuka.zhiliao.hooks.Tag;
import com.shatyuka.zhiliao.hooks.ThirdPartyLogin;
import com.shatyuka.zhiliao.hooks.TopTabs;
import com.shatyuka.zhiliao.hooks.VIPBanner;
import com.shatyuka.zhiliao.hooks.WebView;
import com.shatyuka.zhiliao.hooks.ZhihuPreference;
Expand Down Expand Up @@ -71,7 +71,7 @@ public class Hooks {
new AutoRefresh(),
new PanelBubble(),
new FullScreen(),
new ActivityInfoAd(),
new TopTabs()
};

public static void init(final ClassLoader classLoader) {
Expand Down
55 changes: 0 additions & 55 deletions app/src/main/java/com/shatyuka/zhiliao/hooks/ActivityInfoAd.kt

This file was deleted.

103 changes: 103 additions & 0 deletions app/src/main/java/com/shatyuka/zhiliao/hooks/TopTabs.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package com.shatyuka.zhiliao.hooks

import com.shatyuka.zhiliao.Helper
import de.robv.android.xposed.XC_MethodHook
import de.robv.android.xposed.XposedBridge.hookMethod
import de.robv.android.xposed.XposedHelpers.getObjectField
import de.robv.android.xposed.XposedHelpers.setObjectField
import java.util.stream.Collectors

/**
* api: /root/tab
*/
class TopTabs : BaseHook() {

private val PREFS_KEY_NAME = "edit_tabs"

private var activityInfo: Class<*>? = null
private var topTabs: Class<*>? = null

override fun getName(): String {
return "自定义首页顶部Tab(TopTabs)"
}

override fun init(classLoader: ClassLoader) {
try {
activityInfo = classLoader.loadClass("com.zhihu.android.api.model.ActivityInfo")
} catch (e: Exception) {
logE(e.message)
}

try {
topTabs = classLoader.loadClass("com.zhihu.android.api.model.TopTabs")
} catch (e: Exception) {
logE(e.message)
}
}

override fun hook() {
if (!Helper.prefs.getBoolean("switch_mainswitch", false)) {
return
}

hookMethod(Helper.JacksonHelper.ObjectReader_readValue, object : XC_MethodHook() {
override fun afterHookedMethod(param: MethodHookParam) {
if (param.result == null) {
return
}
when (param.result.javaClass) {
activityInfo -> {
setObjectField(param.result, "topActivity", null)
}

topTabs -> {
postProcessTopTabs(param.result)
}
}
}
})
}

private fun postProcessTopTabs(topTabs: Any) {
setObjectField(topTabs, "topActivity", null)
filterTabs(topTabs)
}

private fun filterTabs(topTabs: Any) {
val tabList = getObjectField(topTabs, "tabs") as List<*>

val resultTabList = ArrayList<Any>()
val tabTypeMap = HashMap<String, Any>()
val originTabTypeList = ArrayList<String>()

tabList.forEach {
val tabType = getObjectField(it, "tabType") as String
tabTypeMap[tabType] = it!!
originTabTypeList.add(tabType)
}

getAllowedTabTypeList().forEach {
val tab = tabTypeMap[it]
if (tab != null) {
resultTabList.add(tab)
}
}

if (resultTabList.isNotEmpty()) {
setObjectField(topTabs, "tabs", resultTabList)
} else {
resetAllowedTabTypeList(originTabTypeList)
}
}

private fun getAllowedTabTypeList(): List<String> {
return Helper.prefs.getString(PREFS_KEY_NAME, "")?.split("|")?.stream()
?.map { it.trim() }?.collect(Collectors.toList()) ?: ArrayList()
}

private fun resetAllowedTabTypeList(tabTypeList: List<String>) {
Helper.prefs.edit().putString(
PREFS_KEY_NAME, tabTypeList.stream().collect(Collectors.joining("|"))
).apply()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,6 @@ protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
Object switch_autorefresh = findPreference.invoke(thisObject, "switch_autorefresh");
Object switch_findnav = findPreference.invoke(thisObject, "switch_findnav");
Object switch_fullscreen = findPreference.invoke(thisObject, "switch_fullscreen");
Object switch_activityinfoad = findPreference.invoke(thisObject, "switch_activityinfoad");
Object preference_sourcecode_clouderhem = findPreference.invoke(thisObject, "preference_sourcecode_clouderhem");

setOnPreferenceChangeListener.invoke(findPreference.invoke(thisObject, "accept_eula"), thisObject);
Expand Down Expand Up @@ -401,7 +400,6 @@ protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
setOnPreferenceClickListener.invoke(switch_findnav, thisObject);
setOnPreferenceClickListener.invoke(switch_fullscreen, thisObject);
setOnPreferenceClickListener.invoke(preference_sourcecode_clouderhem, thisObject);
setOnPreferenceClickListener.invoke(switch_activityinfoad, thisObject);

String loaded_version = Helper.modRes.getString(R.string.app_version);
setSummary.invoke(preference_version, loaded_version);
Expand Down Expand Up @@ -475,6 +473,7 @@ protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
setIcon.invoke(findPreference.invoke(thisObject, "edit_title"), Helper.regex_title != null ? Helper.modRes.getDrawable(R.drawable.ic_check) : Helper.modRes.getDrawable(R.drawable.ic_close));
setIcon.invoke(findPreference.invoke(thisObject, "edit_author"), Helper.regex_author != null ? Helper.modRes.getDrawable(R.drawable.ic_check) : Helper.modRes.getDrawable(R.drawable.ic_close));
setIcon.invoke(findPreference.invoke(thisObject, "edit_content"), Helper.regex_content != null ? Helper.modRes.getDrawable(R.drawable.ic_check) : Helper.modRes.getDrawable(R.drawable.ic_close));
setIcon.invoke(findPreference.invoke(thisObject, "edit_tabs"), Helper.modRes.getDrawable(R.drawable.ic_tab));
setIcon.invoke(findPreference.invoke(thisObject, "switch_webview_debug"), Helper.modRes.getDrawable(R.drawable.ic_code));
setIcon.invoke(findPreference.invoke(thisObject, "switch_watermark"), Helper.modRes.getDrawable(R.drawable.ic_layers));
setIcon.invoke(findPreference.invoke(thisObject, "switch_subscribe"), Helper.modRes.getDrawable(R.drawable.ic_person_add_alt));
Expand All @@ -494,7 +493,6 @@ protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
setIcon.invoke(switch_autorefresh, Helper.modRes.getDrawable(R.drawable.ic_refresh));
setIcon.invoke(switch_findnav, Helper.modRes.getDrawable(R.drawable.ic_quadrilateralstar));
setIcon.invoke(preference_sourcecode_clouderhem, Helper.modRes.getDrawable(R.drawable.ic_github));
setIcon.invoke(switch_activityinfoad, Helper.modRes.getDrawable(R.drawable.ic_tab));

if (Helper.prefs.getBoolean("accept_eula", false)) {
Object category_eula = findPreference.invoke(thisObject, "category_eula");
Expand Down
11 changes: 5 additions & 6 deletions app/src/main/res/xml/preferences_zhihu.xml
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,6 @@
android:key="switch_searchad"
android:title="去搜索推荐"
android:summary="去除「大家都在搜」与推广"/>
<com.zhihu.android.app.ui.widget.SwitchPreference
android:defaultValue="true"
android:dependency="switch_mainswitch"
android:key="switch_activityinfoad"
android:title="去首页顶部广告"
android:summary="去首页顶部Tab活动广告"/>
</PreferenceCategory>
<PreferenceCategory android:title="其他" android:key="category_misc">
<com.zhihu.android.app.ui.widget.SwitchPreference
Expand Down Expand Up @@ -241,6 +235,11 @@
android:key="switch_minehybrid"
android:title="隐藏混合卡片"
android:summary="隐藏「我的」底部混合卡片"/>
<EditTextPreference
android:dependency="switch_mainswitch"
android:key="edit_tabs"
android:title="自定义首页顶部Tab"
android:summary="使用 | 隔开,留空为忽略"/>
</PreferenceCategory>
<PreferenceCategory android:title="自定义过滤" android:key="category_filter">
<EditTextPreference
Expand Down

0 comments on commit 630c6a2

Please sign in to comment.