├── serve-debug ├── __init__.py ├── .python-version ├── pyproject.toml ├── README.MD ├── config.py └── schemas.py ├── app ├── src │ └── main │ │ ├── resources │ │ └── META-INF │ │ │ └── xposed │ │ │ ├── scope.list │ │ │ ├── java_init.lis │ │ │ └── module.prop │ │ ├── assets │ │ ├── xposed_init │ │ ├── ChangeLog.MD │ │ └── web │ │ │ ├── images │ │ │ └── icon │ │ │ │ └── model │ │ │ │ ├── Theme.png │ │ │ │ ├── AntDodo.png │ │ │ │ ├── AntFarm.png │ │ │ │ ├── AntOcean.png │ │ │ │ ├── AntStall.png │ │ │ │ ├── Default.png │ │ │ │ ├── Reserve.png │ │ │ │ ├── AntForest.png │ │ │ │ ├── AntMember.png │ │ │ │ ├── AntOrchard.png │ │ │ │ ├── AntSports.png │ │ │ │ ├── BaseModel.png │ │ │ │ ├── AncientTree.png │ │ │ │ ├── AntCooperate.png │ │ │ │ ├── GreenFinance.png │ │ │ │ ├── selected │ │ │ │ ├── Theme.png │ │ │ │ ├── AntDodo.png │ │ │ │ ├── AntFarm.png │ │ │ │ ├── AntForest.png │ │ │ │ ├── AntMember.png │ │ │ │ ├── AntOcean.png │ │ │ │ ├── AntSports.png │ │ │ │ ├── AntStall.png │ │ │ │ ├── BaseModel.png │ │ │ │ ├── Default.png │ │ │ │ ├── Reserve.png │ │ │ │ ├── AncientTree.png │ │ │ │ ├── AntOrchard.png │ │ │ │ ├── AntCooperate.png │ │ │ │ ├── GreenFinance.png │ │ │ │ ├── ConsumeGold.svg │ │ │ │ └── AnswerAI.svg │ │ │ │ ├── ConsumeGold.svg │ │ │ │ └── AnswerAI.svg │ │ │ └── Sesame-TK-logo.svg │ │ ├── res │ │ ├── drawable │ │ │ ├── main.png │ │ │ ├── ic_launcher.png │ │ │ ├── menu_background.xml │ │ │ ├── tab_selected_background.xml │ │ │ ├── shape_diary_toast.xml │ │ │ ├── dialog_list_button.xml │ │ │ ├── button_main.xml │ │ │ ├── button_extend.xml │ │ │ ├── switch_track.xml │ │ │ ├── setting.xml │ │ │ ├── switch_thumb.xml │ │ │ ├── friend.xml │ │ │ ├── github.xml │ │ │ ├── all_log.xml │ │ │ ├── forest.xml │ │ │ ├── farm.xml │ │ │ └── title_logo.xml │ │ ├── drawable-night │ │ │ └── main.png │ │ ├── values │ │ │ ├── arrays.xml │ │ │ ├── dimen.xml │ │ │ ├── colors.xml │ │ │ └── styles.xml │ │ ├── values-v33 │ │ │ └── styles.xml │ │ ├── layout │ │ │ ├── layout_settings_item.xml │ │ │ ├── activity_web_settings.xml │ │ │ ├── activity_extend.xml │ │ │ ├── fragment_settings_list.xml │ │ │ ├── item_extend_function.xml │ │ │ ├── item_tab.xml │ │ │ ├── list_item.xml │ │ │ ├── toast.xml │ │ │ ├── base_title.xml │ │ │ ├── activity_html_viewer.xml │ │ │ └── activity_settings.xml │ │ └── values-night │ │ │ └── colors.xml │ │ ├── jniLibs │ │ ├── x86 │ │ │ └── libchecker.so │ │ ├── x86_64 │ │ │ └── libchecker.so │ │ ├── arm64-v8a │ │ │ └── libchecker.so │ │ └── armeabi-v7a │ │ │ └── libchecker.so │ │ ├── java │ │ └── fansirsqi │ │ │ └── xposed │ │ │ └── sesame │ │ │ ├── task │ │ │ ├── TaskStatus.java │ │ │ ├── antFarm │ │ │ │ ├── FarmUtil.kt │ │ │ │ └── DadaDailyRpcCall.java │ │ │ ├── ChildTaskExecutor.java │ │ │ ├── antStall │ │ │ │ ├── ReadingDadaRpcCall.java │ │ │ │ └── ReadingDada.java │ │ │ ├── antForest │ │ │ │ ├── GreenLife.java │ │ │ │ └── WhackMole.java │ │ │ ├── reserve │ │ │ │ └── ReserveRpcCall.java │ │ │ ├── TaskCommon.java │ │ │ ├── ancientTree │ │ │ │ └── AncientTreeRpcCall.java │ │ │ ├── AnswerAI │ │ │ │ └── AnswerAIInterface.java │ │ │ └── antCooperate │ │ │ │ └── AntCooperateRpcCall.java │ │ │ ├── hook │ │ │ ├── server │ │ │ │ ├── handlers │ │ │ │ │ ├── RpcRequest.kt │ │ │ │ │ ├── HttpHandler.kt │ │ │ │ │ ├── DebugHandler.kt │ │ │ │ │ └── BaseHandler.kt │ │ │ │ └── ModuleHttpServer.kt │ │ │ ├── rpc │ │ │ │ ├── intervallimit │ │ │ │ │ ├── DefaultIntervalLimit.kt │ │ │ │ │ ├── IntervalLimit.kt │ │ │ │ │ └── RpcIntervalLimit.kt │ │ │ │ ├── bridge │ │ │ │ │ ├── RpcVersion.java │ │ │ │ │ └── RpcBridge.java │ │ │ │ └── debug │ │ │ │ │ └── DebugRpcCall.java │ │ │ ├── HookSender.kt │ │ │ ├── RequestManager.java │ │ │ └── Toast.java │ │ │ ├── util │ │ │ ├── maps │ │ │ │ ├── ReserveaMap.java │ │ │ │ ├── VitalityRewardsMap.java │ │ │ │ ├── MemberBenefitsMap.java │ │ │ │ ├── ParadiseCoinBenefitIdMap.java │ │ │ │ ├── CooperateMap.java │ │ │ │ └── BeachMap.java │ │ │ ├── ListUtil.java │ │ │ ├── LanguageUtil.java │ │ │ ├── Average.java │ │ │ ├── FansirsqiUtil.kt │ │ │ ├── GlobalThreadPools.java │ │ │ ├── RandomUtil.java │ │ │ ├── ResChecker.java │ │ │ ├── Logback.java │ │ │ ├── ToastUtil.java │ │ │ └── StringUtil.java │ │ │ ├── entity │ │ │ ├── ExtendFunctionItem.kt │ │ │ ├── KVMap.kt │ │ │ ├── MemberBenefit.kt │ │ │ ├── CooperateEntity.kt │ │ │ ├── ParadiseCoinBenefit.java │ │ │ ├── MapperEntity.kt │ │ │ ├── OtherEntity.kt │ │ │ ├── VitalityStore.kt │ │ │ ├── AlipayUser.java │ │ │ ├── AlipayVersion.java │ │ │ ├── AlipayBeach.java │ │ │ ├── ReserveEntity.java │ │ │ ├── CollectEnergyEntity.java │ │ │ ├── AreaCode.java │ │ │ └── UserEntity.java │ │ │ ├── model │ │ │ ├── ModelFields.java │ │ │ ├── ModelType.java │ │ │ ├── SelectModelFieldFunc.java │ │ │ ├── ModelGroup.java │ │ │ ├── modelFieldExt │ │ │ │ ├── BooleanModelField.java │ │ │ │ ├── StringModelField.java │ │ │ │ ├── ChoiceModelField.java │ │ │ │ ├── EmptyModelField.java │ │ │ │ └── SelectOneModelField.java │ │ │ └── ModelOrder.java │ │ │ ├── data │ │ │ ├── RunType.kt │ │ │ ├── General.kt │ │ │ └── ViewAppInfo.kt │ │ │ ├── ui │ │ │ ├── dto │ │ │ │ ├── ModelGroupDto.java │ │ │ │ ├── ModelDto.java │ │ │ │ ├── ModelFieldShowDto.java │ │ │ │ └── ModelFieldInfoDto.java │ │ │ ├── widget │ │ │ │ ├── ExtendFunctionAdapter.kt │ │ │ │ └── TabAdapter.java │ │ │ ├── ChoiceDialog.java │ │ │ ├── ObjReference.java │ │ │ ├── ObjSyncReference.java │ │ │ ├── OptionsAdapter.java │ │ │ ├── BaseActivity.kt │ │ │ └── MyWebView.kt │ │ │ ├── newui │ │ │ └── MainActivityMaterial3.kt │ │ │ ├── newmodel │ │ │ └── ModelViews.kt │ │ │ └── extensions │ │ │ └── JSONExtensions.kt │ │ └── AndroidManifest.xml ├── libs │ ├── api-82.jar │ └── api-82-sources.jar └── proguard-rules.pro ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .github └── ISSUE_TEMPLATE │ ├── config.yml │ ├── enhancement.yml │ └── bug_report.yml ├── gradle.properties ├── settings.gradle.kts ├── LICENSE ├── .gitignore └── AppIdMap.txt /serve-debug/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /serve-debug/.python-version: -------------------------------------------------------------------------------- 1 | 3.12 2 | -------------------------------------------------------------------------------- /app/src/main/resources/META-INF/xposed/scope.list: -------------------------------------------------------------------------------- 1 | com.eg.android.AlipayGphone -------------------------------------------------------------------------------- /app/src/main/assets/xposed_init: -------------------------------------------------------------------------------- 1 | fansirsqi.xposed.sesame.hook.ApplicationHook 2 | -------------------------------------------------------------------------------- /app/src/main/assets/ChangeLog.MD: -------------------------------------------------------------------------------- 1 | ## Change Log 2 | 3 | ## Version 1.0.0 (2021-05-11) -------------------------------------------------------------------------------- /app/libs/api-82.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/libs/api-82.jar -------------------------------------------------------------------------------- /app/src/main/resources/META-INF/xposed/java_init.lis: -------------------------------------------------------------------------------- 1 | fansirsqi.xposed.sesame.hook.ApplicationHook -------------------------------------------------------------------------------- /app/src/main/resources/META-INF/xposed/module.prop: -------------------------------------------------------------------------------- 1 | minApiVersion=100 2 | targetApiVersion=100 3 | staticScope=true -------------------------------------------------------------------------------- /app/libs/api-82-sources.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/libs/api-82-sources.jar -------------------------------------------------------------------------------- /app/src/main/res/drawable/main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/res/drawable/main.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/main/jniLibs/x86/libchecker.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/jniLibs/x86/libchecker.so -------------------------------------------------------------------------------- /app/src/main/jniLibs/x86_64/libchecker.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/jniLibs/x86_64/libchecker.so -------------------------------------------------------------------------------- /app/src/main/res/drawable-night/main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/res/drawable-night/main.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/res/drawable/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/jniLibs/arm64-v8a/libchecker.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/jniLibs/arm64-v8a/libchecker.so -------------------------------------------------------------------------------- /app/src/main/jniLibs/armeabi-v7a/libchecker.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/jniLibs/armeabi-v7a/libchecker.so -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/Theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/assets/web/images/icon/model/Theme.png -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/AntDodo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/assets/web/images/icon/model/AntDodo.png -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/AntFarm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/assets/web/images/icon/model/AntFarm.png -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/AntOcean.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/assets/web/images/icon/model/AntOcean.png -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/AntStall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/assets/web/images/icon/model/AntStall.png -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/assets/web/images/icon/model/Default.png -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/Reserve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/assets/web/images/icon/model/Reserve.png -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/AntForest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/assets/web/images/icon/model/AntForest.png -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/AntMember.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/assets/web/images/icon/model/AntMember.png -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/AntOrchard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/assets/web/images/icon/model/AntOrchard.png -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/AntSports.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/assets/web/images/icon/model/AntSports.png -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/BaseModel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/assets/web/images/icon/model/BaseModel.png -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/AncientTree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/assets/web/images/icon/model/AncientTree.png -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/AntCooperate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/assets/web/images/icon/model/AntCooperate.png -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/GreenFinance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/assets/web/images/icon/model/GreenFinance.png -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/task/TaskStatus.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.task; 2 | 3 | public enum TaskStatus { 4 | TODO, FINISHED, RECEIVED 5 | } 6 | -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/selected/Theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/assets/web/images/icon/model/selected/Theme.png -------------------------------------------------------------------------------- /app/src/main/res/values/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.eg.android.AlipayGphone 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/selected/AntDodo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/assets/web/images/icon/model/selected/AntDodo.png -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/selected/AntFarm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/assets/web/images/icon/model/selected/AntFarm.png -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/selected/AntForest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/assets/web/images/icon/model/selected/AntForest.png -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/selected/AntMember.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/assets/web/images/icon/model/selected/AntMember.png -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/selected/AntOcean.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/assets/web/images/icon/model/selected/AntOcean.png -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/selected/AntSports.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/assets/web/images/icon/model/selected/AntSports.png -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/selected/AntStall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/assets/web/images/icon/model/selected/AntStall.png -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/selected/BaseModel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/assets/web/images/icon/model/selected/BaseModel.png -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/selected/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/assets/web/images/icon/model/selected/Default.png -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/selected/Reserve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/assets/web/images/icon/model/selected/Reserve.png -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/selected/AncientTree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/assets/web/images/icon/model/selected/AncientTree.png -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/selected/AntOrchard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/assets/web/images/icon/model/selected/AntOrchard.png -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/selected/AntCooperate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/assets/web/images/icon/model/selected/AntCooperate.png -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/selected/GreenFinance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Youyu-Github/Sesame-TK-Y/HEAD/app/src/main/assets/web/images/icon/model/selected/GreenFinance.png -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: 使用问题 4 | url: https://github.com/Fansirsqi/Sesame-TK/discussions/ 5 | about: 请使用 GitHub Discussion 的“提问”分区讨论使用上的问题。 -------------------------------------------------------------------------------- /app/src/main/res/values/dimen.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 24dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/hook/server/handlers/RpcRequest.kt: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.hook.server.handlers 2 | 3 | data class RpcRequest( 4 | val methodName: String, 5 | val requestData: String 6 | ) -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | android.enableJetifier=true 2 | android.useAndroidX=true 3 | android.suppressUnsupportedCompileSdk=36 4 | org.gradle.jvmargs=-Xmx4g -XX:+UseParallelGC -Dfile.encoding=UTF-8 5 | org.gradle.caching=true 6 | org.gradle.parallel=true 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/hook/rpc/intervallimit/DefaultIntervalLimit.kt: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.hook.rpc.intervallimit 2 | 3 | class DefaultIntervalLimit(override val interval: Int?) : IntervalLimit { 4 | override var time: Long = 0 5 | } -------------------------------------------------------------------------------- /app/src/main/res/values-v33/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/util/maps/ReserveaMap.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.util.maps; 2 | public class ReserveaMap extends IdMapManager { 3 | @Override 4 | public String thisFileName() { 5 | return "ReserveaMap.json";//保护地ID映射表 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/hook/rpc/intervallimit/IntervalLimit.kt: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.hook.rpc.intervallimit 2 | 3 | interface IntervalLimit { 4 | val interval: Int? // 对应 Integer getInterval() 5 | var time: Long // 对应 Long getTime() 和 void setTime(Long) 6 | } -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/util/maps/VitalityRewardsMap.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.util.maps; 2 | public class VitalityRewardsMap extends IdMapManager{ 3 | @Override 4 | public String thisFileName(){ 5 | return "vitalityRewardsMap.json";//活力值兑换映射表 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Nov 27 19:58:21 CST 2024 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-9.0-milestone-5-bin.zip 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/entity/ExtendFunctionItem.kt: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.entity 2 | 3 | /** 4 | * 扩展功能项的数据类 5 | * @param name 功能名称 6 | * @param action 点击时执行的动作 7 | */ 8 | data class ExtendFunctionItem( 9 | val name: String, 10 | val action: () -> Unit 11 | ) -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/util/maps/MemberBenefitsMap.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.util.maps; 2 | 3 | public class MemberBenefitsMap extends IdMapManager { 4 | @Override 5 | public String thisFileName(){ 6 | return "MemberBenefitsMap.json";//会员权益兑换映射表 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/menu_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/util/maps/ParadiseCoinBenefitIdMap.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.util.maps; 2 | 3 | public class ParadiseCoinBenefitIdMap extends IdMapManager { 4 | @Override 5 | public String thisFileName(){ 6 | return "paradiseCoinBenefitMap.json";//小鸡乐园道具兑换映射表 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/util/maps/CooperateMap.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.util.maps; 2 | /** 3 | * 合种ID映射工具类。 4 | */ 5 | public class CooperateMap extends IdMapManager { 6 | @Override 7 | public String thisFileName() { 8 | return "cooperateMap.json";//合种ID映射文件名 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/hook/server/handlers/HttpHandler.kt: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.hook.server.handlers 2 | 3 | import fi.iki.elonen.NanoHTTPD.IHTTPSession 4 | import fi.iki.elonen.NanoHTTPD.Response 5 | 6 | interface HttpHandler { 7 | fun handle(session: IHTTPSession, body: String? = null): Response 8 | } -------------------------------------------------------------------------------- /serve-debug/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "serve-debug" 3 | version = "0.1.0" 4 | description = "Add your description here" 5 | readme = "README.md" 6 | requires-python = ">=3.12" 7 | dependencies = [ 8 | "fastapi>=0.115.12", 9 | "rich>=14.0.0", 10 | "sqlalchemy>=2.0.41", 11 | "uvicorn>=0.34.2", 12 | ] 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/tab_selected_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/util/maps/BeachMap.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.util.maps; 2 | /** 3 | * 沙滩ID映射工具类。 4 | * 提供了一个线程安全的ID映射,支持添加、删除、加载和保存ID映射。 5 | */ 6 | public class BeachMap extends IdMapManager { 7 | @Override 8 | public String thisFileName() { 9 | return "BeachMap.json";//海洋ID映射文件 10 | } 11 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_diary_toast.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /serve-debug/README.MD: -------------------------------------------------------------------------------- 1 | 2 | # create virtual environment 3 | 4 | `python -m venv .venv` 5 | 6 | # activate virtual environment 7 | 8 | `source .venv/bin/activate` 9 | 10 | # install dependencies 11 | 12 | `pip install -r requirements.txt` 13 | 14 | # run the app 15 | 16 | `python main.py` 17 | 18 | # set target url hooks url in model congig and trun on hooks 19 | 20 | # enjoy it 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_settings_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/ConsumeGold.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/dialog_list_button.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/selected/ConsumeGold.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/model/ModelFields.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.model; 2 | import java.util.LinkedHashMap; 3 | //@Data 4 | public final class ModelFields extends LinkedHashMap> { 5 | //private BooleanModelField enable = new BooleanModelField("enable", "开启", true); 6 | public void addField(ModelField modelField) { 7 | put(modelField.getCode(), modelField); 8 | } 9 | } -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/entity/KVMap.kt: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.entity 2 | 3 | import java.io.Serial 4 | import java.io.Serializable 5 | 6 | open class KVMap protected constructor() : Serializable { 7 | 8 | companion object { 9 | @Serial 10 | const val serialVersionUID: Long = 1L 11 | } 12 | 13 | constructor(key: K, value: V) : this() { 14 | this.key = key 15 | this.value = value 16 | } 17 | 18 | var key: K? = null 19 | var value: V? = null 20 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/enhancement.yml: -------------------------------------------------------------------------------- 1 | name: 功能建议 2 | description: 功能建议使用此模板进行提交 3 | labels: [ enhancement ] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | ### 请在下方填写功能需求或建议。 9 | - type: dropdown 10 | attributes: 11 | label: 增强类型 12 | options: 13 | - 功能型增强 14 | - 优化型增强 15 | - 强迫症增强 16 | validations: 17 | required: true 18 | - type: textarea 19 | attributes: 20 | label: 具体描述 21 | description: 请在下方详细描述功能需求或建议。 22 | validations: 23 | required: true -------------------------------------------------------------------------------- /app/src/main/res/drawable/button_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/button_extend.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | mavenCentral() 4 | gradlePluginPortal() 5 | google() 6 | } 7 | plugins { 8 | kotlin("jvm") version "2.2.0-Beta2" // 使用与libs.versions.toml中kotlin-plugin相同的版本 9 | } 10 | } 11 | 12 | dependencyResolutionManagement { 13 | repositories { 14 | maven("https://maven.aliyun.com/repository/spring") 15 | mavenCentral() 16 | google() 17 | } 18 | } 19 | plugins { 20 | id("org.gradle.toolchains.foojay-resolver-convention") version "0.10.0" 21 | } 22 | include(":app") 23 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_web_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/entity/MemberBenefit.kt: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.entity 2 | 3 | import fansirsqi.xposed.sesame.util.maps.IdMapManager 4 | import fansirsqi.xposed.sesame.util.maps.MemberBenefitsMap 5 | 6 | class MemberBenefit(i: String, n: String) : MapperEntity() { 7 | 8 | init { 9 | id = i 10 | name = n 11 | } 12 | 13 | companion object { 14 | fun getList(): List { 15 | return IdMapManager.getInstance(MemberBenefitsMap::class.java).map 16 | .map { (key, value) -> MemberBenefit(key, value) } 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/task/antFarm/FarmUtil.kt: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.task.antFarm 2 | 3 | object FarmUtil { 4 | 5 | val syncAnimalType = listOf( 6 | "all" to listOf("SYNC_RESUME", "QUERY_ALL"),//全局同步 7 | "after_fence" to listOf("SYNC_AFTER_TOOL_FENCE", "QUERY_FARM_INFO"),//使用道具后同步 8 | "after_accelerate" to listOf("SYNC_AFTER_TOOL_ACCELERATE", "QUERY_FARM_INFO"),//加速后同步 9 | "after_hire" to listOf("SYNC_AFTER_HIRE_DONE", "QUERY_FARM_INFO"),//雇佣完成后同步 10 | "after_feed" to listOf("SYNC_AFTER_FEED_ANIMAL", "QUERY_EMOTION_INFO|QUERY_ORCHARD_RIGHTS"),//喂食完成后同步 11 | ) 12 | 13 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_extend.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/data/RunType.kt: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.data 2 | 3 | import lombok.Getter 4 | 5 | /** 6 | * 运行状态枚举类,用于表示不同的运行状态。 7 | * 每个枚举值代表一种状态,包含状态码和状态描述。 8 | */ 9 | @Getter 10 | enum class RunType(val code: Int, val nickName: String) { 11 | DISABLE(0, "未激活"), 12 | ACTIVE(1, "已激活"), 13 | LOADED(2, "已加载"); 14 | 15 | companion object { 16 | private val codeMap = entries.associateBy { it.code } 17 | /** 18 | * 根据状态码获取枚举实例 19 | * @param code 状态编码 20 | * @return 匹配的枚举实例,未找到时返回null 21 | */ 22 | fun fromCode(code: Int): RunType? = codeMap[code] 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/entity/CooperateEntity.kt: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.entity; 2 | 3 | import fansirsqi.xposed.sesame.util.maps.CooperateMap; 4 | import fansirsqi.xposed.sesame.util.maps.IdMapManager; 5 | 6 | /** 7 | * 表示合作用户的实体类,包含 ID 和名称。 8 | */ 9 | class CooperateEntity(i: String, n: String) : MapperEntity() { 10 | init { 11 | id = i 12 | name = n 13 | } 14 | 15 | companion object { 16 | fun getList(): List { 17 | return IdMapManager.getInstance(CooperateMap::class.java).map 18 | .map { (key, value) -> CooperateEntity(key, value) } 19 | } 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_settings_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/switch_track.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_extend_function.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/model/ModelType.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.model; 2 | import java.util.HashMap; 3 | import java.util.Map; 4 | public enum ModelType { 5 | NORMAL(0, "普通模块"), 6 | TASK(1, "任务模块"), 7 | ; 8 | private final Integer code; 9 | ModelType(Integer code, String name) { 10 | this.code = code; 11 | } 12 | private static final Map MAP; 13 | static { 14 | MAP = new HashMap<>(); 15 | ModelType[] values = ModelType.values(); 16 | for (ModelType value : values) { 17 | MAP.put(value.code, value); 18 | } 19 | } 20 | public static ModelType getByCode(Integer code) { 21 | return MAP.get(code); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/util/ListUtil.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.util; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | /** 列表工具类,提供对列表的常用操作。 */ 7 | public class ListUtil { 8 | /** 9 | * 创建一个新的ArrayList实例,并使用提供的元素进行初始化。 10 | * 这是一个泛型方法,可以用于创建并初始化任何类型的列表。 11 | * 12 | * @param objects 要添加到列表中的元素。 13 | * @param 列表元素的类型。 14 | * @return 返回包含所有提供元素的新ArrayList。 15 | */ 16 | @SafeVarargs 17 | public static List newArrayList(T... objects) { 18 | // 创建一个新的ArrayList实例 19 | List list = new ArrayList<>(); 20 | // 如果提供了元素,则将它们添加到列表中 21 | if (objects != null) { 22 | Collections.addAll(list, objects); 23 | } 24 | return list; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | Version 2, December 2004 3 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 版本 2,2004 年 12 月 4 | 5 | Copyright (C) 2004 Sam Hocevar 6 | 版权 (C) 2004 Sam Hocevar 7 | 8 | Everyone is permitted to copy and distribute verbatim or modified 9 | copies of this license document, and changing it is allowed as long 10 | as the name is changed. 11 | 每个人都被允许复制和分发这个许可文档的原文或修改过的副本,只要在更改名称的情况下,更改它是允许的。 12 | 13 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 14 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 15 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 复制、分发和修改的条款和条件 16 | 17 | 0. You just DO WHAT THE FUCK YOU WANT TO. 18 | 0. 你他妈想干嘛就干嘛。 19 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/hook/rpc/bridge/RpcVersion.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.hook.rpc.bridge; 2 | import lombok.Getter; 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | @Getter 6 | public enum RpcVersion { 7 | OLD("OLD"), 8 | NEW("NEW"), 9 | ; 10 | final String code; 11 | RpcVersion(String code) { 12 | this.code = code; 13 | } 14 | private static final Map MAP; 15 | static { 16 | MAP = new HashMap<>(); 17 | RpcVersion[] values = RpcVersion.values(); 18 | for (RpcVersion value : values) { 19 | MAP.put(value.code, value); 20 | } 21 | } 22 | public static RpcVersion getByCode(String code) { 23 | return MAP.get(code); 24 | } 25 | } -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/AnswerAI.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/task/ChildTaskExecutor.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.task; 2 | /** 3 | * ChildTaskExecutor 接口用于定义管理子任务的方法。 4 | * 通过此接口可以对子任务进行添加、移除、清除操作。 5 | */ 6 | public interface ChildTaskExecutor { 7 | /** 8 | * 添加一个子任务到任务执行者 9 | * 10 | * @param childTask 要添加的子任务 11 | * @return 如果添加成功返回 true,否则返回 false 12 | */ 13 | Boolean addChildTask(ModelTask.ChildModelTask childTask); 14 | /** 15 | * 移除一个子任务 16 | * 17 | * @param childTask 要移除的子任务 18 | */ 19 | void removeChildTask(ModelTask.ChildModelTask childTask); 20 | /** 21 | * 清除指定组的所有子任务 22 | * 23 | * @param group 子任务所在的组 24 | * @return 如果清除成功返回 true,否则返回 false 25 | */ 26 | Boolean clearGroupChildTask(String group); 27 | /** 28 | * 清除所有子任务 29 | */ 30 | void clearAllChildTask(); 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/assets/web/images/icon/model/selected/AnswerAI.svg: -------------------------------------------------------------------------------- 1 | 3 | 6 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/task/antFarm/DadaDailyRpcCall.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.task.antFarm; 2 | 3 | import fansirsqi.xposed.sesame.hook.RequestManager; 4 | 5 | /** 6 | * @author Constanline 7 | * @since 2023/08/04 8 | */ 9 | public class DadaDailyRpcCall { 10 | public static String home(String activityId) { 11 | return RequestManager.requestString("com.alipay.reading.game.dadaDaily.home", 12 | "[{\"activityId\":" + activityId + ",\"dadaVersion\":\"1.3.0\",\"version\":1}]"); 13 | } 14 | 15 | public static String submit(String activityId, String answer, Long questionId) { 16 | return RequestManager.requestString("com.alipay.reading.game.dadaDaily.submit", 17 | "[{\"activityId\":" + activityId + ",\"answer\":\"" + answer + "\",\"dadaVersion\":\"1.3.0\",\"questionId\":" + questionId + ",\"version\":1}]"); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #F4F4F4 5 | #2489FD 6 | #2489FD 7 | #000000 8 | 9 | #2489FD 10 | 11 | #BCE1E9 12 | #2489FD 13 | 14 | #E64000 15 | 16 | #e10000 17 | #DCDCDC 18 | #999999 19 | 20 | #AA000000 21 | 22 | #090909 23 | 24 | #FFFFFF 25 | #DFDFDF 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/entity/ParadiseCoinBenefit.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.entity; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | import fansirsqi.xposed.sesame.util.maps.IdMapManager; 8 | import fansirsqi.xposed.sesame.util.maps.ParadiseCoinBenefitIdMap; 9 | 10 | public class ParadiseCoinBenefit extends MapperEntity { 11 | 12 | public ParadiseCoinBenefit(String i, String n) { 13 | id = i; 14 | name = n; 15 | } 16 | 17 | public static List getList() { 18 | List list = new ArrayList<>(); 19 | Map idSet = IdMapManager.getInstance(ParadiseCoinBenefitIdMap.class).getMap(); 20 | for (Map.Entry entry: idSet.entrySet()) { 21 | list.add(new ParadiseCoinBenefit(entry.getKey(), entry.getValue())); 22 | } 23 | return list; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/ui/dto/ModelGroupDto.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.ui.dto; 2 | import lombok.Data; 3 | import java.io.Serializable; 4 | /** 5 | * 模型组数据传输对象。 6 | * 用于封装模型组的相关信息,包括组代码、名称和图标。 7 | */ 8 | @Data 9 | public class ModelGroupDto implements Serializable { 10 | /** 11 | * 模型组代码。 12 | */ 13 | private String code; 14 | /** 15 | * 模型组名称。 16 | */ 17 | private String name; 18 | /** 19 | * 模型组图标。 20 | */ 21 | private String icon; 22 | /** 23 | * 无参构造函数。 24 | * 用于反序列化等场景。 25 | */ 26 | public ModelGroupDto() { 27 | } 28 | /** 29 | * 全参构造函数。 30 | * 用于创建包含完整信息的模型组对象。 31 | * 32 | * @param code 模型组代码 33 | * @param name 模型组名称 34 | * @param icon 模型组图标 35 | */ 36 | public ModelGroupDto(String code, String name, String icon) { 37 | this.code = code; 38 | this.name = name; 39 | this.icon = icon; 40 | } 41 | } -------------------------------------------------------------------------------- /app/src/main/res/values-night/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #1A1A1A 5 | #4D4D4D 6 | 7 | #4D4D4D 8 | #FFFFFF 9 | 10 | #F87640 11 | 12 | #3A3A3A 13 | #FFEBCD 14 | 15 | #F87640 16 | 17 | #F4D022 18 | #DEDBDB 19 | #C8B9B9 20 | 21 | #AA000000 22 | 23 | #FBFBFB 24 | 25 | #FFFFFF 26 | #DFDFDF 27 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_tab.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 18 | 19 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/entity/MapperEntity.kt: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.entity 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore 4 | import fansirsqi.xposed.sesame.util.HanziToPinyin 5 | 6 | abstract class MapperEntity : Comparable { 7 | @JvmField 8 | public var name: String = "" 9 | @JvmField 10 | public var id: String = "" 11 | 12 | @JsonIgnore 13 | private var pinyinCache: List? = null 14 | 15 | @JsonIgnore 16 | fun getPinyin(): List = pinyinCache ?: run { 17 | HanziToPinyin.getInstance() 18 | .get(name) 19 | .map { it.target } 20 | .also { pinyinCache = it } 21 | } 22 | 23 | override fun compareTo(other: MapperEntity): Int { 24 | val list1 = getPinyin() 25 | val list2 = other.getPinyin() 26 | 27 | return list1.zip(list2) { a, b -> a.compareTo(b) } 28 | .firstOrNull { it != 0 } 29 | ?: (list1.size - list2.size) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/res/layout/list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 18 | 19 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/data/General.kt: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.data 2 | 3 | /** 4 | * 类实用工具类。 5 | * 提供了一些常量,这些常量代表了项目中使用的一些关键类的完整名称。 6 | */ 7 | object General { 8 | /** 9 | * 支付宝客户端的包名。 10 | */ 11 | const val PACKAGE_NAME: String = "com.eg.android.AlipayGphone" 12 | 13 | /** 14 | * 当前使用的服务类名。 15 | */ 16 | const val CURRENT_USING_SERVICE: String = "com.alipay.dexaop.power.RuntimePowerService" 17 | 18 | /** 19 | * 当前使用的活动(Activity)类名。 20 | */ 21 | const val CURRENT_USING_ACTIVITY: String = "com.eg.android.AlipayGphone.AlipayLogin" 22 | 23 | /** 24 | * JSON对象的类名。 25 | */ 26 | const val JSON_OBJECT_NAME: String = "com.alibaba.fastjson.JSONObject" 27 | 28 | /** 29 | * H5页面的类名。 30 | */ 31 | const val H5PAGE_NAME: String = "com.alipay.mobile.h5container.api.H5Page" 32 | const val MODULE_PACKAGE_NAME: String = "fansirsqi.xposed.sesame" 33 | const val MODULE_PACKAGE_UI_ICON : String = "$MODULE_PACKAGE_NAME.ui.MainActivityAlias" 34 | } -------------------------------------------------------------------------------- /serve-debug/config.py: -------------------------------------------------------------------------------- 1 | # 新增配置文件 config.py 2 | from sqlalchemy import create_engine 3 | from sqlalchemy.ext.declarative import declarative_base 4 | from sqlalchemy.orm import sessionmaker 5 | from contextlib import contextmanager 6 | import os 7 | import logging 8 | 9 | 10 | SQLALCHEMY_DATABASE_URL = "sqlite:///./webhook.db" 11 | # 生产环境建议使用连接池 12 | # SQLALCHEMY_DATABASE_URL = "postgresql://user:password@localhost/dbname" 13 | 14 | # 配置日志 15 | logging.basicConfig( 16 | level=logging.DEBUG , 17 | format="%(asctime)s - %(name)s - %(levelname)s - %(message)s" 18 | ) 19 | 20 | logger = logging.getLogger(__name__) 21 | 22 | 23 | engine = create_engine( 24 | SQLALCHEMY_DATABASE_URL, 25 | connect_args={"check_same_thread": False} # SQLite特有配置 26 | ) 27 | SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) 28 | 29 | Base = declarative_base() 30 | 31 | # 数据库会话管理器 32 | @contextmanager 33 | def db_session(): 34 | session = SessionLocal() 35 | try: 36 | yield session 37 | finally: 38 | session.close() 39 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/setting.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/newui/MainActivityMaterial3.kt: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.newui 2 | 3 | import android.os.Bundle 4 | import androidx.activity.ComponentActivity 5 | import androidx.activity.compose.setContent 6 | import androidx.compose.material3.Text 7 | import androidx.compose.runtime.Composable 8 | import androidx.compose.ui.tooling.preview.Preview 9 | import androidx.compose.ui.tooling.preview.PreviewParameter 10 | import fansirsqi.xposed.sesame.util.DeviceInfoCard 11 | import fansirsqi.xposed.sesame.util.DeviceInfoUtil 12 | import fansirsqi.xposed.sesame.util.PreviewDeviceInfoProvider 13 | 14 | class MainActivityMaterial3 : ComponentActivity() { 15 | 16 | override fun onCreate(savedInstanceState: Bundle?) { 17 | super.onCreate(savedInstanceState) 18 | setContent { 19 | DeviceInfoCard(DeviceInfoUtil.getDeviceInfo(this)) 20 | } 21 | } 22 | } 23 | 24 | @Preview(showBackground = true) 25 | @Composable 26 | fun DeviceInfoCardPreview(@PreviewParameter(PreviewDeviceInfoProvider::class) info: Map) { 27 | DeviceInfoCard(info = info) 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/entity/OtherEntity.kt: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.entity 2 | 3 | class OtherEntity(id: String, name: String) : MapperEntity() { 4 | init { 5 | this.id = id 6 | this.name = name 7 | } 8 | } 9 | 10 | object OtherEntityProvider { 11 | @JvmStatic 12 | fun listEcoLifeOptions(): List = listOf( 13 | OtherEntity("tick", "绿色行动🍃"), 14 | OtherEntity("plate", "光盘行动💽") 15 | ) 16 | 17 | @JvmStatic 18 | fun listHealthcareOptions(): List = listOf( 19 | OtherEntity("FEEDS", "绿色医疗💉"), 20 | OtherEntity("BILL", "电子小票🎫") 21 | ) 22 | 23 | @JvmStatic 24 | fun farmFamilyOption():List = listOf( 25 | OtherEntity("familySign", "每日签到📅"), 26 | OtherEntity("assignRights", "使用顶梁柱特权👷‍♂️"), 27 | OtherEntity("familyClaimReward", "领取奖励🏆️"), 28 | OtherEntity("feedFamilyAnimal", "帮喂小鸡🐔"), 29 | OtherEntity("eatTogetherConfig", "请吃美食🍲"), 30 | OtherEntity("deliverMsgSend", "道早安🌞"), 31 | OtherEntity("shareToFriends", "好友分享🙆‍♂️|下方配置排除列表"), 32 | ) 33 | } -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/util/LanguageUtil.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.util; 2 | import android.content.Context; 3 | import android.content.res.Configuration; 4 | import android.os.Build; 5 | import java.util.Locale; 6 | import fansirsqi.xposed.sesame.model.BaseModel; 7 | /** 8 | * 语言工具类,用于设置应用程序的语言环境。 9 | */ 10 | public class LanguageUtil { 11 | /** 12 | * 设置应用程序的语言环境为简体中文。 13 | * 如果配置指定使用简体中文,则忽略系统语言设置,强制应用简体中文。 14 | * 15 | * @param context 应用程序上下文,用于访问资源和配置。 16 | */ 17 | public static void setLocale(Context context) { 18 | // 检查是否设置了简体中文 19 | if (BaseModel.getLanguageSimplifiedChinese().getValue()) { 20 | // 创建简体中文的Locale对象 21 | Locale locale = new Locale.Builder().setLanguage("zh").setRegion("CN").build(); 22 | // 设置默认的Locale 23 | Locale.setDefault(locale); 24 | // 获取当前的配置信息 25 | Configuration config = new Configuration(context.getResources().getConfiguration()); 26 | // 更新配置信息中的Locale 27 | config.setLocale(locale); 28 | // 更新资源的配置信息,以应用新的Locale设置 29 | context = context.createConfigurationContext(config); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/task/antStall/ReadingDadaRpcCall.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.task.antStall; 2 | import fansirsqi.xposed.sesame.hook.RequestManager; 3 | import fansirsqi.xposed.sesame.util.StringUtil; 4 | /** 5 | * @author Constanline 6 | * @since 2023/08/22 7 | */ 8 | public class ReadingDadaRpcCall { 9 | private static final String VERSION = "1"; 10 | public static String submitAnswer(String activityId, String outBizId, String questionId, String answer) { 11 | return RequestManager.requestString("com.alipay.reading.game.dada.openDailyAnswer.submitAnswer", 12 | "[{\"activityId\":\"" + activityId + "\",\"answer\":\"" + answer + "\",\"dadaVersion\":\"1.3.0\"," + 13 | (StringUtil.isEmpty(outBizId) ? "" : "\"outBizId\":\"" + outBizId + "\",") + 14 | "\"questionId\":\"" + questionId + "\",\"version\":" + VERSION + "}]"); 15 | } 16 | public static String getQuestion(String activityId) { 17 | return RequestManager.requestString("com.alipay.reading.game.dada.openDailyAnswer.getQuestion", 18 | "[{\"activityId\":\"" + activityId + "\",\"dadaVersion\":\"1.3.0\",\"version\":" + VERSION + "}]"); 19 | } 20 | } -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/model/SelectModelFieldFunc.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.model; 2 | import java.util.LinkedHashMap; 3 | import java.util.Map; 4 | public interface SelectModelFieldFunc { 5 | void clear(); 6 | Integer get(String id); 7 | void add(String id, Integer count); 8 | void remove(String id); 9 | Boolean contains(String id); 10 | static SelectModelFieldFunc newMapInstance() { 11 | return new SelectModelFieldFunc() { 12 | private final Map map = new LinkedHashMap<>(); 13 | @Override 14 | public void clear() { 15 | map.clear(); 16 | } 17 | @Override 18 | public Integer get(String id) { 19 | return map.get(id); 20 | } 21 | @Override 22 | public void add(String id, Integer count) { 23 | map.put(id, count); 24 | } 25 | @Override 26 | public void remove(String id) { 27 | map.remove(id); 28 | } 29 | @Override 30 | public Boolean contains(String id) { 31 | return map.containsKey(id); 32 | } 33 | }; 34 | } 35 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/toast.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 20 | 21 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/layout/base_title.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/newmodel/ModelViews.kt: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.newmodel 2 | 3 | import androidx.compose.foundation.layout.* 4 | import androidx.compose.material3.* 5 | import androidx.compose.runtime.* 6 | import androidx.compose.ui.Alignment 7 | import androidx.compose.ui.Modifier 8 | import androidx.compose.ui.unit.dp 9 | import fansirsqi.xposed.sesame.model.ModelField 10 | 11 | @Composable 12 | fun BooleanFieldView(field: ModelField) { 13 | // 显式指定类型,并提供默认值 14 | var isChecked by remember { 15 | mutableStateOf(field.value as? Boolean ?: false) 16 | } 17 | 18 | Row( 19 | modifier = Modifier 20 | .fillMaxWidth() 21 | .padding(16.dp), 22 | verticalAlignment = Alignment.CenterVertically 23 | ) { 24 | // 确保 name 字段存在且可访问 25 | Text( 26 | text = field.name ?: "Unnamed Field", // 提供默认值以防 name 为 null 27 | style = MaterialTheme.typography.titleMedium, 28 | modifier = Modifier.weight(1f) 29 | ) 30 | Switch( 31 | checked = isChecked, 32 | onCheckedChange = { 33 | isChecked = it 34 | field.setObjectValue(it) // 更新字段值 35 | } 36 | ) 37 | } 38 | } -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/ui/widget/ExtendFunctionAdapter.kt: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.ui.widget 2 | 3 | import android.view.LayoutInflater 4 | import android.view.View 5 | import android.view.ViewGroup 6 | import android.widget.Button 7 | import androidx.recyclerview.widget.RecyclerView 8 | import fansirsqi.xposed.sesame.R 9 | import fansirsqi.xposed.sesame.entity.ExtendFunctionItem 10 | 11 | class ExtendFunctionAdapter( 12 | private val items: List 13 | ) : RecyclerView.Adapter() { 14 | 15 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { 16 | val view = LayoutInflater.from(parent.context) 17 | .inflate(R.layout.item_extend_function, parent, false) 18 | return ViewHolder(view) 19 | } 20 | 21 | override fun onBindViewHolder(holder: ViewHolder, position: Int) { 22 | val item = items[position] 23 | holder.button.text = item.name 24 | holder.button.setOnClickListener { item.action() } 25 | } 26 | 27 | override fun getItemCount(): Int = items.size 28 | 29 | class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { 30 | val button: Button = itemView.findViewById(R.id.button_extend_item) 31 | } 32 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_html_viewer.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 15 | 16 | 23 | 24 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/ui/dto/ModelDto.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.ui.dto; 2 | import lombok.Data; 3 | import java.io.Serializable; 4 | import java.util.List; 5 | /** 6 | * 模型数据传输对象。 7 | * 用于封装模型的代码、名称、组代码以及模型字段展示信息。 8 | */ 9 | @Data 10 | public class ModelDto implements Serializable { 11 | /** 12 | * 模型代码。 13 | */ 14 | private String modelCode; 15 | /** 16 | * 模型名称。 17 | */ 18 | private String modelName; 19 | /** 20 | * 模型图标 21 | */ 22 | private String modelIcon; 23 | /** 24 | * 组代码。 25 | */ 26 | private String groupCode; 27 | /** 28 | * 模型字段展示信息列表。 29 | */ 30 | private List modelFields; 31 | /** 32 | * 无参构造函数。 33 | */ 34 | public ModelDto() { 35 | } 36 | /** 37 | * 全参构造函数。 38 | * @param modelCode 模型代码 39 | * @param modelName 模型名称 40 | * @param groupCode 组代码 41 | * @param modelFields 模型字段展示信息列表 42 | */ 43 | public ModelDto(String modelCode, String modelName, String icon, String groupCode, List modelFields) { 44 | this.modelCode = modelCode; 45 | this.modelName = modelName; 46 | this.modelIcon = icon; 47 | this.groupCode = groupCode; 48 | this.modelFields = modelFields; 49 | } 50 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 14 | 15 | 16 | 23 | 24 | 25 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: 问题与 BUG 反馈 2 | description: 问题反馈应当使用此模板进行提交 3 | labels: [ bug ] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | ### 请在下方填写问题发生的具体原因和复现步骤。 9 | 10 | 发生异常、崩溃、闪退或功能性问题,必须提交问题 Log (日志),没有 Log 的 issues ,提醒不改直接关闭。 11 | - type: input 12 | attributes: 13 | label: | 14 | 程序版本 / 框架版本 / 模块版本 15 | description: 请填写当前使用的 程序版本 (例如:10.5.8,不要填最新版,提醒不改直接关闭)、框架版本 (例如:LSPosed 1.10.1 JingMatrix,不要填最新版) 及 模块版本 (例如:1.1.1,不要填最新版) 16 | validations: 17 | required: true 18 | - type: input 19 | attributes: 20 | label: | 21 | 系统版本 / Android版本 22 | description: 这里填写当前使用的 系统版本 (例如:MIUI、ColorOS、OxygenOS、LineageOS、PE/原生) 及 Android版本 (例如:Android 10、Android 11、Android 12) 23 | validations: 24 | required: true 25 | - type: textarea 26 | attributes: 27 | label: 详细描述问题发生的具体原因 28 | description: 请在下方详细描述问题发生的具体场景、复现步骤和经过,以便我们能够按照你所描述的步骤复现这个问题。 29 | validations: 30 | required: true 31 | - type: textarea 32 | attributes: 33 | label: 提供模块问题 Log 或必要 Log 34 | description: 闪退需提交闪退(crash)日志,无响应需提交无响应(ANR)日志,功能性问题需提交运行时(runtime)日志。 35 | value: | 36 |
展开查看

