Skip to content

Commit

Permalink
feat: 自定义首页顶部Tab
Browse files Browse the repository at this point in the history
CLOUDERHEM committed Jun 17, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent e676864 commit 630c6a2
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
@@ -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;
@@ -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;
@@ -71,7 +71,7 @@ public class Hooks {
new AutoRefresh(),
new PanelBubble(),
new FullScreen(),
new ActivityInfoAd(),
new TopTabs()
};

public static void init(final ClassLoader classLoader) {
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
@@ -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);
@@ -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);
@@ -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));
@@ -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");
11 changes: 5 additions & 6 deletions app/src/main/res/xml/preferences_zhihu.xml
Original file line number Diff line number Diff line change
@@ -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
@@ -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

0 comments on commit 630c6a2

Please sign in to comment.