37 | 
38 |         (此处粘贴问题 Log)
39 | 
40 |         
41 | 42 | validations: 43 | required: true 44 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/model/ModelGroup.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.model; 2 | import lombok.Getter; 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | @Getter 6 | public enum ModelGroup { 7 | BASE("BASE", "基础", "svg/group/base.svg") 8 | , FOREST("FOREST", "森林", "svg/group/forest.svg") 9 | , FARM("FARM", "庄园", "svg/group/farm.svg") 10 | , STALL("STALL", "新村", "svg/group/stall.svg") 11 | , ORCHARD("ORCHARD", "农场", "svg/group/orchard.svg") 12 | , SPORTS("SPORTS", "运动", "svg/group/sports.svg") 13 | , MEMBER("MEMBER", "会员", "svg/group/member.svg") 14 | , OTHER("OTHER", "其他", "svg/group/other.svg") 15 | ; 16 | final String code; 17 | final String name; 18 | final String icon; 19 | ModelGroup(String code, String name, String icon) { 20 | this.code = code; 21 | this.name = name; 22 | this.icon = icon; 23 | } 24 | private static final Map MAP; 25 | static { 26 | MAP = new HashMap<>(); 27 | ModelGroup[] values = ModelGroup.values(); 28 | for (ModelGroup value : values) { 29 | MAP.put(value.code, value); 30 | } 31 | } 32 | public static ModelGroup getByCode(String code) { 33 | return MAP.get(code); 34 | } 35 | public static String getName(String code) { 36 | ModelGroup modelGroup = getByCode(code); 37 | if (modelGroup == null) { 38 | return null; 39 | } 40 | return modelGroup.name; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/ui/ChoiceDialog.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.ui; 2 | import android.content.Context; 3 | import android.content.DialogInterface; 4 | import android.widget.Button; 5 | import androidx.appcompat.app.AlertDialog; 6 | import androidx.core.content.ContextCompat; 7 | import fansirsqi.xposed.sesame.R; 8 | import fansirsqi.xposed.sesame.model.modelFieldExt.ChoiceModelField; 9 | public class ChoiceDialog { 10 | /** 11 | * 显示单选对话框 12 | * 13 | * @param context 当前上下文,用于构建对话框 14 | * @param title 对话框的标题 15 | * @param choiceModelField 包含选项数据的 ChoiceModelField 对象 16 | */ 17 | public static void show(Context context, CharSequence title, ChoiceModelField choiceModelField) { 18 | // 创建并显示单选对话框 19 | AlertDialog dialog = new AlertDialog.Builder(context) 20 | .setTitle(title) 21 | .setSingleChoiceItems(choiceModelField.getExpandKey(), choiceModelField.getValue(), 22 | (p1, p2) -> choiceModelField.setObjectValue(p2)) 23 | .setPositiveButton(context.getString(R.string.ok), null) 24 | .create(); 25 | dialog.setOnShowListener(dialogInterface -> { 26 | // 设置确认按钮颜色 27 | Button positiveButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE); 28 | if (positiveButton != null) { 29 | positiveButton.setTextColor(ContextCompat.getColor(context, R.color.selection_color)); 30 | } 31 | }); 32 | dialog.show(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | /app/normal/* 5 | /app/compatible/* 6 | /app/lint-baseline.xml 7 | *.jks 8 | # Files for the ART/Dalvik VM 9 | *.dex 10 | 11 | # Java class files 12 | *.class 13 | 14 | # Generated files 15 | bin/ 16 | gen/ 17 | out/ 18 | 19 | # Gradle files 20 | .gradle/ 21 | build/ 22 | release/ 23 | 24 | # Local configuration file (sdk path, etc) 25 | local.properties 26 | 27 | # Proguard folder generated by Eclipse 28 | proguard/ 29 | 30 | # Log Files 31 | *.log 32 | 33 | # Android Studio Navigation editor temp files 34 | .navigation/ 35 | 36 | # Android Studio captures folder 37 | captures/ 38 | 39 | # IntelliJ 40 | *.iml 41 | .idea/ 42 | 43 | # Keystore files 44 | # Uncomment the following line if you do not want to check your keystore files in. 45 | #*.jks 46 | 47 | # External native build folder generated in Android Studio 2.2 and later 48 | .externalNativeBuild 49 | 50 | # Google Services (e.g. APIs or Firebase) 51 | google-services.json 52 | 53 | # Freeline 54 | freeline.py 55 | freeline/ 56 | freeline_project_description.json 57 | 58 | # fastlane 59 | fastlane/report.xml 60 | fastlane/Preview.html 61 | fastlane/screenshots 62 | fastlane/test_output 63 | #fastlane/readme.md 64 | 65 | Xposed-Modules-Repo/ 66 | plugin/ 67 | demo/* 68 | /.vscode/settings.json 69 | *.REST 70 | *.txt 71 | *.json 72 | 73 | # CPP source code 74 | #C++源代码 75 | /app/src/main/cpp/ 76 | 77 | #编译缓存 78 | /app/.cxx/* 79 | 80 | # python virtual env 81 | .venv/ 82 | test 83 | 84 | # cache 85 | .lingma/rules/project_rule.md 86 | serve-debug/webhook.db 87 | *.pyc 88 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/ui/dto/ModelFieldShowDto.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.ui.dto; 2 | import lombok.Data; 3 | import fansirsqi.xposed.sesame.model.ModelField; 4 | import java.io.Serializable; 5 | /** 6 | * 模型字段展示数据传输对象。 7 | * 用于封装模型字段的展示信息,包括字段代码、名称、类型、扩展键和配置值。 8 | */ 9 | @Data 10 | public class ModelFieldShowDto implements Serializable { 11 | /** 12 | * 字段代码。 13 | */ 14 | private String code; 15 | /** 16 | * 字段名称。 17 | */ 18 | private String name; 19 | /** 20 | * 字段类型。 21 | */ 22 | private String type; 23 | /** 24 | * 扩展键,用于存储额外的信息。 25 | */ 26 | private Object expandKey; 27 | /** 28 | * 配置值,用于存储字段的配置信息。 29 | */ 30 | private String configValue; 31 | /** 32 | * 字段描述。 33 | */ 34 | private String desc; 35 | /** 36 | * 无参构造函数。 37 | */ 38 | public ModelFieldShowDto() { 39 | } 40 | /** 41 | * 将ModelField对象转换为ModelFieldShowDto对象。 42 | * 这是一个静态工厂方法,用于创建ModelFieldShowDto实例。 43 | * 44 | * @param modelField ModelField对象 45 | * @return ModelFieldShowDto对象 46 | */ 47 | public static ModelFieldShowDto toShowDto(ModelField modelField) { 48 | ModelFieldShowDto dto = new ModelFieldShowDto(); 49 | dto.setCode(modelField.getCode()); 50 | dto.setName(modelField.getName()); 51 | dto.setType(modelField.getType()); 52 | dto.setExpandKey(modelField.getExpandKey()); 53 | dto.setConfigValue(modelField.getConfigValue()); 54 | dto.setDesc(modelField.getDesc()); 55 | return dto; 56 | } 57 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/switch_thumb.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 26 | 27 | 28 | 29 | 30 | 31 | 34 | 35 | 36 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/task/antForest/GreenLife.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.task.antForest; 2 | import org.json.JSONObject; 3 | import fansirsqi.xposed.sesame.util.Log; 4 | import fansirsqi.xposed.sesame.util.ResChecker; 5 | public class GreenLife { 6 | public static final String TAG = GreenLife.class.getSimpleName(); 7 | /** 森林集市 */ 8 | public static void ForestMarket(String sourceType) { 9 | try { 10 | JSONObject jo = new JSONObject(AntForestRpcCall.consultForSendEnergyByAction(sourceType)); 11 | if (ResChecker.checkRes(TAG,jo)) { 12 | JSONObject data = jo.getJSONObject("data"); 13 | if (data.optBoolean("canSendEnergy", false)) { 14 | Thread.sleep(300); 15 | jo = new JSONObject(AntForestRpcCall.sendEnergyByAction(sourceType)); 16 | if (ResChecker.checkRes(TAG,jo)) { 17 | data = jo.getJSONObject("data"); 18 | if (data.optBoolean("canSendEnergy", false)) { 19 | int receivedEnergyAmount = data.getInt("receivedEnergyAmount"); 20 | Log.forest("集市逛街🛍[获得:能量" + receivedEnergyAmount + "g]"); 21 | } 22 | } 23 | } 24 | } else { 25 | Log.runtime(TAG, jo.getJSONObject("data").getString("resultCode")); 26 | Thread.sleep(300); 27 | } 28 | } catch (Throwable t) { 29 | Log.runtime(TAG, "sendEnergyByAction err:"); 30 | Log.printStackTrace(TAG, t); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/friend.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 18 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/ui/dto/ModelFieldInfoDto.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.ui.dto; 2 | import org.json.JSONException; 3 | import lombok.Data; 4 | import fansirsqi.xposed.sesame.model.ModelField; 5 | import java.io.Serializable; 6 | /** 7 | * 模型字段信息数据传输对象。 8 | * 用于封装模型字段的详细信息,包括字段代码、名称、类型、扩展键、扩展值和配置值。 9 | */ 10 | @Data 11 | public class ModelFieldInfoDto implements Serializable { 12 | /** 13 | * 字段代码。 14 | */ 15 | private String code; 16 | /** 17 | * 字段名称。 18 | */ 19 | private String name; 20 | /** 21 | * 字段类型。 22 | */ 23 | private String type; 24 | /** 25 | * 扩展键,用于存储额外的信息。 26 | */ 27 | private Object expandKey; 28 | /** 29 | * 扩展值,用于存储额外的信息。 30 | */ 31 | private Object expandValue; 32 | /** 33 | * 配置值,用于存储字段的配置信息。 34 | */ 35 | private String configValue; 36 | /** 37 | * 字段描述。 38 | */ 39 | private String desc; 40 | /** 41 | * 无参构造函数。 42 | */ 43 | public ModelFieldInfoDto() { 44 | } 45 | /** 46 | * 将ModelField对象转换为ModelFieldInfoDto对象。 47 | * @param modelField ModelField对象 48 | * @return ModelFieldInfoDto对象 49 | */ 50 | public static ModelFieldInfoDto toInfoDto(ModelField modelField) throws JSONException { 51 | ModelFieldInfoDto dto = new ModelFieldInfoDto(); 52 | dto.setCode(modelField.getCode()); 53 | dto.setName(modelField.getName()); 54 | dto.setType(modelField.getType()); 55 | dto.setExpandKey(modelField.getExpandKey()); 56 | dto.setExpandValue(modelField.getExpandValue()); 57 | dto.setConfigValue(modelField.getConfigValue()); 58 | dto.setDesc(modelField.getDesc()); 59 | return dto; 60 | } 61 | } -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/hook/server/handlers/DebugHandler.kt: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.hook.server.handlers 2 | 3 | import com.fasterxml.jackson.databind.JsonNode 4 | import fansirsqi.xposed.sesame.hook.RequestManager 5 | import fi.iki.elonen.NanoHTTPD 6 | import fi.iki.elonen.NanoHTTPD.Response 7 | import fi.iki.elonen.NanoHTTPD.IHTTPSession 8 | 9 | class DebugHandler(secretToken: String) : BaseHandler(secretToken) { 10 | 11 | override fun onGet(session: IHTTPSession): Response { 12 | return ok(mapOf("status" to "success", "method" to "GET")) 13 | } 14 | 15 | override fun onPost(session: IHTTPSession, body: String?): Response { 16 | val jsonNode: JsonNode = try { 17 | mapper.readTree(body ?: return badRequest("Empty body")) 18 | } catch (e: Exception) { 19 | return badRequest("Invalid JSON: ${e.message}") 20 | } 21 | 22 | val methodName = jsonNode.get("methodName")?.asText() ?: return badRequest("Missing methodName") 23 | val requestDataNode = jsonNode.get("requestData") ?: return badRequest("Missing requestData") 24 | 25 | val requestData = when { 26 | requestDataNode.isTextual -> requestDataNode.asText() 27 | requestDataNode.isArray || requestDataNode.isObject -> mapper.writeValueAsString(requestDataNode) 28 | else -> null 29 | } ?: return badRequest("Invalid requestData format") 30 | 31 | val result = try { 32 | RequestManager.requestString(methodName, requestData) 33 | } catch (e: Exception) { 34 | return badRequest("RPC call failed: ${e.message}") 35 | } 36 | 37 | return NanoHTTPD.newFixedLengthResponse(Response.Status.OK, BaseHandler.MIME_JSON, result) 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/github.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | 12 | 18 | 21 | 24 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/model/modelFieldExt/BooleanModelField.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.model.modelFieldExt; 2 | import android.content.Context; 3 | import android.view.View; 4 | import android.view.ViewGroup; 5 | import android.widget.LinearLayout; 6 | import android.widget.Switch; 7 | import fansirsqi.xposed.sesame.R; 8 | import fansirsqi.xposed.sesame.model.ModelField; 9 | public class BooleanModelField extends ModelField { 10 | /** 11 | * 构造函数,初始化 BooleanModelField 对象 12 | * 13 | * @param code 字段代码 14 | * @param name 字段名称 15 | * @param value 字段初始值 16 | */ 17 | public BooleanModelField(String code, String name, Boolean value) { 18 | super(code, name, value); // 调用父类构造函数 19 | } 20 | /** 21 | * 获取字段类型 22 | * 23 | * @return 字段类型字符串 24 | */ 25 | @Override 26 | public String getType() { 27 | return "BOOLEAN"; // 返回字段类型 28 | } 29 | /** 30 | * 创建并返回 Switch 视图 31 | * 32 | * @param context 上下文对象 33 | * @return 生成的 Switch 视图 34 | */ 35 | @Override 36 | public View getView(Context context) { 37 | Switch sw = new Switch(context); // 创建 Switch 控件 38 | sw.setText(getName()); // 设置 Switch 的文本为字段名称 39 | sw.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); // 设置布局参数 40 | sw.setMinHeight(150); // 设置最小高度 41 | sw.setMaxHeight(180); // 设置最大高度 42 | sw.setPaddingRelative(40, 0, 40, 0); // 设置左右内边距 43 | sw.setChecked(getValue()); // 根据字段值设置 Switch 的选中状态 44 | // 设置按钮和轨道样式 45 | sw.setThumbResource(R.drawable.switch_thumb); 46 | sw.setTrackResource(R.drawable.switch_track); 47 | // 设置点击监听器,更新字段值 48 | sw.setOnClickListener(v -> setObjectValue(((Switch) v).isChecked())); 49 | return sw; // 返回创建的 Switch 视图 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/ui/ObjReference.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.ui; 2 | import lombok.Data; 3 | /** 4 | * 非线程安全的引用包装器。 5 | * 提供了一个泛型对象的非线程安全访问和修改。 6 | * @param 泛型类型参数。 7 | */ 8 | @Data 9 | public class ObjReference { 10 | /** 11 | * 被包装的对象。 12 | */ 13 | private T obj; 14 | /** 15 | * 无参构造函数。 16 | */ 17 | public ObjReference() { 18 | } 19 | /** 20 | * 带对象的构造函数。 21 | * @param obj 被包装的对象。 22 | */ 23 | public ObjReference(T obj) { 24 | this.obj = obj; 25 | } 26 | /** 27 | * 检查对象是否存在。 28 | * @return 如果对象不为空,返回true。 29 | */ 30 | public Boolean has() { 31 | return this.obj != null; 32 | } 33 | /** 34 | * 获取被包装的对象。 35 | * @return 被包装的对象。 36 | */ 37 | public T get() { 38 | return obj; 39 | } 40 | /** 41 | * 设置被包装的对象。 42 | * 如果当前对象与传入对象相同,或当前对象为null且传入对象不为null,则设置对象并返回true。 43 | * @param obj 新的对象。 44 | * @return 如果设置成功,返回true。 45 | */ 46 | public Boolean set(T obj) { 47 | if (this.obj == obj) { 48 | return true; 49 | } 50 | if (this.obj != null) { 51 | return false; 52 | } 53 | this.obj = obj; 54 | return true; 55 | } 56 | /** 57 | * 强制设置被包装的对象。 58 | * 无论当前对象是什么,都会设置为传入的对象。 59 | * @param obj 新的对象。 60 | */ 61 | public void setForce(T obj) { 62 | this.obj = obj; 63 | } 64 | /** 65 | * 删除被包装的对象。 66 | */ 67 | public void del() { 68 | this.obj = null; 69 | } 70 | /** 71 | * 如果被包装的对象与传入对象相同,则删除。 72 | * @param obj 要比较的对象。 73 | */ 74 | public void delIfEquals(T obj) { 75 | if (this.obj == obj) { 76 | this.obj = null; 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/entity/VitalityStore.kt: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.entity 2 | 3 | import fansirsqi.xposed.sesame.util.maps.IdMapManager 4 | import fansirsqi.xposed.sesame.util.maps.VitalityRewardsMap 5 | import lombok.Getter 6 | 7 | /** 8 | * @author Byseven 9 | * @date 2025/1/20 10 | * @apiNote 11 | */ 12 | class VitalityStore(i: String, n: String) : MapperEntity() { 13 | init { 14 | this.id = i 15 | this.name = n 16 | } 17 | 18 | @Getter 19 | enum class ExchangeStatus(val nickName: String) { 20 | NO_ENOUGH_POINT("活力值不足"), 21 | NO_ENOUGH_STOCK("库存量不足"), 22 | REACH_LIMIT("兑换达上限"), 23 | SECKILL_NOT_BEGIN("秒杀未开始"), 24 | SECKILL_HAS_END("秒杀已结束"), 25 | HAS_NEVER_EXPIRE_DRESS("不限时皮肤"); 26 | } 27 | 28 | companion object { 29 | private var idNameMap: MutableMap? = null 30 | 31 | @JvmStatic 32 | val list: MutableList 33 | get() { 34 | val list: MutableList = ArrayList() 35 | val instance = IdMapManager.getInstance(VitalityRewardsMap::class.java) 36 | val entries = instance?.map?.entries ?: emptySet() 37 | 38 | for (entry in entries) { 39 | list.add(VitalityStore(entry.key!!, entry.value!!)) 40 | } 41 | return list 42 | } 43 | 44 | @JvmStatic 45 | fun getNameById(id: String?): String? { 46 | if (idNameMap == null) { 47 | idNameMap = HashMap() 48 | for (store in list) { 49 | idNameMap!!.put(store.id, store.name) 50 | } 51 | } 52 | return idNameMap!![id] 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/model/modelFieldExt/StringModelField.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.model.modelFieldExt; 2 | import android.content.Context; 3 | import android.view.Gravity; 4 | import android.view.View; 5 | import android.view.ViewGroup; 6 | import android.widget.Button; 7 | import android.widget.LinearLayout; 8 | import androidx.core.content.ContextCompat; 9 | import fansirsqi.xposed.sesame.R; 10 | import fansirsqi.xposed.sesame.model.ModelField; 11 | import fansirsqi.xposed.sesame.ui.StringDialog; 12 | public class StringModelField extends ModelField { 13 | public StringModelField(String code, String name, String value) { 14 | super(code, name, value); 15 | } 16 | @Override 17 | public String getType() { 18 | return "STRING"; 19 | } 20 | @Override 21 | public String getConfigValue() { 22 | return value; 23 | } 24 | @Override 25 | public void setConfigValue(String configValue) { 26 | value = configValue; 27 | } 28 | @Override 29 | public View getView(Context context) { 30 | Button btn = new Button(context); 31 | btn.setText(getName()); 32 | btn.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); 33 | btn.setTextColor(ContextCompat.getColor(context, R.color.selection_color)); 34 | btn.setBackground(ContextCompat.getDrawable(context, R.drawable.dialog_list_button)); 35 | btn.setGravity(Gravity.START | Gravity.CENTER_VERTICAL); 36 | btn.setMinHeight(150); 37 | btn.setMaxHeight(180); 38 | btn.setPaddingRelative(40, 0, 40, 0); 39 | btn.setAllCaps(false); 40 | btn.setOnClickListener(v -> StringDialog.showEditDialog(v.getContext(), ((Button) v).getText(), this)); 41 | return btn; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/util/Average.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.util; 2 | /**平均值计算工具类*/ 3 | public class Average { 4 | /** 使用一个循环队列来存储固定数量的数值*/ 5 | private final CircularFifoQueue queue; 6 | /** 数值的总和,用于计算平均值*/ 7 | private double sum; 8 | /** 当前的平均值*/ 9 | private double average; 10 | /** 构造函数,初始化队列大小,初始总和和平均值*/ 11 | public Average(int size) { 12 | this.queue = new CircularFifoQueue<>(size); // 创建一个固定大小的循环队列 13 | this.sum = 0.0; // 初始化总和为 0 14 | this.average = 0.0; // 初始化平均值为 0 15 | } 16 | /** 17 | * 计算下一个数值加入后的新平均值 18 | * 19 | * @param value 新加入的数值 20 | * @return 当前的平均值 21 | */ 22 | public double nextDouble(int value) { 23 | // 将新值添加到队列中,并移除队列中的旧值(如果有的话) 24 | Integer last = queue.push(value); 25 | // 如果队列中有旧值,则从总和中减去它 26 | if (last != null) { 27 | sum -= last; 28 | } 29 | // 将新值加入到总和中 30 | sum += value; 31 | // 计算并返回新的平均值 32 | return average = sum / queue.size(); 33 | } 34 | /** 35 | * 计算下一个数值加入后的新平均值(返回整数) 36 | * 37 | * @param value 新加入的数值 38 | * @return 当前的平均值(整数) 39 | */ 40 | public int nextInteger(int value) { 41 | // 使用 nextDouble 方法计算平均值,然后强制转换为整数 42 | return (int) nextDouble(value); 43 | } 44 | /** 45 | * 获取当前的平均值(浮动型) 46 | * 47 | * @return 当前的平均值 48 | */ 49 | public double averageDouble() { 50 | return average; 51 | } 52 | /** 53 | * 获取当前的平均值(整数型) 54 | * 55 | * @return 当前的平均值(整数) 56 | */ 57 | public int getAverageInteger() { 58 | return (int) average; 59 | } 60 | /** 61 | * 清除队列和重置所有统计数据 62 | */ 63 | public void clear() { 64 | // 清空队列 65 | queue.clear(); 66 | // 重置总和和平均值 67 | sum = 0.0; 68 | average = 0.0; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/entity/AlipayUser.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.entity; 2 | import fansirsqi.xposed.sesame.util.Log; 3 | import fansirsqi.xposed.sesame.util.maps.UserMap; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | import java.util.Map; 7 | /** 8 | * 表示支付宝用户的实体类,包含 ID 和名称。 9 | */ 10 | public class AlipayUser extends MapperEntity { 11 | /** 12 | * 构造方法,根据给定的 ID 和名称初始化用户对象。 13 | * @param i 用户的 ID 14 | * @param n 用户的名称 15 | */ 16 | public AlipayUser(String i, String n) { 17 | id = i; 18 | name = n; 19 | } 20 | /** 21 | * 获取所有用户的列表,不使用任何过滤器。 22 | * @return 包含所有符合条件的 AlipayUser 对象的列表 23 | */ 24 | public static List getList() { 25 | return getList(user -> true); // 默认不过滤 26 | } 27 | /** 28 | * 获取符合过滤条件的用户列表。 29 | * @param filterFunc 过滤函数,用于筛选用户 30 | * @return 符合条件的 AlipayUser 对象列表 31 | */ 32 | public static List getList(Filter filterFunc) { 33 | List list = new ArrayList<>(); 34 | Map userIdMap = UserMap.getUserMap(); 35 | for (Map.Entry entry : userIdMap.entrySet()) { 36 | UserEntity userEntity = entry.getValue(); 37 | try { 38 | // 使用过滤器判断是否添加用户 39 | if (filterFunc.apply(userEntity)) { 40 | list.add(new AlipayUser(entry.getKey(), userEntity.getFullName())); 41 | } 42 | } catch (Throwable t) { 43 | Log.printStackTrace(t); // 捕获并记录异常 44 | } 45 | } 46 | return list; 47 | } 48 | /** 49 | * 过滤接口,用于筛选符合条件的用户。 50 | */ 51 | public interface Filter { 52 | /** 53 | * 判断给定用户是否符合条件。 54 | * @param user 用户实体对象 55 | * @return 符合条件返回 true,否则返回 false 56 | */ 57 | Boolean apply(UserEntity user); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/entity/AlipayVersion.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.entity; 2 | import lombok.Getter; 3 | /** 4 | * 表示支付宝版本的实体类,可进行版本比较。 5 | */ 6 | @Getter 7 | public class AlipayVersion implements Comparable { 8 | // 原始版本字符串 9 | private final String versionString; 10 | // 版本号数组,用于比较 11 | private final Integer[] versionArray; 12 | /** 13 | * 构造方法,将版本字符串解析为整数数组。 14 | * @param versionString 版本号字符串(以点号分隔,例如 "10.1.1") 15 | */ 16 | public AlipayVersion(String versionString) { 17 | this.versionString = versionString; 18 | String[] split = versionString.split("\\."); 19 | int length = split.length; 20 | versionArray = new Integer[length]; 21 | for (int i = 0; i < length; i++) { 22 | try { 23 | versionArray[i] = Integer.parseInt(split[i]); 24 | } catch (NumberFormatException e) { 25 | versionArray[i] = Integer.MAX_VALUE; // 如果解析失败,使用 Integer.MAX_VALUE 表示 26 | } 27 | } 28 | } 29 | /** 30 | * 实现版本比较逻辑。 31 | * @param alipayVersion 需要比较的另一个 AlipayVersion 实例 32 | * @return -1 表示当前版本小于对比版本,1 表示大于,0 表示相等 33 | */ 34 | @Override 35 | public int compareTo(AlipayVersion alipayVersion) { 36 | int thisLength = versionArray.length; 37 | int thatLength = alipayVersion.versionArray.length; 38 | int compareResult = Integer.compare(thisLength, thatLength); // 比较长度 39 | int minLength = Math.min(thisLength, thatLength); // 取最小长度 40 | // 按版本号逐段比较 41 | for (int i = 0; i < minLength; i++) { 42 | int thisVer = versionArray[i]; 43 | int thatVer = alipayVersion.versionArray[i]; 44 | if (thisVer != thatVer) { 45 | return Integer.compare(thisVer, thatVer); 46 | } 47 | } 48 | // 如果所有对应段都相等,返回长度比较结果 49 | return compareResult; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/task/reserve/ReserveRpcCall.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.task.reserve; 2 | import fansirsqi.xposed.sesame.hook.RequestManager; 3 | public class ReserveRpcCall { 4 | private static final String VERSION = "20230501"; 5 | private static final String VERSION2 = "20230522"; 6 | public static String queryTreeItemsForExchange() { 7 | return RequestManager.requestString("alipay.antforest.forest.h5.queryTreeItemsForExchange", 8 | "[{\"cityCode\":\"370100\",\"itemTypes\":\"\",\"source\":\"chInfo_ch_appcenter__chsub_9patch\",\"version\":\"" 9 | + VERSION2 + "\"}]"); 10 | } 11 | public static String queryTreeForExchange(String projectId) { 12 | return RequestManager.requestString("alipay.antforest.forest.h5.queryTreeForExchange", 13 | "[{\"projectId\":\"" + projectId + "\",\"version\":\"" + VERSION 14 | + "\",\"source\":\"chInfo_ch_appcenter__chsub_9patch\"}]"); 15 | } 16 | public static String exchangeTree(String projectId) { 17 | int projectId_num = Integer.parseInt(projectId); 18 | return RequestManager.requestString("alipay.antmember.forest.h5.exchangeTree", 19 | "[{\"projectId\":" + projectId_num + ",\"sToken\":\"" + System.currentTimeMillis() + "\",\"version\":\"" 20 | + VERSION + "\",\"source\":\"chInfo_ch_appcenter__chsub_9patch\"}]"); 21 | } 22 | /* 查询地图树苗 */ 23 | public static String queryAreaTrees() { 24 | return RequestManager.requestString("alipay.antmember.forest.h5.queryAreaTrees", "[{}]"); 25 | } 26 | public static String queryTreeItemsForExchange(String applyActions, String itemTypes) { 27 | String args = "[{\"applyActions\":\"" + applyActions + "\",\"itemTypes\":\"" + itemTypes + "\"}]"; 28 | return RequestManager.requestString("alipay.antforest.forest.h5.queryTreeItemsForExchange", args); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/hook/HookSender.kt: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.hook 2 | 3 | import fansirsqi.xposed.sesame.util.Log 4 | import okhttp3.Call 5 | import okhttp3.Callback 6 | import okhttp3.MediaType 7 | import okhttp3.MediaType.Companion.toMediaType 8 | import okhttp3.OkHttpClient 9 | import okhttp3.Request 10 | import okhttp3.RequestBody 11 | import okhttp3.RequestBody.Companion.toRequestBody 12 | import okhttp3.Response 13 | import org.json.JSONObject 14 | import java.io.IOException 15 | 16 | /** 17 | * 用于发送Hook数据到DEBUG服务器 18 | * @author Byseven 19 | * @date 2025/1/17 20 | * @apiNote 21 | */ 22 | object HookSender { 23 | private const val TAG = "HookSender" 24 | var sendFlag: Boolean = true 25 | private val client = OkHttpClient() 26 | 27 | private val JSON_MEDIA_TYPE: MediaType? = "application/json; charset=utf-8".toMediaType() 28 | 29 | fun sendHookData(jo: JSONObject, url: String) { 30 | try { 31 | val body: RequestBody = jo.toString().toRequestBody(JSON_MEDIA_TYPE) 32 | val request = Request.Builder() 33 | .url(url) 34 | .post(body) 35 | .build() 36 | client.newCall(request).enqueue(object : Callback { 37 | override fun onFailure(call: Call, e: IOException) { 38 | if (!sendFlag) {//避免过多冗余失败记录 39 | Log.error(TAG, "Failed to send hook data: ${e.message}") 40 | sendFlag = false 41 | } 42 | } 43 | 44 | override fun onResponse(call: Call, response: Response) { 45 | if (!response.isSuccessful) Log.error(TAG, "Failed to receive response: $response") 46 | // } else { 47 | // Log.runtime(TAG, "Hook data sent successfully.") 48 | // } 49 | } 50 | }) 51 | } catch (_: Exception) { 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/hook/server/ModuleHttpServer.kt: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.hook.server 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper 4 | import fansirsqi.xposed.sesame.hook.server.handlers.HttpHandler 5 | import fansirsqi.xposed.sesame.hook.server.handlers.DebugHandler 6 | import fansirsqi.xposed.sesame.util.Log 7 | import fi.iki.elonen.NanoHTTPD 8 | 9 | class ModuleHttpServer( 10 | port: Int = 8080, 11 | secretToken: String = "" 12 | ) : NanoHTTPD("0.0.0.0", port) { 13 | private val tag = "ModuleHttpServer" 14 | 15 | companion object { 16 | const val MIME_PLAINTEXT = "text/plain" 17 | } 18 | 19 | private val routes = mutableMapOf() 20 | private val pathDescriptions = mapOf( 21 | "/debugHandler" to "调试接口", 22 | ) 23 | 24 | init { 25 | // 后续新增接口只需在这里注册即可 26 | 27 | register("/debugHandler", DebugHandler(secretToken)) 28 | } 29 | 30 | private fun register(path: String, handler: HttpHandler) { 31 | Log.runtime(tag, "Registering handler : $pathDescriptions[$path]") 32 | routes[path] = handler 33 | } 34 | 35 | override fun serve(session: IHTTPSession): Response { 36 | val uri = session.uri 37 | val handler = routes[uri] ?: return notFound() 38 | 39 | // 如果是 POST 请求,读取 body 40 | var body: String? = null 41 | if (session.method === Method.POST) { 42 | body = getPostBody(session) 43 | } 44 | 45 | return handler.handle(session, body) 46 | } 47 | 48 | private fun getPostBody(session: IHTTPSession): String? { 49 | val size = session.headers["content-length"]?.toIntOrNull() ?: return null 50 | val buffer = ByteArray(size) 51 | session.inputStream.read(buffer, 0, size) 52 | return String(buffer) 53 | } 54 | 55 | private fun notFound(): Response { 56 | return newFixedLengthResponse(Response.Status.NOT_FOUND, MIME_PLAINTEXT, "Not Found") 57 | } 58 | } -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/entity/AlipayBeach.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.entity; 2 | import fansirsqi.xposed.sesame.util.maps.BeachMap; 3 | import fansirsqi.xposed.sesame.util.maps.IdMapManager; 4 | import java.util.ArrayList; 5 | import java.util.Collections; 6 | import java.util.List; 7 | import java.util.Map; 8 | /** 9 | * 表示支付宝海滩的实体类,包含 ID 和名称。 10 | */ 11 | public class AlipayBeach extends MapperEntity { 12 | // 使用 volatile 关键字确保多线程环境下的可见性 13 | private static volatile List list; 14 | /** 15 | * 构造方法,根据给定的 ID 和名称初始化对象。 16 | * @param i 海滩的 ID 17 | * @param n 海滩的名称 18 | */ 19 | public AlipayBeach(String i, String n) { 20 | id = i; 21 | name = n; 22 | } 23 | /** 24 | * 获取包含所有海滩的列表,首次调用时从 BeachMap 初始化。 25 | * 使用双重检查锁定机制实现懒加载以提高性能。 26 | * @return 包含所有 AlipayBeach 对象的不可变列表 27 | */ 28 | public static List getList() { 29 | if (list == null) { 30 | synchronized (AlipayBeach.class) { 31 | if (list == null) { 32 | List tempList = new ArrayList<>(); 33 | for (Map.Entry entry : IdMapManager.getInstance(BeachMap.class).getMap().entrySet()) { 34 | tempList.add(new AlipayBeach(entry.getKey(), entry.getValue())); 35 | } 36 | list = Collections.unmodifiableList(tempList); 37 | } 38 | } 39 | } 40 | return list; 41 | } 42 | /** 43 | * 根据给定的 ID 删除相应的 AlipayBeach 对象。 44 | * 首次调用 getList 方法以确保列表已初始化。 45 | * @param id 要删除的海滩 ID 46 | */ 47 | public static void remove(String id) { 48 | getList(); 49 | synchronized (AlipayBeach.class) { 50 | list = new ArrayList<>(list); // 创建可变列表的副本 51 | list.removeIf(beach -> beach.id.equals(id)); // 使用流简化移除操作 52 | list = Collections.unmodifiableList(list); // 确保返回不可变列表 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/model/ModelOrder.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.model; 2 | import java.util.ArrayList; 3 | import java.util.Collections; 4 | import java.util.List; 5 | import fansirsqi.xposed.sesame.task.AnswerAI.AnswerAI; 6 | import fansirsqi.xposed.sesame.task.ancientTree.AncientTree; 7 | import fansirsqi.xposed.sesame.task.antCooperate.AntCooperate; 8 | import fansirsqi.xposed.sesame.task.antDodo.AntDodo; 9 | import fansirsqi.xposed.sesame.task.antFarm.AntFarm; 10 | import fansirsqi.xposed.sesame.task.antForest.AntForest; 11 | import fansirsqi.xposed.sesame.task.antMember.AntMember; 12 | import fansirsqi.xposed.sesame.task.antOcean.AntOcean; 13 | import fansirsqi.xposed.sesame.task.antOrchard.AntOrchard; 14 | import fansirsqi.xposed.sesame.task.antSports.AntSports; 15 | import fansirsqi.xposed.sesame.task.antStall.AntStall; 16 | import fansirsqi.xposed.sesame.task.consumeGold.ConsumeGold; 17 | import fansirsqi.xposed.sesame.task.greenFinance.GreenFinance; 18 | import fansirsqi.xposed.sesame.task.reserve.Reserve; 19 | import lombok.Getter; 20 | public class ModelOrder { 21 | @SuppressWarnings("unchecked") 22 | private static final Class[] array = new Class[]{ 23 | BaseModel.class,//基础设置 24 | AntForest.class,//森林 25 | AntFarm.class,//庄园 26 | AntOrchard.class,//农场 27 | AntOcean.class,//海洋 28 | AntDodo.class,//神奇物种 29 | AncientTree.class,//古树 30 | AntCooperate.class,//合种 31 | Reserve.class,//保护地 32 | AntSports.class,//运动 33 | AntMember.class,//会员 34 | AntStall.class,//蚂蚁新村 35 | GreenFinance.class,//绿色经营 36 | // AntBookRead.class,//读书 37 | // ConsumeGold.class,//消费金 38 | // OmegakoiTown.class,//小镇 39 | AnswerAI.class,//AI答题 40 | }; 41 | @Getter private static final List> clazzList = new ArrayList<>(); 42 | static { 43 | Collections.addAll(clazzList, array); 44 | } 45 | } -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/task/TaskCommon.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.task; 2 | 3 | import java.util.List; 4 | 5 | import fansirsqi.xposed.sesame.model.BaseModel; 6 | import fansirsqi.xposed.sesame.util.Log; 7 | import fansirsqi.xposed.sesame.util.TimeUtil; 8 | 9 | /** 10 | * 通用任务工具类 11 | *

12 | * 提供任务相关的通用功能,包括时间判断和状态更新。 13 | */ 14 | public class TaskCommon { 15 | public static volatile Boolean IS_ENERGY_TIME = false; 16 | public static volatile Boolean IS_AFTER_8AM = false; 17 | public static volatile Boolean IS_MODULE_SLEEP_TIME = false; 18 | 19 | public static void update() { 20 | 21 | Log.runtime("TaskCommon Update:"); 22 | long currentTimeMillis = System.currentTimeMillis(); 23 | List isEnergyTime = BaseModel.getEnergyTime().getValue(); 24 | Log.runtime("获取能量时间配置:" + isEnergyTime); 25 | if (isConfigDisabled(isEnergyTime)) { 26 | Log.runtime("只收能量时间配置已关闭"); 27 | IS_ENERGY_TIME = false; 28 | } else { 29 | IS_ENERGY_TIME = TimeUtil.checkInTimeRange(currentTimeMillis, isEnergyTime); 30 | } 31 | 32 | List isModuleSleepTime = BaseModel.getModelSleepTime().getValue(); 33 | Log.runtime("获取模块休眠配置:" + isModuleSleepTime); 34 | if (isConfigDisabled(isModuleSleepTime)) { 35 | Log.runtime("休眠配置已关闭"); 36 | IS_MODULE_SLEEP_TIME = false; 37 | } else { 38 | IS_MODULE_SLEEP_TIME = TimeUtil.checkInTimeRange(currentTimeMillis, isModuleSleepTime); 39 | } 40 | 41 | IS_AFTER_8AM = TimeUtil.isAfterOrCompareTimeStr(currentTimeMillis, "0800"); 42 | } 43 | 44 | /** 45 | * 判断当前配置是否表示“关闭” 46 | * 47 | * @param config 输入的字符串列表 48 | * @return true 表示关闭 49 | */ 50 | public static boolean isConfigDisabled(List config) { 51 | if (config == null || config.isEmpty()) return true; 52 | 53 | String first = config.get(0).trim(); 54 | 55 | return "-1".equals(first); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/util/FansirsqiUtil.kt: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.util 2 | 3 | import kotlinx.coroutines.Dispatchers 4 | import kotlinx.coroutines.withContext 5 | import org.json.JSONObject 6 | import java.io.BufferedReader 7 | import java.io.InputStreamReader 8 | import java.net.HttpURLConnection 9 | import java.net.URL 10 | 11 | object FansirsqiUtil { 12 | // 定义一言API的URL 13 | private const val HITOKOTO_API_URL = "https://v1.hitokoto.cn/" 14 | 15 | /** 16 | * 获取一言(挂起函数),推荐在协程中使用 17 | * @return 成功返回句子,失败返回默认句子 18 | */ 19 | suspend fun getOneWord(): String = withContext(Dispatchers.IO) { 20 | return@withContext try { 21 | val connection = URL(HITOKOTO_API_URL).openConnection() as HttpURLConnection 22 | connection.requestMethod = "GET" 23 | connection.connectTimeout = 5000 24 | connection.readTimeout = 5000 25 | 26 | val response = BufferedReader(InputStreamReader(connection.inputStream)).use { reader -> 27 | reader.readText() 28 | } 29 | 30 | val jsonObject = JSONObject(response) 31 | val hitokoto = jsonObject.optString( 32 | "hitokoto", 33 | " 去年相送,余杭门外,飞雪似杨花。\n今年春尽,杨花似雪,犹不见还家。" 34 | ) 35 | val from = jsonObject.optString("from", "少年游·润州作代人寄远 苏轼") 36 | 37 | "$hitokoto\n\n -----Re: $from" 38 | } catch (e: Exception) { 39 | Log.printStackTrace(e) 40 | " 去年相送,余杭门外,飞雪似杨花。\n今年春尽,杨花似雪,犹不见还家。\n\n -----Re: 少年游·润州作代人寄远 苏轼" 41 | } 42 | } 43 | 44 | /** 45 | * 生成随机字符串 46 | * @param length 字符串长度 47 | */ 48 | fun getRandomString(length: Int): String { 49 | val charPool: List = ('a'..'z') + ('A'..'Z') + ('0'..'9') 50 | return (1..length) 51 | .map { kotlin.random.Random.nextInt(0, charPool.size) } 52 | .map(charPool::get) 53 | .joinToString("") 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 | 26 | 27 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/extensions/JSONExtensions.kt: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.extensions 2 | 3 | import org.json.JSONArray 4 | import org.json.JSONException 5 | 6 | // 所有JSON相关的扩展函数放在这里 7 | 8 | 9 | /** 10 | * JSON 相关扩展函数集合 11 | */ 12 | object JSONExtensions { 13 | 14 | /** 15 | * 安全地将 List 转换为 JSONArray 16 | * @receiver 字符串列表(允许为null,返回空JSONArray) 17 | */ 18 | fun List?.toSafeJSONArray(): JSONArray { 19 | return this?.let { JSONArray(it) } ?: JSONArray() 20 | } 21 | 22 | /** 23 | * 将 MutableList 转换为 JSONArray 24 | * @receiver 可变的字符串集合 25 | * @throws JSONException 如果元素包含无效的JSON值 26 | */ 27 | fun MutableList.toJSONArray(): JSONArray = JSONArray(this) 28 | 29 | /** 30 | * 将 JSONArray 转换为 MutableList 31 | * @receiver JSON数组对象 32 | * @throws JSONException 如果数组包含非字符串元素 33 | */ 34 | fun JSONArray.toMutableStringList(): MutableList { 35 | return MutableList(length()) { getString(it) } 36 | } 37 | 38 | /** 39 | * 安全地将 JSONArray 转换为 List 40 | * @receiver JSON数组对象(允许为null,返回空列表) 41 | * @param default 转换失败时的默认值 42 | */ 43 | fun JSONArray?.toSafeStringList(default: String = ""): List { 44 | if (this == null) return emptyList() 45 | return try { 46 | List(length()) { getString(it) ?: default } 47 | } catch (e: JSONException) { 48 | emptyList() 49 | } 50 | } 51 | 52 | /** 53 | * 将 JSONArray 转换为指定类型的列表 54 | * @param transform 类型转换函数 55 | */ 56 | inline fun JSONArray.toList(transform: (Any?) -> T): List { 57 | return List(length()) { transform(get(it)) } 58 | } 59 | 60 | /** 61 | * 检查 JSONArray 是否为空 62 | */ 63 | fun JSONArray?.isNullOrEmpty(): Boolean { 64 | return this == null || length() == 0 65 | } 66 | 67 | /** 68 | * 如果 JSONArray 为null则返回空数组 69 | */ 70 | fun JSONArray?.orEmpty(): JSONArray { 71 | return this ?: JSONArray() 72 | } 73 | } 74 | 75 | 76 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/hook/rpc/bridge/RpcBridge.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.hook.rpc.bridge; 2 | import fansirsqi.xposed.sesame.entity.RpcEntity; 3 | public interface RpcBridge { 4 | RpcVersion getVersion(); 5 | void load() throws Exception; 6 | void unload(); 7 | String requestString(RpcEntity rpcEntity, int tryCount, int retryInterval); 8 | default String requestString(RpcEntity rpcEntity) { 9 | return requestString(rpcEntity, 3, -1); 10 | } 11 | default String requestString(String method, String data) { 12 | return requestString(method, data, 3, -1); 13 | } 14 | default String requestString(String method, String data, String relation) { 15 | return requestString(method, data, relation, 3, -1); 16 | } 17 | default String requestString(String method, String data, String appName, String methodName, String facadeName) { 18 | return requestString(new RpcEntity(method, data, appName, methodName, facadeName), 3, -1); 19 | } 20 | default String requestString(String method, String data, int tryCount, int retryInterval) { 21 | return requestString(new RpcEntity(method, data), tryCount, retryInterval); 22 | } 23 | default String requestString(String method, String data, String relation, int tryCount, int retryInterval) { 24 | return requestString(new RpcEntity(method, data, relation), tryCount, retryInterval); 25 | } 26 | RpcEntity requestObject(RpcEntity rpcEntity, int tryCount, int retryInterval); 27 | 28 | default RpcEntity requestObject(String method, String data, String relation) { 29 | return requestObject(method, data, relation, 3, -1); 30 | } 31 | default RpcEntity requestObject(String method, String data, int tryCount, int retryInterval) { 32 | return requestObject(new RpcEntity(method, data), tryCount, retryInterval); 33 | } 34 | default RpcEntity requestObject(String method, String data, String relation, int tryCount, int retryInterval) { 35 | return requestObject(new RpcEntity(method, data, relation), tryCount, retryInterval); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/util/GlobalThreadPools.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.util; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | import java.util.concurrent.LinkedBlockingQueue; 6 | import java.util.concurrent.ScheduledExecutorService; 7 | import java.util.concurrent.SynchronousQueue; 8 | import java.util.concurrent.ThreadPoolExecutor; 9 | import java.util.concurrent.TimeUnit; 10 | 11 | /** 12 | * 全局线程池管理类 13 | */ 14 | public class GlobalThreadPools { 15 | private static final String TAG = "GlobalThreadPools"; 16 | 17 | /** 18 | * 使当前线程暂停指定的毫秒数。 19 | * 20 | * @param millis 毫秒数。 21 | */ 22 | public static void sleep(long millis) { 23 | try { 24 | Thread.sleep(millis); 25 | } catch (InterruptedException e) { 26 | Log.error(TAG, "Thread sleep interrupted " + e.getMessage()); 27 | Thread.currentThread().interrupt(); 28 | } catch (Exception e1) { 29 | Log.printStackTrace(e1); 30 | // Thread.currentThread().interrupt(); 31 | Log.error(TAG, "Thread sleep interrupted " + e1.getMessage()); 32 | } catch (Throwable t) { 33 | Log.printStackTrace(t); 34 | // Thread.currentThread().interrupt(); 35 | Log.error(TAG, "Thread sleep interrupted " + t.getMessage()); 36 | } 37 | } 38 | 39 | public static void shutdownAndAwaitTermination(ExecutorService pool, long timeout, String poolName) { 40 | if (pool != null && !pool.isShutdown()) { 41 | pool.shutdown(); 42 | try { 43 | if (!pool.awaitTermination(1, TimeUnit.SECONDS)) { 44 | pool.shutdownNow(); 45 | if (!pool.awaitTermination(timeout, TimeUnit.SECONDS)) { 46 | Log.runtime(TAG, "thread " + poolName + " can't close"); 47 | } 48 | } 49 | } catch (InterruptedException ie) { 50 | pool.shutdownNow(); 51 | Thread.currentThread().interrupt(); 52 | } 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/task/ancientTree/AncientTreeRpcCall.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.task.ancientTree; 2 | import fansirsqi.xposed.sesame.hook.RequestManager; 3 | public class AncientTreeRpcCall { 4 | private static final String VERSION = "20230522"; 5 | public static String homePage(String selectCityCode) { 6 | return RequestManager.requestString("alipay.greenmatrix.rpc.h5.ancienttree.homePage", 7 | "[{\"cityCode\":\"330100\",\"selectCityCode\":\"" + selectCityCode 8 | + "\",\"source\":\"antforesthome\"}]"); 9 | } 10 | public static String queryTreeItemsForExchange(String cityCode) { 11 | return RequestManager.requestString("alipay.antforest.forest.h5.queryTreeItemsForExchange", 12 | "[{\"cityCode\":\"" + cityCode 13 | + "\",\"itemTypes\":\"\",\"source\":\"chInfo_ch_appcenter__chsub_9patch\",\"version\":\"" 14 | + VERSION + "\"}]"); 15 | } 16 | public static String districtDetail(String districtCode) { 17 | return RequestManager.requestString("alipay.greenmatrix.rpc.h5.ancienttree.districtDetail", 18 | "[{\"districtCode\":\"" + districtCode + "\",\"source\":\"antforesthome\"}]"); 19 | } 20 | public static String projectDetail(String ancientTreeProjectId, String cityCode) { 21 | return RequestManager.requestString("alipay.greenmatrix.rpc.h5.ancienttree.projectDetail", 22 | "[{\"ancientTreeProjectId\":\"" + ancientTreeProjectId 23 | + "\",\"channel\":\"ONLINE\",\"cityCode\":\"" + cityCode 24 | + "\",\"source\":\"ancientreethome\"}]"); 25 | } 26 | public static String protect(String activityId, String ancientTreeProjectId, String cityCode) { 27 | return RequestManager.requestString("alipay.greenmatrix.rpc.h5.ancienttree.protect", 28 | "[{\"ancientTreeActivityId\":\"" + activityId + "\",\"ancientTreeProjectId\":\"" 29 | + ancientTreeProjectId + "\",\"cityCode\":\"" + cityCode 30 | + "\",\"source\":\"ancientreethome\"}]"); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/ui/ObjSyncReference.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.ui; 2 | import lombok.Data; 3 | /** 4 | * 线程安全的引用包装器。 5 | * 提供了一个泛型对象的线程安全访问和修改。 6 | * @param 泛型类型参数。 7 | */ 8 | @Data 9 | public class ObjSyncReference { 10 | /** 11 | * 被包装的对象。 12 | */ 13 | private T obj; 14 | /** 15 | * 无参构造函数。 16 | */ 17 | public ObjSyncReference() { 18 | } 19 | /** 20 | * 带对象的构造函数。 21 | * @param obj 被包装的对象。 22 | */ 23 | public ObjSyncReference(T obj) { 24 | this.obj = obj; 25 | } 26 | /** 27 | * 检查对象是否存在。 28 | * @return 如果对象不为空,返回true。 29 | */ 30 | public Boolean has() { 31 | synchronized (this) { 32 | return this.obj != null; 33 | } 34 | } 35 | /** 36 | * 获取被包装的对象。 37 | * @return 被包装的对象。 38 | */ 39 | public T get() { 40 | synchronized (this) { 41 | return obj; 42 | } 43 | } 44 | /** 45 | * 设置被包装的对象。 46 | * 如果当前对象与传入对象相同,或当前对象为null且传入对象不为null,则设置对象并返回true。 47 | * @param obj 新的对象。 48 | * @return 如果设置成功,返回true。 49 | */ 50 | public Boolean set(T obj) { 51 | synchronized (this) { 52 | if (this.obj == obj) { 53 | return true; 54 | } 55 | if (this.obj != null) { 56 | return false; 57 | } 58 | this.obj = obj; 59 | return true; 60 | } 61 | } 62 | /** 63 | * 强制设置被包装的对象。 64 | * 无论当前对象是什么,都会设置为传入的对象。 65 | * @param obj 新的对象。 66 | */ 67 | public void setForce(T obj) { 68 | synchronized (this) { 69 | this.obj = obj; 70 | } 71 | } 72 | /** 73 | * 删除被包装的对象。 74 | */ 75 | public void del() { 76 | synchronized (this) { 77 | this.obj = null; 78 | } 79 | } 80 | /** 81 | * 如果被包装的对象与传入对象相同,则删除。 82 | * @param obj 要比较的对象。 83 | */ 84 | public void delIfEquals(T obj) { 85 | synchronized (this) { 86 | if (this.obj == obj) { 87 | this.obj = null; 88 | } 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/all_log.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 13 | 16 | 20 | 21 | -------------------------------------------------------------------------------- /serve-debug/schemas.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | import json # Import json for parsing 3 | from pydantic import BaseModel, field_validator, ValidationError # Import field_validator 4 | from typing import Optional, Any # 导入 Optional 和 Any 用于可选字段和任意类型 5 | 6 | from models import HookData # 保留,可能未来需要 7 | from config import logger 8 | 9 | # 定义 Pydantic 模型用于请求体和响应体 10 | class HookDataBase(BaseModel): 11 | # 更新字段类型以匹配实际传入的数据 12 | TimeStamp: Optional[int] = None # 时间戳通常是整数 13 | Method: str 14 | Params: Optional[Any] = None # Params 可以是任意 JSON 对象/字典 15 | Data: Optional[Any] = None # Data 可以是任意 JSON 对象/字典 16 | 17 | class HookDataCreate(HookDataBase): 18 | pass # 创建时不需要 id, created_at, updated_at 19 | 20 | class HookDataSchema(HookDataBase): 21 | id: int 22 | created_at: datetime 23 | updated_at: datetime 24 | 25 | # Override types from HookDataBase for response serialization 26 | TimeStamp: Optional[int] = None 27 | Params: Optional[Any] = None 28 | Data: Optional[Any] = None 29 | 30 | @field_validator('TimeStamp', mode='before') 31 | @classmethod 32 | def parse_timestamp(cls, value): 33 | if isinstance(value, str): 34 | try: 35 | return int(value) 36 | except (ValueError, TypeError): 37 | logger.warning(f"Could not parse timestamp string: {value}") 38 | return None # Or handle error as needed 39 | return value # Keep original if already int or None 40 | 41 | @field_validator('Params', 'Data', mode='before') 42 | @classmethod 43 | def parse_json_string(cls, value): 44 | if isinstance(value, str): 45 | try: 46 | return json.loads(value) 47 | except json.JSONDecodeError: 48 | logger.warning(f"Could not parse JSON string: {value}") 49 | # Decide how to handle invalid JSON: return original string, None, or raise error 50 | return value # Return original string if parsing fails 51 | return value # Keep original if already dict or None 52 | 53 | class Config: 54 | from_attributes = True # 允许从 ORM 对象创建 Pydantic 模型 (Pydantic V2) 55 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/forest.xml: -------------------------------------------------------------------------------- 1 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/task/AnswerAI/AnswerAIInterface.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.task.AnswerAI; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * AI答题服务接口 7 | * 定义了AI答题服务的基本操作,包括获取答案、设置模型等功能 8 | */ 9 | public interface AnswerAIInterface { 10 | 11 | /** 12 | * 设置模型名称 13 | * 14 | * @param modelName 模型名称 15 | */ 16 | default void setModelName(String modelName) { 17 | // 默认空实现 18 | } 19 | 20 | /** 21 | * 获取模型名称 22 | * 23 | * @return 当前使用的模型名称 24 | */ 25 | default String getModelName() { 26 | // 默认空实现 27 | return ""; 28 | } 29 | 30 | /** 31 | * 获取AI回答结果 32 | * 33 | * @param text 问题内容 34 | * @return AI回答结果,如果获取失败返回空字符串 35 | */ 36 | String getAnswerStr(String text); 37 | 38 | /** 39 | * 获取AI回答结果,指定模型 40 | * 41 | * @param text 问题内容 42 | * @param model 模型名称 43 | * @return AI回答结果,如果获取失败返回空字符串 44 | */ 45 | String getAnswerStr(String text, String model); 46 | 47 | /** 48 | * 获取AI答案 49 | * 50 | * @param title 问题标题 51 | * @param answerList 候选答案列表 52 | * @return 选中的答案索引,如果没有找到合适的答案返回-1 53 | */ 54 | Integer getAnswer(String title, List answerList); 55 | 56 | /** 57 | * 释放资源 58 | * 实现类应在此方法中清理所有使用的资源 59 | */ 60 | default void release() { 61 | // 默认空实现 62 | } 63 | 64 | /** 65 | * 获取单例实例 66 | * 67 | * @return 默认的AI答题服务实现 68 | */ 69 | static AnswerAIInterface getInstance() { 70 | return SingletonHolder.INSTANCE; 71 | } 72 | 73 | /** 74 | * 单例持有者,延迟加载 75 | */ 76 | class SingletonHolder { 77 | private static final AnswerAIInterface INSTANCE = new AnswerAIInterface() { 78 | @Override 79 | public String getAnswerStr(String text) { 80 | return ""; 81 | } 82 | 83 | @Override 84 | public String getAnswerStr(String text, String model) { 85 | return ""; 86 | } 87 | 88 | @Override 89 | public Integer getAnswer(String title, List answerList) { 90 | return -1; 91 | } 92 | }; 93 | } 94 | } -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/model/modelFieldExt/ChoiceModelField.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.model.modelFieldExt; 2 | 3 | import android.content.Context; 4 | import android.view.Gravity; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.Button; 8 | import android.widget.LinearLayout; 9 | 10 | import androidx.core.content.ContextCompat; 11 | 12 | import fansirsqi.xposed.sesame.R; 13 | import fansirsqi.xposed.sesame.model.ModelField; 14 | import fansirsqi.xposed.sesame.ui.ChoiceDialog; 15 | public class ChoiceModelField extends ModelField { 16 | private String[] choiceArray; 17 | 18 | public ChoiceModelField(String code, String name, Integer value) { 19 | super(code, name, value); 20 | } 21 | public ChoiceModelField(String code, String name, Integer value, String[] choiceArray) { 22 | super(code, name, value); 23 | this.choiceArray = choiceArray; 24 | } 25 | 26 | public ChoiceModelField(String code, String name, Integer value,String desc) { 27 | super(code, name, value, desc); 28 | } 29 | public ChoiceModelField(String code, String name, Integer value, String[] choiceArray,String desc) { 30 | super(code, name, value, desc); 31 | this.choiceArray = choiceArray; 32 | } 33 | 34 | @Override 35 | public String getType() { 36 | return "CHOICE"; 37 | } 38 | public String[] getExpandKey() { 39 | return choiceArray; 40 | } 41 | @Override 42 | public View getView(Context context) { 43 | Button btn = new Button(context); 44 | btn.setText(getName()); 45 | btn.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); 46 | btn.setTextColor(ContextCompat.getColor(context, R.color.selection_color)); 47 | btn.setBackground(ContextCompat.getDrawable(context, R.drawable.dialog_list_button)); 48 | btn.setGravity(Gravity.START | Gravity.CENTER_VERTICAL); 49 | btn.setMinHeight(150); 50 | btn.setMaxHeight(180); 51 | btn.setPaddingRelative(40, 0, 40, 0); 52 | btn.setAllCaps(false); 53 | btn.setOnClickListener(v -> ChoiceDialog.show(v.getContext(), ((Button) v).getText(), this)); 54 | return btn; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/farm.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 10 | 13 | 16 | 19 | 22 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/ui/OptionsAdapter.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.ui; 2 | /* 3 | * @Description: 好友统计,列表长按菜单 4 | * @UpdateDate: 2024/10/23 5 | * @UpdateTime: 16:39 6 | */ 7 | import android.annotation.SuppressLint; 8 | import android.content.Context; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.BaseAdapter; 13 | import android.widget.TextView; 14 | import java.util.ArrayList; 15 | /** 16 | * 选项适配器。 17 | * 用于在列表视图中显示选项。 18 | */ 19 | public class OptionsAdapter extends BaseAdapter { 20 | @SuppressLint("StaticFieldLeak") 21 | private static OptionsAdapter adapter; 22 | /** 23 | * 获取单例适配器实例。 24 | * @param c 上下文对象。 25 | * @return 适配器实例。 26 | */ 27 | public static OptionsAdapter get(Context c) { 28 | if (adapter == null) { 29 | adapter = new OptionsAdapter(c); 30 | } 31 | return adapter; 32 | } 33 | private final Context context; 34 | private final ArrayList list; 35 | /** 36 | * 私有构造函数,防止外部直接实例化。 37 | * @param c 上下文对象。 38 | */ 39 | private OptionsAdapter(Context c) { 40 | context = c; 41 | list = new ArrayList<>(); 42 | // 初始化列表项 43 | list.add("查看森林"); 44 | list.add("查看庄园"); 45 | list.add("查看资料"); 46 | list.add("删除"); 47 | } 48 | @Override 49 | public int getCount() { 50 | // 返回列表项的数量 51 | return list == null ? 0 : list.size(); 52 | } 53 | @Override 54 | public Object getItem(int position) { 55 | // 返回指定位置的列表项 56 | return list.get(position); 57 | } 58 | @Override 59 | public long getItemId(int position) { 60 | // 返回列表项的唯一ID,这里简单地使用位置作为ID 61 | return position; 62 | } 63 | @SuppressLint("InflateParams") 64 | @Override 65 | public View getView(int position, View convertView, ViewGroup parent) { 66 | // 复用convertView以提高性能 67 | if (convertView == null) { 68 | // inflate布局 69 | convertView = LayoutInflater.from(context).inflate(android.R.layout.simple_list_item_1, null); 70 | } 71 | // 获取TextView并设置文本 72 | TextView txt = (TextView) convertView; 73 | txt.setText(getItem(position).toString()); 74 | return convertView; 75 | } 76 | } -------------------------------------------------------------------------------- /AppIdMap.txt: -------------------------------------------------------------------------------- 1 | 10000003:充值中心 2 | 10000009:爱心捐赠 3 | 20000001:null 4 | 20000003:账单 5 | 20000014:我的银行卡 6 | 20000019:余额 7 | 20000032:余额宝 8 | 20000033:余额提现 9 | 20000038:关联账户认证/身份认证 10 | 20000042:null 11 | 20000047:null 12 | 20000067:? 13 | 20000076:账单 14 | 20000111:? 15 | 20000120:饿了么外卖 16 | 20000123:个人收钱 17 | 20000134:股票 18 | 20000142:娱乐宝 19 | 20000160:支付宝会员 20 | 20000165:理财 21 | 20000180:借呗 22 | 20000193:生活缴费 23 | 20000199:花呗 24 | 20000218:黄金 25 | 20000241:车险服务 26 | 20000691:我的客服 27 | 20000725:设置 28 | 20000754:我的快递 29 | 20000793:基金 30 | 20000909:args error 31 | 20000936:蚂蚁保险 32 | 20001045:args error 33 | 60000002:蚂蚁森林 34 | 60000010:? 35 | 60000071:天天有料 36 | 60000081:商家服务 37 | 60000123:args error 38 | 60000127:args error 39 | 60000148:财富号 40 | 60000161:支付宝会员周周乐 41 | 63300018:? 42 | 66666673:风险测试/风险类型 43 | 66666674:蚂蚁庄园 44 | 66666698:标签系统/标签和随笔 45 | 66666708:余利宝 46 | 66666721:财富有料 47 | 66666735:基金组合 48 | 66666741:上证指数讨论区 49 | 66666755:好医保 50 | 66666783:爱攒油加油站 51 | 66666819:还贷管家 52 | 66666823:? 53 | 66666825:财富标签页/我的理财标签 54 | 66666828:知识课堂 55 | 66666866:收益曲线 56 | 66666883:网商贷 57 | 66666886:蚂蚁森林合种 58 | 66666897:工资理财 59 | 68686987:网贷 60 | 68687015:办理赔 61 | 68687031:智能理财助理 62 | 68687049:蚂蚁心愿 63 | 68687058:null 64 | 68687109:null 65 | 68687129:行走积分赛 66 | 68687131:养老金 67 | 68687158:支付宝积分猜涨跌 68 | 68687197:null 69 | 68687233:股票工具 70 | 68687242:尊享理财 71 | 68687249:大盘晴雨表 72 | 68687279:null 73 | 68687357:null 74 | 77700124:余额宝 75 | 77700126:互相宝 76 | 77700130:花呗账单 77 | 77700144:扫码点单 78 | 77700152:信用卡还款 79 | 77700173:标注高德地图(在高德地图上标注我的商铺) 80 | 77700174:财富王者 81 | 77700199:财富SHOW 82 | 77700223:笔笔攒 83 | 77700234:模拟炒股 84 | 77700252:市场投资情绪 85 | 77700253:资金管理 86 | 77700257:收钱有奖 87 | 77700279:校园生活 88 | 77700292:收入统计 89 | 77700296:? 90 | 98000012:? 91 | 2013062600000474:new 92 | 2016122804685366:new 93 | 2017081908285290:new 94 | 2018030502317554:new 95 | 2018040402504128:new 96 | 2018051160096372:new 97 | 2018052460226391:new 98 | 2018071160524903:new 99 | 2018091361395351:new 100 | 2018110662035452:new 101 | 2018110762040932:new 102 | 2018112962211021:new 103 | 2018122762703259:new 104 | 2019010462802084:new 105 | 2019012963182381:new 106 | 2019021363229455:new 107 | 2019030863479637:new 108 | 2019031563521845:new 109 | 2019032763709372:new 110 | 2019032863733398:new 111 | 2019040963856084:new 112 | 2019042364288308:new 113 | 2019060465478294:new 114 | 2019060565481471:new 115 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/data/ViewAppInfo.kt: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.data 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Context 5 | import android.content.Intent 6 | import android.content.pm.ApplicationInfo 7 | import android.os.Bundle 8 | import fansirsqi.xposed.sesame.BuildConfig 9 | import fansirsqi.xposed.sesame.R 10 | import fansirsqi.xposed.sesame.util.Log 11 | import androidx.core.net.toUri 12 | 13 | @SuppressLint("StaticFieldLeak") 14 | object ViewAppInfo { 15 | val TAG: String = ViewAppInfo::class.java.simpleName 16 | var context: Context? = null 17 | var appTitle: String = "" 18 | var appVersion: String = "" 19 | var appBuildTarget: String = "" 20 | var appBuildNumber: String = "" 21 | val emojiList = 22 | listOf( 23 | "🍅", "🍓", "🥓", "🍂", "🍚", "🌰", "🟢", "🌴", 24 | "🥗", "🧀", "🥩", "🍍", "🌶️", "🍲", "🍆", "🥕", 25 | "✨", "🍑", "🍘", "🍀", "🥞", "🍈", "🥝", "🧅", 26 | "🌵", "🌾", "🥜", "🍇", "🌭", "🥑", "🥐", "🥖", 27 | "🍊", "🌽", "🍉", "🍖", "🍄", "🥚", "🥙", "🥦", 28 | "🍌", "🍱", "🍏", "🍎", "🌲", "🌿", "🍁", "🍒", 29 | "🥔", "🌯", "🌱", "🍐", "🍞", "🍳", "🍙", "🍋", 30 | "🍗", "🌮", "🍃", "🥘", "🥒", "🧄", "🍠", "🥥", "📦" 31 | ) 32 | 33 | // var runType: RunType? = RunType.DISABLE 34 | @Volatile 35 | internal var runType: RunType? = RunType.DISABLE 36 | @Synchronized set 37 | 38 | @JvmStatic 39 | fun setRunType(type: RunType) { 40 | runType = type 41 | } 42 | 43 | @JvmStatic 44 | fun getRunType() = runType 45 | 46 | /** 47 | * 初始化 ViewAppInfo,设置应用的相关信息,如版本号、构建日期等 48 | * 49 | * @param context 上下文对象,用于获取应用的资源信息 50 | */ 51 | fun init(context: Context) { 52 | if (ViewAppInfo.context == null) { 53 | ViewAppInfo.context = context 54 | appBuildNumber = BuildConfig.VERSION_CODE.toString() 55 | appTitle = context.getString(R.string.app_name) //+ BuildConfig.VERSION_NAME 56 | appBuildTarget = BuildConfig.BUILD_DATE + " " + BuildConfig.BUILD_TIME + " ⏰" 57 | try { 58 | appVersion = "${BuildConfig.VERSION_NAME} " + emojiList.random() 59 | } catch (e: Exception) { 60 | Log.printStackTrace(e) 61 | } 62 | } 63 | } 64 | 65 | 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/entity/ReserveEntity.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.entity; 2 | import java.util.ArrayList; 3 | import java.util.Collections; 4 | import java.util.Iterator; 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.Set; 8 | import fansirsqi.xposed.sesame.util.maps.IdMapManager; 9 | import fansirsqi.xposed.sesame.util.maps.ReserveaMap; 10 | /** 11 | * 表示支付宝保留项的实体类,包含 ID 和名称。 12 | */ 13 | public class ReserveEntity extends MapperEntity { 14 | // 使用 volatile 关键字确保多线程环境下的可见性 15 | private static volatile List list; 16 | /** 17 | * 构造方法,根据给定的 ID 和名称初始化对象。 18 | * @param i 保留项的 ID 19 | * @param n 保留项的名称 20 | */ 21 | public ReserveEntity(String i, String n) { 22 | id = i; 23 | name = n; 24 | } 25 | /** 26 | * 获取包含所有保留项的列表,首次调用时从 ReserveIdMapUtil 初始化。 27 | * 使用双重检查锁定机制实现懒加载以提高性能。 28 | * @return 包含所有 ReserveEntity 对象的不可变列表 29 | */ 30 | public static List getList() { 31 | if (list == null) { 32 | synchronized (ReserveEntity.class) { 33 | if (list == null) { 34 | List tempList = new ArrayList<>(); 35 | Set> idSet = IdMapManager.getInstance(ReserveaMap.class).getMap().entrySet(); 36 | for (Map.Entry entry : idSet) { 37 | tempList.add(new ReserveEntity(entry.getKey(), entry.getValue())); 38 | } 39 | list = Collections.unmodifiableList(tempList); 40 | } 41 | } 42 | } 43 | return list; 44 | } 45 | /** 46 | * 根据给定的 ID 删除相应的 ReserveEntity 对象。 47 | * 首次调用 getList 方法以确保列表已初始化。 48 | * @param id 要删除的保留项 ID 49 | */ 50 | public static void remove(String id) { 51 | getList(); 52 | synchronized (ReserveEntity.class) { 53 | List tempList = new ArrayList<>(list); // 创建可变列表的副本 54 | Iterator iterator = tempList.iterator(); 55 | while (iterator.hasNext()) { 56 | ReserveEntity reserve = iterator.next(); 57 | if (reserve.id.equals(id)) { 58 | iterator.remove(); 59 | } 60 | } 61 | list = Collections.unmodifiableList(tempList); // 确保返回不可变列表 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/entity/CollectEnergyEntity.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.entity; 2 | import lombok.Getter; 3 | import lombok.Setter; 4 | import org.json.JSONObject; 5 | /** 6 | * 表示一个能量收集实体,包含用户信息及操作相关的状态。 7 | */ 8 | @Getter 9 | public class CollectEnergyEntity { 10 | // 用户 ID 11 | private final String userId; 12 | // 用户主页 JSON 对象 13 | @Setter 14 | private JSONObject userHome; 15 | // RPC 请求实体 16 | @Setter 17 | private RpcEntity rpcEntity; 18 | // 收集次数 19 | private Integer collectCount = 0; 20 | // 尝试次数 21 | private Integer tryCount = 0; 22 | // 是否需要翻倍 23 | @Setter 24 | private Boolean needDouble = false; 25 | // 是否需要重试 26 | @Setter 27 | private Boolean needRetry = false; 28 | /** 29 | * 构造方法,仅指定用户 ID。 30 | * @param userId 用户 ID 31 | */ 32 | public CollectEnergyEntity(String userId) { 33 | this.userId = userId; 34 | } 35 | /** 36 | * 构造方法,指定用户 ID 和用户主页信息。 37 | * @param userId 用户 ID 38 | * @param userHome 用户主页 JSON 对象 39 | */ 40 | public CollectEnergyEntity(String userId, JSONObject userHome) { 41 | this.userId = userId; 42 | this.userHome = userHome; 43 | } 44 | /** 45 | * 构造方法,指定用户 ID、用户主页信息及 RPC 请求实体。 46 | * @param userId 用户 ID 47 | * @param userHome 用户主页 JSON 对象 48 | * @param rpcEntity RPC 请求实体 49 | */ 50 | public CollectEnergyEntity(String userId, JSONObject userHome, RpcEntity rpcEntity) { 51 | this.userId = userId; 52 | this.userHome = userHome; 53 | this.rpcEntity = rpcEntity; 54 | } 55 | /** 56 | * 增加尝试次数。 57 | * @return 更新后的尝试次数 58 | */ 59 | public Integer addTryCount() { 60 | this.tryCount += 1; 61 | return tryCount; 62 | } 63 | /** 64 | * 重置尝试次数为 0。 65 | */ 66 | public void resetTryCount() { 67 | this.tryCount = 0; 68 | } 69 | /** 70 | * 设置需要翻倍,并增加收集次数。 71 | */ 72 | public void setNeedDouble() { 73 | this.collectCount += 1; 74 | this.needDouble = true; 75 | } 76 | /** 77 | * 取消需要翻倍状态。 78 | */ 79 | public void unsetNeedDouble() { 80 | this.needDouble = false; 81 | } 82 | /** 83 | * 设置需要重试状态。 84 | */ 85 | public void setNeedRetry() { 86 | this.needRetry = true; 87 | } 88 | /** 89 | * 取消需要重试状态。 90 | */ 91 | public void unsetNeedRetry() { 92 | this.needRetry = false; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/model/modelFieldExt/EmptyModelField.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.model.modelFieldExt; 2 | import android.app.AlertDialog; 3 | import android.content.Context; 4 | import android.view.Gravity; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.Button; 8 | import android.widget.LinearLayout; 9 | import android.widget.Toast; 10 | import androidx.core.content.ContextCompat; 11 | import com.fasterxml.jackson.annotation.JsonIgnore; 12 | import fansirsqi.xposed.sesame.R; 13 | import fansirsqi.xposed.sesame.model.ModelField; 14 | public class EmptyModelField extends ModelField { 15 | private final Runnable clickRunner; 16 | public EmptyModelField(String code, String name) { 17 | super(code, name, null); 18 | this.clickRunner = null; 19 | } 20 | public EmptyModelField(String code, String name, Runnable clickRunner) { 21 | super(code, name, null); 22 | this.clickRunner = clickRunner; 23 | } 24 | @Override 25 | public String getType() { 26 | return "EMPTY"; 27 | } 28 | @Override 29 | public void setObjectValue(Object value) { 30 | } 31 | @JsonIgnore 32 | public View getView(Context context) { 33 | Button btn = new Button(context); 34 | btn.setText(getName()); 35 | btn.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); 36 | btn.setTextColor(ContextCompat.getColor(context, R.color.selection_color)); 37 | btn.setBackground(ContextCompat.getDrawable(context, R.drawable.dialog_list_button)); 38 | btn.setGravity(Gravity.START | Gravity.CENTER_VERTICAL); 39 | btn.setMinHeight(150); 40 | btn.setMaxHeight(180); 41 | btn.setPaddingRelative(40, 0, 40, 0); 42 | btn.setAllCaps(false); 43 | if (clickRunner != null) { 44 | btn.setOnClickListener(v -> new AlertDialog.Builder(context) 45 | .setTitle("警告") 46 | .setMessage("确认执行该操作?") 47 | .setPositiveButton(R.string.ok, (dialog, id) -> clickRunner.run()) 48 | .setNegativeButton(R.string.cancel, (dialog, id) -> dialog.dismiss()) 49 | .create() 50 | .show()); 51 | } else { 52 | btn.setOnClickListener(v -> Toast.makeText(context, "无配置项", Toast.LENGTH_SHORT).show()); 53 | } 54 | return btn; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/util/RandomUtil.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.util; 2 | 3 | import java.util.Random; 4 | 5 | /** 6 | * 随机数工具类,提供生成随机数和随机字符串的方法。 7 | */ 8 | public class RandomUtil { 9 | private static final Random rnd = new Random(); 10 | 11 | /** 12 | * 生成一个随机延迟时间(100到300毫秒之间)。 13 | * 14 | * @return 生成的随机延迟时间(毫秒)。 15 | */ 16 | public static int delay() { 17 | return nextInt(100, 300); 18 | } 19 | 20 | /** 21 | * 生成一个指定范围内的随机整数。 22 | * 23 | * @param min 最小值(包含)。 24 | * @param max 最大值(不包含)。 25 | * @return 生成的随机整数。 26 | */ 27 | public static int nextInt(int min, int max) { 28 | if (min >= max) return min; 29 | return rnd.nextInt(max - min) + min; 30 | } 31 | 32 | /** 33 | * 生成一个随机的长整数。 34 | * 35 | * @return 生成的随机长整数。 36 | */ 37 | public static long nextLong() { 38 | return rnd.nextLong(); 39 | } 40 | 41 | /** 42 | * 生成一个指定范围内的随机长整数。 43 | * 44 | * @param min 最小值(包含)。 45 | * @param max 最大值(不包含)。 46 | * @return 生成的随机长整数。 47 | */ 48 | public static long nextLong(long min, long max) { 49 | if (min >= max) return min; 50 | long o = max - min; 51 | return (rnd.nextLong() % o) + min; 52 | } 53 | 54 | /** 55 | * 生成一个随机的双精度浮点数。 56 | * 57 | * @return 生成的随机双精度浮点数。 58 | */ 59 | public static double nextDouble() { 60 | return rnd.nextDouble(); 61 | } 62 | 63 | /** 64 | * 生成一个指定长度的随机数字字符串。 65 | * 66 | * @param len 随机字符串的长度。 67 | * @return 生成的随机数字字符串。 68 | */ 69 | public static String getRandomInt(int len) { 70 | StringBuilder rs = new StringBuilder(); 71 | for (int i = 0; i < len; i++) { 72 | rs.append(rnd.nextInt(10)); 73 | } 74 | return rs.toString(); 75 | } 76 | 77 | /** 78 | * 生成一个指定长度的随机字符串,包含小写字母和数字。 79 | * 80 | * @param length 随机字符串的长度。 81 | * @return 生成的随机字符串。 82 | */ 83 | public static String getRandomString(int length) { 84 | String chars = "abcdefghijklmnopqrstuvwxyz0123456789"; 85 | StringBuilder sb = new StringBuilder(); 86 | for (int i = 0; i < length; i++) { 87 | int number = nextInt(0, chars.length()); 88 | sb.append(chars.charAt(number)); 89 | } 90 | return sb.toString(); 91 | } 92 | 93 | public static String getRandomTag() { 94 | return "_" + System.currentTimeMillis() + "_" + RandomUtil.getRandomString(8); 95 | } 96 | 97 | 98 | } -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/hook/server/handlers/BaseHandler.kt: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.hook.server.handlers 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper 4 | import fi.iki.elonen.NanoHTTPD 5 | import fi.iki.elonen.NanoHTTPD.Response 6 | import fi.iki.elonen.NanoHTTPD.IHTTPSession 7 | import fi.iki.elonen.NanoHTTPD.Method 8 | 9 | abstract class BaseHandler(private val secretToken: String) : HttpHandler { 10 | 11 | protected val mapper = ObjectMapper() 12 | 13 | final override fun handle(session: IHTTPSession, body: String?): Response { 14 | if (!verifyToken(session)) { 15 | return unauthorized() 16 | } 17 | 18 | val method = session.method 19 | return when { 20 | method === Method.GET -> onGet(session) 21 | method === Method.POST -> onPost(session, body) 22 | else -> methodNotAllowed() 23 | } 24 | } 25 | 26 | private fun verifyToken(session: IHTTPSession): Boolean { 27 | val authHeader = session.headers["authorization"] ?: return false 28 | if (!authHeader.startsWith("Bearer ", ignoreCase = true)) { 29 | return false 30 | } 31 | val token = authHeader.substring(7).trim() 32 | return token == secretToken 33 | } 34 | 35 | open fun onGet(session: IHTTPSession): Response { 36 | return notFound() 37 | } 38 | 39 | open fun onPost(session: IHTTPSession, body: String?): Response { 40 | return notFound() 41 | } 42 | 43 | protected fun json(status: Response.Status, data: Map): Response { 44 | return NanoHTTPD.newFixedLengthResponse(status, MIME_JSON, mapper.writeValueAsString(data)) 45 | } 46 | 47 | protected fun ok(data: Map): Response { 48 | return json(Response.Status.OK, data) 49 | } 50 | 51 | protected fun badRequest(message: String): Response { 52 | return json(Response.Status.BAD_REQUEST, mapOf("status" to "error", "message" to message)) 53 | } 54 | 55 | protected fun unauthorized(): Response { 56 | return json(Response.Status.UNAUTHORIZED, mapOf("status" to "unauthorized")) 57 | } 58 | 59 | protected fun methodNotAllowed(): Response { 60 | return json(Response.Status.METHOD_NOT_ALLOWED, mapOf("status" to "method_not_allowed")) 61 | } 62 | 63 | protected fun notFound(): Response { 64 | return json(Response.Status.NOT_FOUND, mapOf("status" to "not_found")) 65 | } 66 | 67 | companion object { 68 | const val MIME_JSON = "application/json" 69 | } 70 | } -------------------------------------------------------------------------------- /app/src/main/assets/web/Sesame-TK-logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/task/antStall/ReadingDada.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.task.antStall; 2 | 3 | import org.json.JSONArray; 4 | import org.json.JSONObject; 5 | 6 | import fansirsqi.xposed.sesame.model.ModelGroup; 7 | import fansirsqi.xposed.sesame.task.AnswerAI.AnswerAI; 8 | import fansirsqi.xposed.sesame.util.JsonUtil; 9 | import fansirsqi.xposed.sesame.util.Log; 10 | import fansirsqi.xposed.sesame.util.StringUtil; 11 | 12 | /** 13 | * @author Constanline 14 | * @since 2023/08/22 15 | */ 16 | public class ReadingDada { 17 | private static final String TAG = ReadingDada.class.getSimpleName(); 18 | 19 | public ModelGroup getGroup() { 20 | return ModelGroup.STALL; 21 | } 22 | 23 | public static boolean answerQuestion(JSONObject bizInfo) { 24 | try { 25 | String taskJumpUrl = bizInfo.optString("taskJumpUrl"); 26 | if (StringUtil.isEmpty(taskJumpUrl)) { 27 | taskJumpUrl = bizInfo.getString("targetUrl"); 28 | } 29 | String activityId = taskJumpUrl.split("activityId%3D")[1].split("%26")[0]; 30 | String outBizId; 31 | if (taskJumpUrl.contains("outBizId%3D")) { 32 | outBizId = taskJumpUrl.split("outBizId%3D")[1].split("%26")[0]; 33 | } else { 34 | outBizId = ""; 35 | } 36 | String s = ReadingDadaRpcCall.getQuestion(activityId); 37 | JSONObject jo = new JSONObject(s); 38 | if ("200".equals(jo.getString("resultCode"))) { 39 | JSONArray jsonArray = jo.getJSONArray("options"); 40 | String question = jo.getString("title"); 41 | String answer = AnswerAI.getAnswer(question, JsonUtil.jsonArrayToList(jsonArray), "other"); 42 | if (answer == null || answer.isEmpty()) { 43 | answer = jsonArray.getString(0); 44 | } 45 | s = ReadingDadaRpcCall.submitAnswer(activityId, outBizId, jo.getString("questionId"), answer); 46 | jo = new JSONObject(s); 47 | if ("200".equals(jo.getString("resultCode"))) { 48 | Log.record(TAG, "答题完成"); 49 | return true; 50 | } else { 51 | Log.record(TAG, "答题失败"); 52 | } 53 | } else { 54 | Log.record(TAG, "获取问题失败"); 55 | } 56 | } catch (Throwable e) { 57 | Log.runtime(TAG, "answerQuestion err:"); 58 | Log.printStackTrace(TAG, e); 59 | } 60 | return false; 61 | } 62 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\tools\adt-bundle-windows-x86_64-20131030\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | 20 | -keep class de.robv.android.xposed.** { *; } 21 | 22 | # Keep Logback classes 23 | -keep class ch.qos.logback.** { *; } 24 | -keep class org.slf4j.** { *; } 25 | -dontwarn ch.qos.logback.** 26 | -dontwarn org.slf4j.** 27 | 28 | # Keep your application classes 29 | -keep class fansirsqi.xposed.sesame.** { *; } 30 | -keepattributes *Annotation* 31 | -keepattributes Signature 32 | -keepattributes Exceptions 33 | 34 | # Keep Jackson classes and annotations 35 | -keep class com.fasterxml.jackson.** { *; } 36 | -keepattributes Signature 37 | -keepattributes RuntimeVisibleAnnotations 38 | -keepattributes RuntimeVisibleParameterAnnotations 39 | -keepattributes RuntimeVisibleTypeAnnotations 40 | -keepattributes AnnotationDefault 41 | 42 | # Keep Java Beans classes 43 | -keep class java.beans.** { *; } 44 | -dontwarn java.beans.** 45 | 46 | # Keep Jackson Java7 Support 47 | -keep class com.fasterxml.jackson.databind.ext.Java7SupportImpl { *; } 48 | -dontwarn com.fasterxml.jackson.databind.ext.Java7SupportImpl 49 | 50 | # Keep ModelField classes and their members 51 | -keep class fansirsqi.xposed.sesame.model.ModelField { *; } 52 | -keep class fansirsqi.xposed.sesame.model.modelFieldExt.** { *; } 53 | -keepclassmembers class * extends fansirsqi.xposed.sesame.model.ModelField { 54 | ; 55 | ; 56 | } 57 | 58 | # Additional serialization rules 59 | -keepclassmembers class * { 60 | @com.fasterxml.jackson.annotation.* *; 61 | } 62 | -keepnames class * implements java.io.Serializable 63 | -keepclassmembers class * implements java.io.Serializable { 64 | static final long serialVersionUID; 65 | private static final java.io.ObjectStreamField[] serialPersistentFields; 66 | !static !transient ; 67 | private void writeObject(java.io.ObjectOutputStream); 68 | private void readObject(java.io.ObjectInputStream); 69 | java.lang.Object writeReplace(); 70 | java.lang.Object readResolve(); 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/hook/RequestManager.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.hook; 2 | import fansirsqi.xposed.sesame.entity.RpcEntity; 3 | /** 4 | * @author Byseven 5 | * @date 2025/1/6 6 | * @apiNote 7 | */ 8 | public class RequestManager { 9 | 10 | private static String checkResult(String result, String method) { 11 | if (result == null || result.trim().isEmpty()) { 12 | throw new IllegalStateException("Empty response from RPC method: " + method); 13 | } 14 | return result; 15 | } 16 | 17 | public static String requestString(RpcEntity rpcEntity) { 18 | String result = ApplicationHook.rpcBridge.requestString(rpcEntity, 3, -1); 19 | return checkResult(result, rpcEntity.getMethodName()); 20 | } 21 | public static String requestString(RpcEntity rpcEntity, int tryCount, int retryInterval) { 22 | String result = ApplicationHook.rpcBridge.requestString(rpcEntity, tryCount, retryInterval); 23 | return checkResult(result, rpcEntity.getMethodName()); 24 | } 25 | public static String requestString(String method, String data) { 26 | String result = ApplicationHook.rpcBridge.requestString(method, data); 27 | return checkResult(result, method); 28 | } 29 | public static String requestString(String method, String data, String relation) { 30 | String result = ApplicationHook.rpcBridge.requestString(method, data, relation); 31 | return checkResult(result, method); 32 | } 33 | public static String requestString(String method, String data, String appName, String methodName, String facadeName) { 34 | String result = ApplicationHook.rpcBridge.requestString(method, data, appName, methodName, facadeName); 35 | return checkResult(result, method); 36 | } 37 | public static String requestString(String method, String data, int tryCount, int retryInterval) { 38 | String result = ApplicationHook.rpcBridge.requestString(method, data, tryCount, retryInterval); 39 | return checkResult(result, method); 40 | } 41 | public static String requestString(String method, String data, String relation, int tryCount, int retryInterval) { 42 | String result = ApplicationHook.rpcBridge.requestString(method, data, relation, tryCount, retryInterval); 43 | return checkResult(result, method); 44 | } 45 | 46 | public static void requestObject(RpcEntity rpcEntity, int tryCount, int retryInterval) { 47 | ApplicationHook.rpcBridge.requestObject(rpcEntity, tryCount, retryInterval); 48 | } 49 | 50 | public static RpcEntity requestObject(String method, String data, int tryCount, int retryInterval) { 51 | return ApplicationHook.rpcBridge.requestObject(method, data, tryCount, retryInterval); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/hook/Toast.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.hook; 2 | import android.content.Context; 3 | import android.os.Handler; 4 | import android.os.Looper; 5 | import fansirsqi.xposed.sesame.model.BaseModel; 6 | import fansirsqi.xposed.sesame.util.Log; 7 | public class Toast { 8 | private static final String TAG = Toast.class.getSimpleName(); 9 | /** 10 | * 显示 Toast 消息 11 | * 12 | * @param message 要显示的消息 13 | */ 14 | public static void show(CharSequence message) { 15 | show(message, false); 16 | } 17 | /** 18 | * 显示 Toast 消息 19 | * 20 | * @param message 要显示的消息 21 | * @param force 是否强制显示 22 | */ 23 | public static void show(CharSequence message, boolean force) { 24 | Context context = ApplicationHook.getAppContext(); 25 | if (context == null) { 26 | Log.runtime(TAG, "Context is null, cannot show toast"); 27 | return; 28 | } 29 | boolean shouldShow = force || (BaseModel.getShowToast() != null && BaseModel.getShowToast().getValue()); 30 | if (shouldShow) { 31 | displayToast(context.getApplicationContext(), message); 32 | } 33 | } 34 | /** 35 | * 显示 Toast 消息(确保在主线程中调用) 36 | * 37 | * @param context 上下文 38 | * @param message 要显示的消息 39 | */ 40 | private static void displayToast(Context context, CharSequence message) { 41 | try { 42 | Handler mainHandler = new Handler(Looper.getMainLooper()); 43 | if (Looper.myLooper() == Looper.getMainLooper()) { 44 | // 如果当前线程是主线程,直接显示 45 | createAndShowToast(context, message); 46 | } else { 47 | // 在非主线程,通过 Handler 切换到主线程 48 | mainHandler.post(() -> createAndShowToast(context, message)); 49 | } 50 | } catch (Throwable t) { 51 | Log.runtime(TAG, "displayToast err:"); 52 | Log.printStackTrace(TAG, t); 53 | } 54 | } 55 | /** 56 | * 创建并显示 Toast 57 | * 58 | * @param context 上下文 59 | * @param message 要显示的消息 60 | */ 61 | private static void createAndShowToast(Context context, CharSequence message) { 62 | try { 63 | android.widget.Toast toast = android.widget.Toast.makeText(context, message, android.widget.Toast.LENGTH_SHORT); 64 | toast.setGravity( 65 | toast.getGravity(), 66 | toast.getXOffset(), 67 | BaseModel.getToastOffsetY() != null ? BaseModel.getToastOffsetY().getValue() : 0 68 | ); 69 | toast.show(); 70 | } catch (Throwable t) { 71 | Log.runtime(TAG, "createAndShowToast err:"); 72 | Log.printStackTrace(TAG, t); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 23 | 26 | 29 | 32 | 35 | 36 | 39 | 40 | 41 | 42 | 43 | 44 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/entity/AreaCode.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.entity; 2 | import org.json.JSONArray; 3 | import org.json.JSONException; 4 | import org.json.JSONObject; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import fansirsqi.xposed.sesame.util.Files; 8 | import fansirsqi.xposed.sesame.util.Log; 9 | /** 10 | * 区域代码类,继承自IdAndName。 11 | * 该类用于管理城市代码和城市名称。 12 | */ 13 | public class AreaCode extends MapperEntity { 14 | private static final String TAG = AreaCode.class.getSimpleName(); 15 | private static List list; 16 | /** 17 | * 构造函数,初始化区域代码对象。 18 | * 19 | * @param i 区域代码 20 | * @param n 区域名称 21 | */ 22 | public AreaCode(String i, String n) { 23 | id = i; 24 | name = n; 25 | } 26 | /** 27 | * 获取区域代码列表。 28 | * 如果列表尚未初始化,则从文件中读取城市代码。 29 | * 如果读取失败,则使用默认城市代码。 30 | * 31 | * @return 区域代码列表 32 | */ 33 | public static List getList() throws JSONException { 34 | if (list == null) { 35 | String cityCode = Files.readFromFile(Files.getCityCodeFile()); 36 | JSONArray ja = parseCityCode(cityCode); 37 | list = new ArrayList<>(); 38 | for (int i = 0; i < ja.length(); i++) { 39 | try { 40 | JSONObject jo = ja.getJSONObject(i); 41 | list.add(new AreaCode(jo.getString("cityCode"), jo.getString("cityName"))); 42 | } catch (JSONException e) { 43 | Log.printStackTrace(TAG, e); 44 | } 45 | } 46 | } 47 | return list; 48 | } 49 | /** 50 | * 解析城市代码字符串为JSONArray。 51 | * 如果解析失败,则返回默认的城市代码JSONArray。 52 | * 53 | * @param cityCode 城市代码字符串 54 | * @return 解析后的JSONArray 55 | */ 56 | private static JSONArray parseCityCode(String cityCode) throws JSONException { 57 | try { 58 | return new JSONArray(cityCode); 59 | } catch (JSONException e) { 60 | // 解析失败,使用默认城市代码 61 | Log.runtime(TAG, "parseCityCode failed with error message: " + e.getMessage()+"\n Now use default cities."); 62 | JSONArray defaultCities = new JSONArray(); 63 | defaultCities.put(new JSONObject().put("cityCode", "350100").put("cityName", "福州市")); 64 | defaultCities.put(new JSONObject().put("cityCode", "440100").put("cityName", "广州市")); 65 | defaultCities.put(new JSONObject().put("cityCode", "330100").put("cityName", "杭州市")); 66 | defaultCities.put(new JSONObject().put("cityCode", "370100").put("cityName", "济南市")); 67 | defaultCities.put(new JSONObject().put("cityCode", "320100").put("cityName", "南京市")); 68 | defaultCities.put(new JSONObject().put("cityCode", "430100").put("cityName", "长沙市")); 69 | return defaultCities; 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/hook/rpc/intervallimit/RpcIntervalLimit.kt: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.hook.rpc.intervallimit 2 | 3 | import fansirsqi.xposed.sesame.util.GlobalThreadPools 4 | import fansirsqi.xposed.sesame.util.Log 5 | import java.util.concurrent.ConcurrentHashMap 6 | 7 | object RpcIntervalLimit { 8 | private const val TAG = "RpcIntervalLimit" 9 | private const val DEFAULT_INTERVAL = 500 10 | private val DEFAULT_INTERVAL_LIMIT = DefaultIntervalLimit(DEFAULT_INTERVAL) 11 | private val intervalLimitMap = ConcurrentHashMap() 12 | 13 | /** 14 | * 为指定方法添加间隔限制。 15 | * 16 | * @param method 方法名称 17 | * @param interval 间隔时间(毫秒) 18 | */ 19 | fun addIntervalLimit(method: String, interval: Int) { 20 | addIntervalLimit(method, DefaultIntervalLimit(interval)) 21 | } 22 | 23 | /** 24 | * 为指定方法添加自定义间隔限制对象。 25 | * 26 | * @param method 方法名称 27 | * @param intervalLimit 自定义的间隔限制对象 28 | */ 29 | fun addIntervalLimit(method: String, intervalLimit: IntervalLimit) { 30 | synchronized(intervalLimitMap) { 31 | if (intervalLimitMap.containsKey(method)) { 32 | Log.runtime(TAG, "方法:$method 间隔限制已存在") 33 | throw IllegalArgumentException("方法:$method 间隔限制已存在") 34 | } 35 | intervalLimitMap[method] = intervalLimit 36 | } 37 | } 38 | 39 | /** 40 | * 更新指定方法的间隔限制。 41 | * 42 | * @param method 方法名称 43 | * @param interval 新的间隔时间(毫秒) 44 | */ 45 | fun updateIntervalLimit(method: String, interval: Int) { 46 | updateIntervalLimit(method, DefaultIntervalLimit(interval)) 47 | } 48 | 49 | /** 50 | * 更新指定方法的间隔限制对象。 51 | * 52 | * @param method 方法名称 53 | * @param intervalLimit 新的自定义间隔限制对象 54 | */ 55 | fun updateIntervalLimit(method: String, intervalLimit: IntervalLimit) { 56 | intervalLimitMap[method] = intervalLimit 57 | } 58 | 59 | /** 60 | * 进入指定方法的间隔限制,确保调用间隔时间不小于设定值。 61 | * 62 | * @param method 方法名称 63 | */ 64 | fun enterIntervalLimit(method: String) { 65 | val intervalLimit = intervalLimitMap.getOrDefault(method, DEFAULT_INTERVAL_LIMIT) 66 | val lock = requireNotNull(intervalLimit) { "间隔限制对象不能为空" } 67 | 68 | synchronized(lock) { 69 | // 解决 Int? 的问题,使用默认值兜底 70 | val interval = intervalLimit.interval ?: DEFAULT_INTERVAL 71 | val now = System.currentTimeMillis() 72 | val lastTime = intervalLimit.time 73 | val sleep = interval - (now - lastTime) 74 | 75 | if (sleep > 0) { 76 | GlobalThreadPools.sleep(sleep) 77 | } 78 | 79 | intervalLimit.time = now 80 | } 81 | } 82 | 83 | /** 84 | * 清除所有方法的间隔限制。 85 | */ 86 | fun clearIntervalLimit() { 87 | intervalLimitMap.clear() 88 | } 89 | } -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/util/ResChecker.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.util; 2 | 3 | import org.json.JSONException; 4 | import org.json.JSONObject; 5 | 6 | import java.util.regex.Pattern; 7 | 8 | public class ResChecker { 9 | private static final String TAG = ResChecker.class.getSimpleName(); 10 | 11 | private static boolean core(String TAG, JSONObject jo) { 12 | try { 13 | Log.runtime(TAG, "Checking JSON success: " + jo); 14 | // 检查 success 或 isSuccess 字段为 true 15 | if (jo.optBoolean("success") || jo.optBoolean("isSuccess")) { 16 | return true; 17 | } 18 | 19 | // 检查 resultCode 20 | Object resCode = jo.opt("resultCode"); 21 | if (resCode != null) { 22 | if (resCode instanceof Integer && (Integer) resCode == 200) { 23 | return true; 24 | } else if (resCode instanceof String && 25 | Pattern.matches("(?i)SUCCESS|100", (String) resCode)) { 26 | return true; 27 | } 28 | } 29 | 30 | // 检查 memo 字段 31 | if ("SUCCESS".equalsIgnoreCase(jo.optString("memo", ""))) { 32 | return true; 33 | } 34 | 35 | Log.error(TAG, "Check failed: " + jo); 36 | return false; 37 | 38 | } catch (Throwable t) { 39 | Log.printStackTrace(TAG, "Error checking JSON success:", t); 40 | return false; 41 | } 42 | } 43 | 44 | /** 45 | * 检查JSON对象是否表示成功 46 | *

47 | * 成功条件包括:
48 | * - success == true
49 | * - isSuccess == true
50 | * - resultCode == 200 或 "SUCCESS" 或 "100"
51 | * - memo == "SUCCESS"
52 | * 53 | * @param jo JSON对象 54 | * @return true 如果成功 55 | */ 56 | private static boolean checkRes(JSONObject jo) { 57 | return core(TAG, jo); 58 | } 59 | 60 | /** 61 | * 检查JSON对象是否表示成功 62 | *

63 | * 成功条件包括:
64 | * - success == true
65 | * - isSuccess == true
66 | * - resultCode == 200 或 "SUCCESS" 或 "100"
67 | * - memo == "SUCCESS"
68 | * 69 | * @param jo JSON对象 70 | * @return true 如果成功 71 | */ 72 | public static boolean checkRes(String TAG, JSONObject jo) { 73 | return core(TAG, jo); 74 | } 75 | 76 | 77 | 78 | /** 79 | * 检查JSON对象是否表示成功 80 | *

81 | * 成功条件包括:
82 | * - success == true
83 | * - isSuccess == true
84 | * - resultCode == 200 或 "SUCCESS" 或 "100"
85 | * - memo == "SUCCESS"
86 | * 87 | * @param jsonStr JSON对象的字符串表示 88 | * @return true 如果成功 89 | */ 90 | public static boolean checkRes(String TAG, String jsonStr) throws JSONException { 91 | JSONObject jo = new JSONObject(jsonStr); 92 | return checkRes(TAG, jo); 93 | } 94 | 95 | 96 | } 97 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/title_logo.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/task/antCooperate/AntCooperateRpcCall.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.task.antCooperate; 2 | import org.json.JSONArray; 3 | import org.json.JSONException; 4 | import org.json.JSONObject; 5 | 6 | import fansirsqi.xposed.sesame.hook.RequestManager; 7 | public class AntCooperateRpcCall { 8 | private static final String VERSION = "20230501"; 9 | public static String queryUserCooperatePlantList() { 10 | return RequestManager.requestString("alipay.antmember.forest.h5.queryUserCooperatePlantList", "[{}]"); 11 | } 12 | public static String queryCooperatePlant(String coopId) { 13 | String args1 = "[{\"cooperationId\":\"" + coopId + "\"}]"; 14 | return RequestManager.requestString("alipay.antmember.forest.h5.queryCooperatePlant", args1); 15 | } 16 | public static String cooperateWater(String uid, String coopId, int count) { 17 | return RequestManager.requestString("alipay.antmember.forest.h5.cooperateWater", 18 | "[{\"bizNo\":\"" + uid + "_" + coopId + "_" + System.currentTimeMillis() + "\",\"cooperationId\":\"" 19 | + coopId + "\",\"energyCount\":" + count + ",\"source\":\"\",\"version\":\"" + VERSION 20 | + "\"}]"); 21 | } 22 | /** 23 | * 获取合种浇水量排行 24 | * @param bizType 参数:D/A,“D”为查询当天,“A”为查询所有 25 | * @param coopId 合种ID 26 | * @return 27 | */ 28 | public static String queryCooperateRank(String bizType, String coopId) { 29 | return RequestManager.requestString("alipay.antmember.forest.h5.queryCooperateRank", 30 | "[{\"bizType\":\""+ bizType + "\",\"cooperationId\":\"" + coopId + "\",\"source\":\"chInfo_ch_url-https://render.alipay.com/p/yuyan/180020010001247580/home.html\"}]"); 31 | } 32 | 33 | /** 34 | * 召唤队友浇水 35 | * @param userId 用户ID 36 | * @param cooperationId 合种ID 37 | * @return requestString 38 | */ 39 | public static String sendCooperateBeckon(String userId, String cooperationId) throws JSONException { 40 | JSONObject jo = new JSONObject(); 41 | jo.put("bizImage","https://gw.alipayobjects.com/zos/rmsportal/gzYPfxdAxLrkzFUeVkiY.jpg"); 42 | jo.put("link","lipays://platformapi/startapp?appId=66666886&url=%2Fwww%2Fcooperation%2Findex.htm%3FcooperationId%3D"+cooperationId+"%26sourceName%3Dcard"); 43 | jo.put("midTitle","快来给我们的树苗浇水,让它快快长大。"); 44 | jo.put("noticeLink","alipays://platformapi/startapp?appId=60000002&url=https%3A%2F%2Frender.alipay.com%2Fp%2Fc%2F17ussbd8vtfg%2Fmessage.html%3FsourceName%3Dcard&showOptionMenu=NO&transparentTitle=NO"); 45 | jo.put("topTitle","树苗需要你的呵护"); 46 | jo.put("source","chInfo_ch_url-https://render.alipay.com/p/yuyan/180020010001247580/home.html"); 47 | jo.put("cooperationId",cooperationId); 48 | jo.put("userId",userId); 49 | return RequestManager.requestString("alipay.antmember.forest.h5.sendCooperateBeckon", 50 | new JSONArray().put(jo).toString()); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/task/antForest/WhackMole.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.task.antForest; 2 | 3 | import org.json.JSONArray; 4 | import org.json.JSONObject; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | import fansirsqi.xposed.sesame.util.GlobalThreadPools; 10 | import fansirsqi.xposed.sesame.util.Log; 11 | import fansirsqi.xposed.sesame.util.ResChecker; 12 | 13 | /** 14 | * @author Byseven 15 | * @date 2025/3/7 16 | * @apiNote 17 | */ 18 | public class WhackMole { 19 | private static final String TAG = WhackMole.class.getSimpleName(); 20 | 21 | /** 22 | * 6秒拼手速 打地鼠 23 | */ 24 | public static void startWhackMole() { 25 | try { 26 | long startTime = System.currentTimeMillis(); 27 | JSONObject response = new JSONObject(AntForestRpcCall.startWhackMole("senlinguangchangdadishu")); 28 | if (response.optBoolean("success")) { 29 | JSONArray moleInfoArray = response.optJSONArray("moleInfo"); 30 | if (moleInfoArray != null) { 31 | List moleIdList = new ArrayList<>(); 32 | for (int i = 0; i < moleInfoArray.length(); i++) { 33 | JSONObject mole = moleInfoArray.getJSONObject(i); 34 | long moleId = mole.getLong("id"); 35 | moleIdList.add(String.valueOf(moleId)); // 收集每个地鼠的 ID 36 | } 37 | if (!moleIdList.isEmpty()) { 38 | String token = response.getString("token"); // 获取令牌 39 | long elapsedTime = System.currentTimeMillis() - startTime; // 计算已耗时间 40 | GlobalThreadPools.sleep(Math.max(0, 6000 - elapsedTime)); // 睡眠至6秒 41 | response = new JSONObject(AntForestRpcCall.settlementWhackMole(token, moleIdList, "senlinguangchangdadishu")); 42 | if (ResChecker.checkRes(TAG, response)) { 43 | int totalEnergy = response.getInt("totalEnergy"); 44 | Log.forest("森林能量⚡️[获得:6秒拼手速能量 " + totalEnergy + "g]"); 45 | } 46 | } 47 | } 48 | } else { 49 | Log.runtime(TAG, response.getJSONObject("data").toString()); 50 | } 51 | } catch (Throwable t) { 52 | Log.runtime(TAG, "whackMole err"); 53 | Log.printStackTrace(TAG, t); 54 | } 55 | } 56 | 57 | /** 58 | * 关闭6秒拼手速 59 | */ 60 | public static Boolean closeWhackMole() { 61 | try { 62 | JSONObject jo = new JSONObject(AntForestRpcCall.closeWhackMole("senlinguangchangdadishu")); 63 | if (jo.optBoolean("success")) { 64 | return true; 65 | } else { 66 | Log.runtime(TAG, jo.getString("resultDesc")); 67 | } 68 | } catch (Throwable t) { 69 | Log.printStackTrace(t); 70 | } 71 | return false; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/model/modelFieldExt/SelectOneModelField.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.model.modelFieldExt; 2 | import android.content.Context; 3 | import android.view.Gravity; 4 | import android.view.View; 5 | import android.view.ViewGroup; 6 | import android.widget.Button; 7 | import android.widget.LinearLayout; 8 | import androidx.core.content.ContextCompat; 9 | import fansirsqi.xposed.sesame.R; 10 | import fansirsqi.xposed.sesame.model.ModelField; 11 | import fansirsqi.xposed.sesame.model.SelectModelFieldFunc; 12 | import fansirsqi.xposed.sesame.entity.MapperEntity; 13 | import fansirsqi.xposed.sesame.ui.widget.ListDialog; 14 | import java.util.List; 15 | import java.util.Objects; 16 | public class SelectOneModelField extends ModelField implements SelectModelFieldFunc { 17 | private SelectListFunc selectListFunc; 18 | private List expandValue; 19 | public SelectOneModelField(String code, String name, String value, List expandValue) { 20 | super(code, name, value); 21 | this.expandValue = expandValue; 22 | } 23 | public SelectOneModelField(String code, String name, String value, SelectListFunc selectListFunc) { 24 | super(code, name, value); 25 | this.selectListFunc = selectListFunc; 26 | } 27 | @Override 28 | public String getType() { 29 | return "SELECT_ONE"; 30 | } 31 | public List getExpandValue() { 32 | return selectListFunc == null ? expandValue : selectListFunc.getList(); 33 | } 34 | @Override 35 | public View getView(Context context) { 36 | Button btn = new Button(context); 37 | btn.setText(getName()); 38 | btn.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); 39 | btn.setTextColor(ContextCompat.getColor(context, R.color.selection_color)); 40 | btn.setBackground(ContextCompat.getDrawable(context, R.drawable.dialog_list_button)); 41 | btn.setGravity(Gravity.START | Gravity.CENTER_VERTICAL); 42 | btn.setMinHeight(150); 43 | btn.setPaddingRelative(40, 0, 40, 0); 44 | btn.setAllCaps(false); 45 | btn.setOnClickListener(v -> ListDialog.show(v.getContext(), ((Button) v).getText(), this, ListDialog.ListType.RADIO)); 46 | return btn; 47 | } 48 | @Override 49 | public void clear() { 50 | value = defaultValue; 51 | } 52 | @Override 53 | public Integer get(String id) { 54 | return 0; 55 | } 56 | @Override 57 | public void add(String id, Integer count) { 58 | value = id; 59 | } 60 | @Override 61 | public void remove(String id) { 62 | if (Objects.equals(value, id)) { 63 | value = defaultValue; 64 | } 65 | } 66 | @Override 67 | public Boolean contains(String id) { 68 | return Objects.equals(value, id); 69 | } 70 | public interface SelectListFunc { 71 | List getList(); 72 | } 73 | } -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/util/Logback.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.util; 2 | 3 | import org.slf4j.LoggerFactory; 4 | 5 | import java.io.File; 6 | import java.util.List; 7 | 8 | import ch.qos.logback.classic.LoggerContext; 9 | import ch.qos.logback.classic.android.LogcatAppender; 10 | import ch.qos.logback.classic.encoder.PatternLayoutEncoder; 11 | import ch.qos.logback.classic.spi.ILoggingEvent; 12 | import ch.qos.logback.core.rolling.RollingFileAppender; 13 | import ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy; 14 | import ch.qos.logback.core.util.FileSize; 15 | public class Logback { 16 | private static String LOG_DIR; 17 | 18 | public static List logNames = List.of( 19 | "runtime", "system", "record", "debug", "forest", 20 | "farm", "other", "error", "capture"); 21 | 22 | public static void configureLogbackDirectly() { 23 | // 延迟初始化 LOG_DIR 24 | if (LOG_DIR == null) { 25 | assert Files.LOG_DIR != null; 26 | LOG_DIR = Files.LOG_DIR.getPath() + File.separator; 27 | } 28 | 29 | LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); 30 | lc.stop(); 31 | for (String logName : logNames) { 32 | setupAppender(lc, logName); 33 | } 34 | 35 | PatternLayoutEncoder ple = new PatternLayoutEncoder(); 36 | ple.setContext(lc); 37 | ple.setPattern("[%thread] %logger{80} %msg%n"); 38 | ple.start(); 39 | 40 | LogcatAppender la = new LogcatAppender(); 41 | la.setContext(lc); 42 | la.setEncoder(ple); 43 | la.start(); 44 | 45 | ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("ROOT"); 46 | root.addAppender(la); 47 | } 48 | 49 | static void setupAppender(LoggerContext loggerContext, String logName) { 50 | RollingFileAppender rfa = new RollingFileAppender<>(); 51 | rfa.setContext(loggerContext); 52 | rfa.setName(logName); 53 | rfa.setFile(LOG_DIR + logName + ".log"); 54 | 55 | SizeAndTimeBasedRollingPolicy satbrp = new SizeAndTimeBasedRollingPolicy<>(); 56 | satbrp.setContext(loggerContext); 57 | satbrp.setFileNamePattern(LOG_DIR + "bak/" + logName + "-%d{yyyy-MM-dd}.%i.log"); 58 | satbrp.setMaxFileSize(FileSize.valueOf("50MB")); 59 | satbrp.setTotalSizeCap(FileSize.valueOf("100MB")); 60 | satbrp.setMaxHistory(7); 61 | satbrp.setCleanHistoryOnStart(true); 62 | satbrp.setParent(rfa); 63 | satbrp.start(); 64 | 65 | rfa.setRollingPolicy(satbrp); 66 | 67 | PatternLayoutEncoder ple = new PatternLayoutEncoder(); 68 | ple.setContext(loggerContext); 69 | ple.setPattern("%d{dd日 HH:mm:ss.SS} %msg%n"); 70 | ple.start(); 71 | 72 | rfa.setEncoder(ple); 73 | rfa.start(); 74 | 75 | ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(logName); 76 | root.addAppender(rfa); 77 | } 78 | } -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/ui/BaseActivity.kt: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.ui 2 | 3 | import android.content.Context 4 | import android.content.res.Configuration 5 | import android.graphics.Color 6 | import android.os.Bundle 7 | import android.view.View 8 | import androidx.core.view.WindowCompat 9 | import androidx.core.view.WindowInsetsControllerCompat 10 | import androidx.appcompat.app.AppCompatActivity 11 | import androidx.appcompat.widget.Toolbar 12 | import fansirsqi.xposed.sesame.R 13 | import fansirsqi.xposed.sesame.data.ViewAppInfo 14 | 15 | open class BaseActivity : AppCompatActivity() { 16 | private lateinit var toolbar: Toolbar 17 | 18 | /** 19 | * 在创建活动时调用,初始化基础设置。 20 | * 21 | * @param savedInstanceState 之前保存的实例状态 22 | */ 23 | override fun onCreate(savedInstanceState: Bundle?) { 24 | super.onCreate(savedInstanceState) 25 | ViewAppInfo.init(applicationContext) 26 | 27 | // 使用WindowInsetsControllerCompat处理状态栏 28 | WindowCompat.setDecorFitsSystemWindows(window, false) 29 | @Suppress("DEPRECATION") 30 | window.statusBarColor = Color.TRANSPARENT 31 | WindowInsetsControllerCompat(window, window.decorView).let { controller -> 32 | controller.isAppearanceLightStatusBars = true 33 | } 34 | } 35 | 36 | /** 37 | * 当活动的内容视图发生变化时调用。 38 | * 设置工具栏并初始化标题和副标题。 39 | */ 40 | override fun onContentChanged() { 41 | super.onContentChanged() 42 | // 查找并设置工具栏 43 | toolbar = findViewById(R.id.x_toolbar) 44 | toolbar.setTitle(baseTitle) 45 | toolbar.setSubtitle(baseSubtitle) 46 | // 设置工具栏为支持操作栏 47 | setSupportActionBar(toolbar) 48 | } 49 | 50 | var baseTitle: String? 51 | get() = ViewAppInfo.appTitle 52 | set(title) { 53 | toolbar.title = title 54 | } 55 | open var baseSubtitle: String? 56 | get() = null 57 | set(subTitle) { 58 | toolbar.subtitle = subTitle 59 | } 60 | 61 | fun setBaseTitleTextColor(color: Int) { 62 | toolbar.setTitleTextColor(color) 63 | } 64 | 65 | fun setBaseSubtitleTextColor(color: Int) { 66 | toolbar.setSubtitleTextColor(color) 67 | } 68 | 69 | override fun attachBaseContext(newBase: Context) { 70 | val configuration = newBase.resources.configuration 71 | // 创建新的Configuration对象 72 | val configurationNew = Configuration(configuration) 73 | // 创建新的Context配置 74 | val context = newBase.createConfigurationContext(configurationNew) 75 | super.attachBaseContext(context) 76 | } 77 | 78 | override fun onConfigurationChanged(newConfig: Configuration) { 79 | super.onConfigurationChanged(newConfig) 80 | // 当UI模式(日夜模式)发生变化时,重建Activity以应用新主题 81 | if ((newConfig.diff(resources.configuration) and Configuration.UI_MODE_NIGHT_MASK) != 0) { 82 | recreate() 83 | } else { 84 | toolbar.title = baseTitle 85 | toolbar.subtitle = baseSubtitle 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/util/ToastUtil.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.util; 2 | import android.annotation.SuppressLint; 3 | import android.content.Context; 4 | import android.os.Handler; 5 | import android.os.Looper; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.widget.TextView; 9 | import android.widget.Toast; 10 | import fansirsqi.xposed.sesame.R; 11 | import fansirsqi.xposed.sesame.model.BaseModel; 12 | public class ToastUtil { 13 | private static final String TAG = "ToastUtil"; 14 | private static Context appContext; 15 | /** 16 | * 初始化全局 Context。建议在 Application 类中调用。 17 | * 18 | * @param context 应用上下文 19 | */ 20 | public static void init(Context context) { 21 | if (context != null) { 22 | appContext = context.getApplicationContext(); 23 | } 24 | } 25 | /** 26 | * 获取当前环境的 Context 27 | * 28 | * @return Context 29 | */ 30 | private static Context getContext() { 31 | if (appContext == null) { 32 | throw new IllegalStateException("ToastUtil is not initialized. Call ToastUtil.init(context) in Application."); 33 | } 34 | return appContext; 35 | } 36 | /** 37 | * 显示自定义 Toast 38 | * 39 | * @param message 显示的消息 40 | */ 41 | public static void showToast(String message) { 42 | showToast(getContext(), message); 43 | } 44 | /** 45 | * 显示自定义 Toast 46 | * 47 | * @param context 上下文 48 | * @param message 显示的消息 49 | */ 50 | public static void showToast(Context context, String message) { 51 | Log.runtime(TAG,"showToast: " + message); 52 | Toast toast = Toast.makeText(context, message, Toast.LENGTH_SHORT); 53 | toast.setGravity(toast.getGravity(), toast.getXOffset(), BaseModel.getToastOffsetY().getValue()); 54 | toast.show(); 55 | } 56 | /** 57 | * 创建自定义 Toast 58 | * 59 | * @param message 显示的消息 60 | * @param duration 显示时长 61 | * @return Toast 对象 62 | */ 63 | public static Toast makeText(String message, int duration) { 64 | return makeText(getContext(), message, duration); 65 | } 66 | /** 67 | * 创建自定义 Toast 68 | * 69 | * @param context 上下文 70 | * @param message 显示的消息 71 | * @param duration 显示时长 72 | * @return Toast 对象 73 | */ 74 | public static Toast makeText(Context context, String message, int duration) { 75 | Toast toast = Toast.makeText(context, message, duration); 76 | toast.setGravity(toast.getGravity(), toast.getXOffset(), BaseModel.getToastOffsetY().getValue()); 77 | return toast; 78 | } 79 | public static void showToastWithDelay(Context context, String message, int delayMillis) { 80 | new Handler(Looper.getMainLooper()).postDelayed(() -> makeText(context, message, Toast.LENGTH_SHORT).show(), delayMillis); 81 | } 82 | public static void showToastWithDelay(String message, int delayMillis) { 83 | new Handler(Looper.getMainLooper()).postDelayed(() -> makeText(message, Toast.LENGTH_SHORT).show(), delayMillis); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/entity/UserEntity.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.entity; 2 | 3 | import fansirsqi.xposed.sesame.util.StringUtil; 4 | import lombok.Data; 5 | import lombok.Getter; 6 | 7 | /** 8 | * 表示一个用户实体,包含用户的基本信息。 9 | */ 10 | @Getter 11 | public class UserEntity { 12 | /** 13 | * 用户 ID 14 | */ 15 | public final String userId; 16 | /** 17 | * 用户的账号 18 | */ 19 | public final String account; 20 | /** 21 | * 用户的好友状态(例如:是否是好友等) 22 | */ 23 | public final Integer friendStatus; 24 | /** 25 | * 用户的真实姓名 26 | */ 27 | public final String realName; 28 | /** 29 | * 用户的昵称 30 | */ 31 | public final String nickName; 32 | /** 33 | * 用户的备注名 34 | */ 35 | public final String remarkName; 36 | /** 37 | * 用于显示的名字,优先使用备注名,若无则使用昵称 38 | */ 39 | public final String showName; 40 | /** 41 | * 用于显示的遮掩名字,真实姓名首字母被遮掩 42 | */ 43 | public final String maskName; 44 | /** 45 | * 用户的全名,格式为:显示名字 | 真实姓名 (账号) 46 | */ 47 | public final String fullName; 48 | 49 | /** 50 | * 构造方法,初始化用户基本信息。 51 | * 52 | * @param userId 用户 ID 53 | * @param account 用户账号 54 | * @param friendStatus 用户好友状态 55 | * @param realName 用户真实姓名 56 | * @param nickName 用户昵称 57 | * @param remarkName 用户备注名 58 | */ 59 | public UserEntity(String userId, String account, Integer friendStatus, String realName, String nickName, String remarkName) { 60 | this.userId = userId; 61 | this.account = account; 62 | this.friendStatus = friendStatus; 63 | this.realName = realName; 64 | this.nickName = nickName; 65 | this.remarkName = remarkName; 66 | // 计算显示名称 67 | String showNameTmp = StringUtil.isEmpty(remarkName) ? nickName : remarkName; 68 | // 处理遮掩名称,真实姓名的第一个字母会被替换为 * 69 | String maskNameTmp = (realName != null && realName.length() > 1) 70 | ? "*" + realName.substring(1) 71 | : realName; 72 | // 设置 showName 和 maskName 73 | this.showName = showNameTmp; 74 | this.maskName = showNameTmp + "|" + maskNameTmp; 75 | // 设置 fullName,格式为:显示名称 | 真实姓名 (账号) 76 | this.fullName = showNameTmp + "|" + realName + "(" + account + ")"; 77 | // Log.runtime(TAG,"UserEntity " + "created: " + this.fullName); 78 | } 79 | 80 | /** 81 | * 用户 DTO 类,用于传输数据的简化版本。 82 | */ 83 | @Data 84 | public static class UserDto { 85 | public String userId; 86 | public String account; 87 | public Integer friendStatus; 88 | public String realName; 89 | public String nickName; 90 | public String remarkName; 91 | 92 | /** 93 | * 将 UserDto 转换为 UserEntity 实体。 94 | * 95 | * @return 转换后的 UserEntity 实体 96 | */ 97 | public UserEntity toEntity() { 98 | return new UserEntity(userId, account, friendStatus, realName, nickName, remarkName); 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/util/StringUtil.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.util; 2 | import java.util.Collection; 3 | import java.util.Iterator; 4 | import java.util.Map; 5 | import java.util.Objects; 6 | public class StringUtil { 7 | public static boolean isEmpty(String str) { 8 | return str == null || str.isEmpty(); 9 | } 10 | public static String collectionJoinString(CharSequence conjunction, Collection collection) { 11 | if (!collection.isEmpty()) { 12 | StringBuilder b = new StringBuilder(); 13 | Iterator iterator = collection.iterator(); 14 | b.append(toStringOrEmpty(iterator.next())); 15 | while (iterator.hasNext()) { 16 | b.append(conjunction).append(toStringOrEmpty(iterator.next())); 17 | } 18 | return b.toString(); 19 | } 20 | return ""; 21 | } 22 | public static String arrayJoinString(CharSequence conjunction, Object... array) { 23 | int length = array.length; 24 | if (length > 0) { 25 | StringBuilder b = new StringBuilder(); 26 | b.append(toStringOrEmpty(array[0])); 27 | for (int i = 1; i < length; i++) { 28 | b.append(conjunction).append(toStringOrEmpty(array[i])); 29 | } 30 | return b.toString(); 31 | } 32 | return ""; 33 | } 34 | public static String arrayToString(Object... array) { 35 | return arrayJoinString(",", array); 36 | } 37 | private static String toStringOrEmpty(Object obj) { 38 | return Objects.toString(obj, ""); 39 | } 40 | public static String padLeft(int str, int totalWidth, char padChar) { 41 | return padLeft(String.valueOf(str), totalWidth, padChar); 42 | } 43 | public static String padRight(int str, int totalWidth, char padChar) { 44 | return padRight(String.valueOf(str), totalWidth, padChar); 45 | } 46 | public static String padLeft(String str, int totalWidth, char padChar) { 47 | StringBuilder sb = new StringBuilder(str); 48 | while (sb.length() < totalWidth) { 49 | sb.insert(0, padChar); 50 | } 51 | return sb.toString(); 52 | } 53 | public static String padRight(String str, int totalWidth, char padChar) { 54 | StringBuilder sb = new StringBuilder(str); 55 | while (sb.length() < totalWidth) { 56 | sb.append(padChar); 57 | } 58 | return sb.toString(); 59 | } 60 | public static String getSubString(String text, String left, String right) { 61 | String result = ""; 62 | int zLen; 63 | if (left == null || left.isEmpty()) { 64 | zLen = 0; 65 | } else { 66 | zLen = text.indexOf(left); 67 | if (zLen > -1) { 68 | zLen += left.length(); 69 | } else { 70 | zLen = 0; 71 | } 72 | } 73 | int yLen = text.indexOf(right, zLen); 74 | if (yLen < 0 || right == null || right.isEmpty()) { 75 | yLen = text.length(); 76 | } 77 | result = text.substring(zLen, yLen); 78 | return result; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/ui/MyWebView.kt: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.ui 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import android.webkit.WebSettings 6 | import android.webkit.WebView 7 | import android.webkit.WebViewClient 8 | 9 | /** 10 | * 自定义 WebView 类,提供默认的初始化设置和滚动到底部的功能。 11 | */ 12 | class MyWebView : WebView { 13 | /** 14 | * 构造函数,用于当没有 AttributeSet 参数时。 15 | * 16 | * @param c Context 对象 17 | */ 18 | constructor(c: Context) : super(c) { 19 | defInit() 20 | } 21 | 22 | /** 23 | * 构造函数,用于当有 AttributeSet 参数时。 24 | * 25 | * @param context Context 对象 26 | * @param attrs AttributeSet 对象 27 | */ 28 | constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { 29 | defInit() 30 | } 31 | 32 | /** 33 | * 构造函数,用于当有 AttributeSet 和 defStyleAttr 参数时。 34 | * 35 | * @param context Context 对象 36 | * @param attrs AttributeSet 对象 37 | * @param defStyleAttr 默认样式属性 38 | */ 39 | constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { 40 | defInit() 41 | } 42 | 43 | /** 44 | * 构造函数,用于当有 AttributeSet、defStyleAttr 和 defStyleRes 参数时。 45 | * 46 | * @param context Context 对象 47 | * @param attrs AttributeSet 对象 48 | * @param defStyleAttr 默认样式属性 49 | * @param defStyleRes 默认样式资源 50 | */ 51 | constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) { 52 | defInit() 53 | } 54 | 55 | /** 56 | * 默认初始化方法,设置 WebView 的一些默认属性。 57 | */ 58 | private fun defInit() { 59 | val settings = settings 60 | settings.setSupportZoom(true) // 支持缩放 61 | settings.builtInZoomControls = true // 显示内置缩放控件 62 | settings.displayZoomControls = false // 不显示缩放控件 63 | settings.useWideViewPort = false // 不使用宽视图端口 64 | settings.layoutAlgorithm = WebSettings.LayoutAlgorithm.NORMAL // 设置布局算法为 NORMAL 65 | settings.allowFileAccess = true // 允许访问文件 66 | // 设置 WebViewClient 以处理页面加载完成事件 67 | webViewClient = object : WebViewClient() { 68 | override fun onPageFinished(view: WebView, url: String) { 69 | super.onPageFinished(view, url) 70 | // 如果 URL 以 .log 结尾,则尝试滚动到底部 71 | if (url.endsWith(".log")) { 72 | postDelayed(object : Runnable { 73 | override fun run() { 74 | // 如果内容高度为 0,则每隔 100 毫秒检查一次,直到有内容 75 | if (contentHeight == 0) { 76 | postDelayed(this, 100) 77 | } else { 78 | scrollToBottom() // 滚动到底部 79 | } 80 | } 81 | }, 500) // 延迟 500 毫秒执行 82 | } 83 | } 84 | } 85 | } 86 | 87 | /** 88 | * 滚动到 WebView 的底部。 89 | */ 90 | fun scrollToBottom() { 91 | // 计算垂直滚动范围并滚动到底部 92 | scrollTo(0, computeVerticalScrollRange()) 93 | } 94 | } -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/ui/widget/TabAdapter.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.ui.widget; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.TextView; 8 | 9 | import androidx.annotation.NonNull; 10 | import androidx.core.content.ContextCompat; 11 | import androidx.recyclerview.widget.RecyclerView; 12 | 13 | import java.util.List; 14 | 15 | import fansirsqi.xposed.sesame.R; 16 | 17 | public class TabAdapter extends RecyclerView.Adapter { 18 | private final List titles; 19 | private final OnTabClickListener listener; 20 | private int selectedPosition = 0; 21 | private final Context context; 22 | 23 | public TabAdapter(Context context, List titles, OnTabClickListener listener) { 24 | this.context = context; 25 | this.titles = titles; 26 | this.listener = listener; 27 | } 28 | 29 | @NonNull 30 | @Override 31 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 32 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_tab, parent, false); 33 | return new ViewHolder(view); 34 | } 35 | 36 | @Override 37 | public void onBindViewHolder(@NonNull ViewHolder holder, int position) { 38 | holder.textView.setText(titles.get(position)); 39 | holder.textView.setTextColor(ContextCompat.getColor(context, R.color.textColorPrimary)); 40 | 41 | // 设置背景资源 42 | if (selectedPosition == position) { 43 | // holder.itemView.setBackgroundResource(R.drawable.tab_selected_background); 44 | holder.textView.setTextColor(ContextCompat.getColor(context, R.color.orange)); 45 | holder.itemView.findViewById(R.id.indicator_bar).setBackgroundResource(R.color.orange); 46 | } else { 47 | // holder.itemView.setBackgroundResource(R.drawable.tab_background); 48 | holder.textView.setTextColor(ContextCompat.getColor(context, R.color.textColorPrimary)); 49 | holder.itemView.findViewById(R.id.indicator_bar).setBackgroundResource(android.R.color.transparent); 50 | } 51 | 52 | holder.itemView.setOnClickListener(v -> { 53 | if (position != selectedPosition) { 54 | listener.onTabClick(position); 55 | setSelectedPosition(position); 56 | } 57 | }); 58 | } 59 | 60 | @Override 61 | public int getItemCount() { 62 | return titles.size(); 63 | } 64 | 65 | public void setSelectedPosition(int position) { 66 | int oldPosition = selectedPosition; 67 | selectedPosition = position; 68 | notifyItemChanged(oldPosition); 69 | notifyItemChanged(selectedPosition); 70 | } 71 | 72 | public static class ViewHolder extends RecyclerView.ViewHolder { 73 | TextView textView; 74 | 75 | public ViewHolder(@NonNull View itemView) { 76 | super(itemView); 77 | textView = itemView.findViewById(R.id.tab_text); 78 | } 79 | } 80 | 81 | public interface OnTabClickListener { 82 | void onTabClick(int position); 83 | } 84 | } -------------------------------------------------------------------------------- /app/src/main/java/fansirsqi/xposed/sesame/hook/rpc/debug/DebugRpcCall.java: -------------------------------------------------------------------------------- 1 | package fansirsqi.xposed.sesame.hook.rpc.debug; 2 | import fansirsqi.xposed.sesame.hook.RequestManager; 3 | public class DebugRpcCall { 4 | private static final String version = "2.0"; 5 | public static String queryBaseinfo() { 6 | return RequestManager.requestString("com.alipay.neverland.biz.rpc.queryBaseinfo", 7 | "[{\"branchId\":\"WUFU\",\"source\":\"fuqiTown\"}]"); 8 | } 9 | /** 行走格子 */ 10 | public static String walkGrid() { 11 | return RequestManager.requestString("com.alipay.neverland.biz.rpc.walkGrid", 12 | "[{\"drilling\":false,\"mapId\":\"MF1\",\"source\":\"fuqiTown\"}]"); 13 | } 14 | /** 小游戏 */ 15 | public static String miniGameFinish(String gameId, String gameKey) { 16 | return RequestManager.requestString("com.alipay.neverland.biz.rpc.miniGameFinish", 17 | "[{\"gameId\":\"" + gameId + "\",\"gameKey\":\"" + gameKey 18 | + "\",\"mapId\":\"MF1\",\"score\":490,\"source\":\"fuqiTown\"}]"); 19 | } 20 | public static String taskFinish(String bizId) { 21 | return RequestManager.requestString("com.alipay.adtask.biz.mobilegw.service.task.finish", 22 | "[{\"bizId\":\"" + bizId + "\"}]"); 23 | } 24 | public static String queryAdFinished(String bizId, String scene) { 25 | return RequestManager.requestString("com.alipay.neverland.biz.rpc.queryAdFinished", 26 | "[{\"adBizNo\":\"" + bizId + "\",\"scene\":\"" + scene 27 | + "\",\"source\":\"fuqiTown\"}]"); 28 | } 29 | public static String queryWufuTaskHall() { 30 | return RequestManager.requestString("com.alipay.neverland.biz.rpc.queryWufuTaskHall", 31 | "[{\"source\":\"fuqiTown\"}]"); 32 | } 33 | public static String fuQiTaskQuery() { 34 | return RequestManager.requestString("com.alipay.wufudragonprod.biz.wufu2024.fuQiTown.fuQiTask.query", 35 | "[{}]"); 36 | } 37 | public static String fuQiTaskTrigger(String appletId, String stageCode) { 38 | return RequestManager.requestString("com.alipay.wufudragonprod.biz.wufu2024.fuQiTown.fuQiTask.trigger", 39 | "[{\"appletId\":\"" + appletId + "\",\"stageCode\":\"" + stageCode + "\"}]"); 40 | } 41 | public static String queryEnvironmentCertDetailList(String alias, int pageNum, String targetUserID) { 42 | return RequestManager.requestString("alipay.antforest.forest.h5.queryEnvironmentCertDetailList", 43 | "[{\"alias\":\"" + alias + "\",\"certId\":\"\",\"pageNum\":" + pageNum 44 | + ",\"shareId\":\"\",\"source\":\"chInfo_ch_appcenter__chsub_9patch\",\"targetUserID\":\"" 45 | + targetUserID + "\",\"version\":\"20230701\"}]"); 46 | } 47 | public static String sendTree(String certificateId, String friendUserId) { 48 | return RequestManager.requestString("alipay.antforest.forest.h5.sendTree", 49 | "[{\"blessWords\":\"梭梭没有叶子,四季常青,从不掉发,祝你发量如梭。\",\"certificateId\":\"" + certificateId 50 | + "\",\"friendUserId\":\"" + friendUserId 51 | + "\",\"source\":\"chInfo_ch_appcenter__chsub_9patch\"}]"); 52 | } 53 | } --------------------------------------------------------------------------------