You've already forked revanced-integrations
mirror of
https://github.com/revanced/revanced-integrations
synced 2025-11-21 18:35:37 +01:00
Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c3e302d224 | ||
|
|
1010eedbb2 | ||
|
|
c7756e1299 | ||
|
|
3022afc7c4 | ||
|
|
9bcb04de8e | ||
|
|
322e145f75 | ||
|
|
5a24e84868 | ||
|
|
c049dc3e8d | ||
|
|
149a90a2e8 | ||
|
|
2d001cfb1d | ||
|
|
8bb93a439b | ||
|
|
0fe4db9f28 | ||
|
|
4cc8a22c26 | ||
|
|
11fbf1a5b3 | ||
|
|
fa0ad3a57b | ||
|
|
73b40595c4 | ||
|
|
04bbe259cb | ||
|
|
8dde925b47 | ||
|
|
4ca1182485 | ||
|
|
4c72ac1cd5 | ||
|
|
cdca96224a | ||
|
|
868e99a619 | ||
|
|
f1e9aa30ba | ||
|
|
ae8d39a831 | ||
|
|
0304ccb168 | ||
|
|
5a710aa033 | ||
|
|
fd924ad934 | ||
|
|
f47cc8b375 | ||
|
|
b97c6005f0 | ||
|
|
8feeb323ba | ||
|
|
c4be039367 | ||
|
|
0a1f42595e | ||
|
|
c3f79eb27b | ||
|
|
cf2d6b955a | ||
|
|
37974389ac | ||
|
|
3fd6df8277 | ||
|
|
ba22e3bc56 | ||
|
|
7e2f48eb3e | ||
|
|
6a1669ea71 | ||
|
|
6d8c0a0c73 |
2
.github/ISSUE_TEMPLATE/config.yml
vendored
2
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -5,4 +5,4 @@ contact_links:
|
||||
about: Don't know how or where to start? Check out our documentation!
|
||||
- name: 🗨 Discussions
|
||||
url: https://github.com/revanced/revanced-suggestions/discussions
|
||||
about: Got something you think should change or be added? Search for or start a new discussion!
|
||||
about: Got something you think should change or be added? Search for or start a new discussion!
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/feature-issue.yml
vendored
2
.github/ISSUE_TEMPLATE/feature-issue.yml
vendored
@@ -43,4 +43,4 @@ body:
|
||||
label: Additional context
|
||||
description: Add additional context here.
|
||||
validations:
|
||||
required: false
|
||||
required: false
|
||||
|
||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -37,4 +37,4 @@ jobs:
|
||||
- name: Release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: npx semantic-release
|
||||
run: npx semantic-release
|
||||
|
||||
116
CHANGELOG.md
116
CHANGELOG.md
@@ -1,3 +1,119 @@
|
||||
## [0.46.2](https://github.com/revanced/revanced-integrations/compare/v0.46.1...v0.46.2) (2022-10-01)
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **general-ads:** hook pathBuilder ([c7756e1](https://github.com/revanced/revanced-integrations/commit/c7756e1299bdc2e241525ad89561ea67bc372e3a))
|
||||
|
||||
## [0.46.1](https://github.com/revanced/revanced-integrations/compare/v0.46.0...v0.46.1) (2022-09-30)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **general-ads:** remove duplicate blocklist entry ([#165](https://github.com/revanced/revanced-integrations/issues/165)) ([9bcb04d](https://github.com/revanced/revanced-integrations/commit/9bcb04de8e8bd0c8c46ce797db42eb758e632580))
|
||||
|
||||
# [0.46.0](https://github.com/revanced/revanced-integrations/compare/v0.45.0...v0.46.0) (2022-09-30)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **general-ads:** block additional home ads ([5a24e84](https://github.com/revanced/revanced-integrations/commit/5a24e8486809b73f6c5a95b3f6d28a3da1cddbb8))
|
||||
|
||||
# [0.45.0](https://github.com/revanced/revanced-integrations/compare/v0.44.1...v0.45.0) (2022-09-29)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* `disable-startup-shorts-player` patch ([#164](https://github.com/revanced/revanced-integrations/issues/164)) ([149a90a](https://github.com/revanced/revanced-integrations/commit/149a90a2e8711a95ec4a310c7ba1e8f0ef6a218f))
|
||||
|
||||
## [0.44.1](https://github.com/revanced/revanced-integrations/compare/v0.44.0...v0.44.1) (2022-09-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **hide-email-address:** invalid initial switch toggle state ([#163](https://github.com/revanced/revanced-integrations/issues/163)) ([8bb93a4](https://github.com/revanced/revanced-integrations/commit/8bb93a439be21c2f564f3bc2adaedf669977f1fb))
|
||||
|
||||
# [0.44.0](https://github.com/revanced/revanced-integrations/compare/v0.43.1...v0.44.0) (2022-09-28)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* `hide-email-address` patch ([#149](https://github.com/revanced/revanced-integrations/issues/149)) ([4cc8a22](https://github.com/revanced/revanced-integrations/commit/4cc8a22c26c20164d88bff8953d1de53e2041753))
|
||||
|
||||
## [0.43.1](https://github.com/revanced/revanced-integrations/compare/v0.43.0...v0.43.1) (2022-09-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* move dummy classes to `dummy` module ([#162](https://github.com/revanced/revanced-integrations/issues/162)) ([fa0ad3a](https://github.com/revanced/revanced-integrations/commit/fa0ad3a57b437bfc2d34062ac54e56b6900bafab))
|
||||
|
||||
# [0.43.0](https://github.com/revanced/revanced-integrations/compare/v0.42.2...v0.43.0) (2022-09-26)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* enable minification ([#158](https://github.com/revanced/revanced-integrations/issues/158)) ([8dde925](https://github.com/revanced/revanced-integrations/commit/8dde925b47ff30afc373303b0fdb65c86f9ba82b))
|
||||
|
||||
## [0.42.2](https://github.com/revanced/revanced-integrations/compare/v0.42.1...v0.42.2) (2022-09-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **swipe-controls:** crash on SDK below 24 ([#157](https://github.com/revanced/revanced-integrations/issues/157)) ([4c72ac1](https://github.com/revanced/revanced-integrations/commit/4c72ac1cd5ee2aae8478171e56e488563459a0f7))
|
||||
|
||||
## [0.42.1](https://github.com/revanced/revanced-integrations/compare/v0.42.0...v0.42.1) (2022-09-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **build:** remove distributionSha256Sum property ([#153](https://github.com/revanced/revanced-integrations/issues/153)) [skip ci] ([ae8d39a](https://github.com/revanced/revanced-integrations/commit/ae8d39a83144bb19f2db1403c32b73232be570b5))
|
||||
* **custom-playback-speed:** fill array to generate required instructions ([#155](https://github.com/revanced/revanced-integrations/issues/155)) ([868e99a](https://github.com/revanced/revanced-integrations/commit/868e99a6199118151766ecf2dbf7a9df02b59a3e))
|
||||
* **hide-time-and-seekbar:** don't draw the seekbar ([#154](https://github.com/revanced/revanced-integrations/issues/154)) ([f1e9aa3](https://github.com/revanced/revanced-integrations/commit/f1e9aa30baa582f7eb07f62168ea2d57c5622685))
|
||||
|
||||
# [0.42.0](https://github.com/revanced/revanced-integrations/compare/v0.41.2...v0.42.0) (2022-09-23)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **tiktok:** adapt `tiktok-download` with `tiktok-settings`. ([#152](https://github.com/revanced/revanced-integrations/issues/152)) ([5a710aa](https://github.com/revanced/revanced-integrations/commit/5a710aa0330741d6ff84dd526e1e59d679e6923c))
|
||||
|
||||
## [0.41.2](https://github.com/revanced/revanced-integrations/compare/v0.41.1...v0.41.2) (2022-09-22)
|
||||
|
||||
## [0.41.1](https://github.com/revanced/revanced-integrations/compare/v0.41.0...v0.41.1) (2022-09-22)
|
||||
|
||||
# [0.41.0](https://github.com/revanced/revanced-integrations/compare/v0.40.0...v0.41.0) (2022-09-21)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* `tiktok-feed-filter` , `tiktok-settings` and `tiktok-force-login` patch ([#142](https://github.com/revanced/revanced-integrations/issues/142)) ([c3f79eb](https://github.com/revanced/revanced-integrations/commit/c3f79eb27bf71c02299fdd6892179fd081eca07e))
|
||||
|
||||
# [0.40.0](https://github.com/revanced/revanced-integrations/compare/v0.39.0...v0.40.0) (2022-09-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* disable sponsorblock on shorts ([#135](https://github.com/revanced/revanced-integrations/issues/135)) ([3797438](https://github.com/revanced/revanced-integrations/commit/37974389ac27e98d18cdfc67c61c0945b53bd0c1))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* `disable-auto-player-popup-panels` patch ([#145](https://github.com/revanced/revanced-integrations/issues/145)) ([3fd6df8](https://github.com/revanced/revanced-integrations/commit/3fd6df82770acacb6fc16b176521abd98080756f))
|
||||
|
||||
# [0.39.0](https://github.com/revanced/revanced-integrations/compare/v0.38.0...v0.39.0) (2022-09-21)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* `hide-time-and-seekbar` patch ([#146](https://github.com/revanced/revanced-integrations/issues/146)) ([7e2f48e](https://github.com/revanced/revanced-integrations/commit/7e2f48eb3e92c49c4ea0516f9a8e7e5fbfb39965))
|
||||
|
||||
# [0.38.0](https://github.com/revanced/revanced-integrations/compare/v0.37.4...v0.38.0) (2022-09-20)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* disable `swipe-controls` when player controls are visible ([#123](https://github.com/revanced/revanced-integrations/issues/123)) ([6d8c0a0](https://github.com/revanced/revanced-integrations/commit/6d8c0a0c738ce976a7a37d2e1e3d38e6ebc29d09))
|
||||
|
||||
## [0.37.4](https://github.com/revanced/revanced-integrations/compare/v0.37.3...v0.37.4) (2022-09-18)
|
||||
|
||||
|
||||
|
||||
2
app/.gitignore
vendored
2
app/.gitignore
vendored
@@ -1 +1 @@
|
||||
/build
|
||||
/build
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'org.jetbrains.kotlin.android'
|
||||
|
||||
android {
|
||||
compileSdkVersion 32
|
||||
namespace 'app.revanced.integrations'
|
||||
|
||||
defaultConfig {
|
||||
applicationId "app.revanced.integrations"
|
||||
minSdkVersion 23
|
||||
targetSdkVersion 32
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
multiDexEnabled false
|
||||
|
||||
Properties properties = new Properties()
|
||||
if (rootProject.file("local.properties").exists()) {
|
||||
properties.load(rootProject.file("local.properties").newDataInputStream())
|
||||
}
|
||||
|
||||
buildConfigField "String", "YT_API_KEY", "\"${properties.getProperty("youtubeAPIKey", "")}\""
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_11
|
||||
targetCompatibility JavaVersion.VERSION_11
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly 'androidx.annotation:annotation:1.4.0'
|
||||
}
|
||||
|
||||
48
app/build.gradle.kts
Normal file
48
app/build.gradle.kts
Normal file
@@ -0,0 +1,48 @@
|
||||
import java.io.FileInputStream
|
||||
import java.util.Properties
|
||||
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
id("org.jetbrains.kotlin.android")
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdk = 32
|
||||
buildToolsVersion = "32.0.0"
|
||||
namespace = "app.revanced.integrations"
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "app.revanced.integrations"
|
||||
minSdk = 23
|
||||
targetSdk = 32
|
||||
versionCode = 1
|
||||
versionName = "1.0"
|
||||
multiDexEnabled = false
|
||||
|
||||
val properties = Properties()
|
||||
if (rootProject.file("local.properties").exists()) {
|
||||
properties.load(FileInputStream(rootProject.file("local.properties")))
|
||||
}
|
||||
|
||||
buildConfigField("String", "YT_API_KEY", "\"${properties.getProperty("youtubeAPIKey", "")}\"")
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = true
|
||||
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility(JavaVersion.VERSION_11)
|
||||
targetCompatibility(JavaVersion.VERSION_11)
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = JavaVersion.VERSION_11.toString()
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly(project(mapOf("path" to ":dummy")))
|
||||
compileOnly("androidx.annotation:annotation:1.5.0")
|
||||
}
|
||||
9
app/proguard-rules.pro
vendored
9
app/proguard-rules.pro
vendored
@@ -18,4 +18,11 @@
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
#-renamesourcefileattribute SourceFile
|
||||
-dontobfuscate
|
||||
-keep class app.revanced.** {
|
||||
*;
|
||||
}
|
||||
-keep class com.google.** {
|
||||
*;
|
||||
}
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
|
||||
</manifest>
|
||||
</manifest>
|
||||
|
||||
@@ -3,8 +3,6 @@ package app.revanced.integrations.patches;
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
|
||||
public class AutoRepeatPatch {
|
||||
|
||||
|
||||
//Used by app.revanced.patches.youtube.layout.autorepeat.patch.AutoRepeatPatch
|
||||
public static boolean shouldAutoRepeat() {
|
||||
return SettingsEnum.PREFERRED_AUTO_REPEAT.getBoolean();
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package app.revanced.integrations.patches;
|
||||
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
|
||||
public class DisablePlayerPopupPanelsPatch {
|
||||
//Used by app.revanced.patches.youtube.layout.playerpopuppanels.patch.PlayerPopupPanelsPatch
|
||||
public static boolean disablePlayerPopupPanels() {
|
||||
return SettingsEnum.PLAYER_POPUP_PANELS.getBoolean();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package app.revanced.integrations.patches;
|
||||
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
|
||||
public class DisableStartupShortsPlayerPatch {
|
||||
//Used by app.revanced.patches.youtube.layout.startupshortsreset.patch.DisableShortsOnStartupPatch
|
||||
public static boolean disableStartupShortsPlayer() {
|
||||
return SettingsEnum.DISABLE_STARTUP_SHORTS_PLAYER.getBoolean();
|
||||
}
|
||||
}
|
||||
@@ -1,136 +1,101 @@
|
||||
package app.revanced.integrations.patches;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
import app.revanced.integrations.utils.LogHelper;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class GeneralBytecodeAdsPatch {
|
||||
|
||||
//Used by app.revanced.patches.youtube.ad.general.bytecode.patch.GeneralBytecodeAdsPatch
|
||||
public static boolean containsAd(String value, ByteBuffer buffer) {
|
||||
return containsLithoAd(value, buffer);
|
||||
}
|
||||
public static boolean isAdComponent(StringBuilder pathBuilder) {
|
||||
var path = pathBuilder.toString();
|
||||
if (path.isEmpty()) return false;
|
||||
|
||||
private static boolean containsLithoAd(String value, ByteBuffer buffer) {
|
||||
boolean enabled = false;
|
||||
for (SettingsEnum setting : SettingsEnum.getAdRemovalSettings()) {
|
||||
if (setting.getBoolean()) {
|
||||
enabled = true;
|
||||
break;
|
||||
}
|
||||
LogHelper.debug(GeneralBytecodeAdsPatch.class, "Searching for an ad in: " + path);
|
||||
|
||||
List<String> blockList = new ArrayList<>();
|
||||
|
||||
if (SettingsEnum.ADREMOVER_AD_REMOVAL.getBoolean()) {
|
||||
blockList.add("video_display_full_buttoned_layout");
|
||||
blockList.add("ad_");
|
||||
blockList.add("ads_video_with_context");
|
||||
blockList.add("cell_divider");
|
||||
blockList.add("reels_player_overlay");
|
||||
blockList.add("shelf_header");
|
||||
blockList.add("watch_metadata_app_promo");
|
||||
blockList.add("video_display_full_layout");
|
||||
}
|
||||
|
||||
try {
|
||||
if (value == null || value.isEmpty() || !enabled) return false;
|
||||
LogHelper.debug(GeneralBytecodeAdsPatch.class, "Searching for AD: " + value);
|
||||
|
||||
List<String> blockList = new ArrayList<>();
|
||||
List<String> bufferBlockList = new ArrayList<>();
|
||||
|
||||
if (SettingsEnum.ADREMOVER_AD_REMOVAL.getBoolean()) {
|
||||
blockList.add("_ad");
|
||||
blockList.add("ad_badge");
|
||||
blockList.add("ads_video_with_context");
|
||||
blockList.add("cell_divider");
|
||||
blockList.add("reels_player_overlay");
|
||||
blockList.add("shelf_header");
|
||||
blockList.add("text_search_ad_with_description_first");
|
||||
blockList.add("watch_metadata_app_promo");
|
||||
blockList.add("video_display_full_layout");
|
||||
|
||||
bufferBlockList.add("ad_cpn");
|
||||
}
|
||||
if (SettingsEnum.ADREMOVER_SUGGESTED_FOR_YOU_REMOVAL.getBoolean()) {
|
||||
bufferBlockList.add("watch-vrecH");
|
||||
}
|
||||
if (SettingsEnum.ADREMOVER_MOVIE_REMOVAL.getBoolean()) {
|
||||
blockList.add("browsy_bar");
|
||||
blockList.add("compact_movie");
|
||||
blockList.add("horizontal_movie_shelf");
|
||||
blockList.add("movie_and_show_upsell_card");
|
||||
|
||||
bufferBlockList.add("YouTube Movies");
|
||||
}
|
||||
if (containsAny(value, "home_video_with_context", "related_video_with_context") &&
|
||||
anyMatch(bufferBlockList, new String(buffer.array(), StandardCharsets.UTF_8)::contains)
|
||||
) return true;
|
||||
|
||||
if (SettingsEnum.ADREMOVER_COMMENTS_REMOVAL.getBoolean()) {
|
||||
blockList.add("comments_");
|
||||
}
|
||||
if (SettingsEnum.ADREMOVER_COMMUNITY_GUIDELINES.getBoolean()) {
|
||||
blockList.add("community_guidelines");
|
||||
}
|
||||
if (SettingsEnum.ADREMOVER_COMPACT_BANNER_REMOVAL.getBoolean()) {
|
||||
blockList.add("compact_banner");
|
||||
}
|
||||
if (SettingsEnum.ADREMOVER_EMERGENCY_BOX_REMOVAL.getBoolean()) {
|
||||
blockList.add("emergency_onebox");
|
||||
}
|
||||
if (SettingsEnum.ADREMOVER_FEED_SURVEY_REMOVAL.getBoolean()) {
|
||||
blockList.add("in_feed_survey");
|
||||
}
|
||||
if (SettingsEnum.ADREMOVER_MEDICAL_PANEL_REMOVAL.getBoolean()) {
|
||||
blockList.add("medical_panel");
|
||||
}
|
||||
if (SettingsEnum.ADREMOVER_PAID_CONTECT_REMOVAL.getBoolean()) {
|
||||
blockList.add("paid_content_overlay");
|
||||
}
|
||||
if (SettingsEnum.ADREMOVER_COMMUNITY_POSTS_REMOVAL.getBoolean()) {
|
||||
blockList.add("post_base_wrapper");
|
||||
}
|
||||
if (SettingsEnum.ADREMOVER_MERCHANDISE_REMOVAL.getBoolean()) {
|
||||
blockList.add("product_carousel");
|
||||
}
|
||||
if (SettingsEnum.ADREMOVER_SHORTS_SHELF.getBoolean()) {
|
||||
blockList.add("shorts_shelf");
|
||||
}
|
||||
if (SettingsEnum.ADREMOVER_INFO_PANEL_REMOVAL.getBoolean()) {
|
||||
blockList.add("publisher_transparency_panel");
|
||||
blockList.add("single_item_information_panel");
|
||||
}
|
||||
if (SettingsEnum.ADREMOVER_HIDE_SUGGESTIONS.getBoolean()) {
|
||||
blockList.add("horizontal_video_shelf");
|
||||
}
|
||||
if (SettingsEnum.ADREMOVER_HIDE_LATEST_POSTS.getBoolean()) {
|
||||
blockList.add("post_shelf");
|
||||
}
|
||||
if (SettingsEnum.ADREMOVER_HIDE_CHANNEL_GUIDELINES.getBoolean()) {
|
||||
blockList.add("channel_guidelines_entry_banner");
|
||||
}
|
||||
|
||||
if (containsAny(value,
|
||||
"home_video_with_context",
|
||||
"related_video_with_context",
|
||||
"search_video_with_context",
|
||||
"menu",
|
||||
"root",
|
||||
"-count",
|
||||
"-space",
|
||||
"-button"
|
||||
)) return false;
|
||||
|
||||
if (anyMatch(blockList, value::contains)) {
|
||||
LogHelper.debug(GeneralBytecodeAdsPatch.class, "Blocking ad: " + value);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (SettingsEnum.DEBUG.getBoolean()) {
|
||||
if (value.contains("related_video_with_context")) {
|
||||
LogHelper.debug(GeneralBytecodeAdsPatch.class, value + " | " + bytesToHex(buffer.array()));
|
||||
return false;
|
||||
}
|
||||
LogHelper.debug(GeneralBytecodeAdsPatch.class, value + " returns false.");
|
||||
}
|
||||
return false;
|
||||
} catch (Exception ex) {
|
||||
LogHelper.printException(GeneralBytecodeAdsPatch.class, ex.getMessage(), ex);
|
||||
return false;
|
||||
if (SettingsEnum.ADREMOVER_MOVIE_REMOVAL.getBoolean()) {
|
||||
blockList.add("browsy_bar");
|
||||
blockList.add("compact_movie");
|
||||
blockList.add("horizontal_movie_shelf");
|
||||
blockList.add("movie_and_show_upsell_card");
|
||||
}
|
||||
|
||||
if (SettingsEnum.ADREMOVER_COMMENTS_REMOVAL.getBoolean()) {
|
||||
blockList.add("comments_");
|
||||
}
|
||||
if (SettingsEnum.ADREMOVER_COMMUNITY_GUIDELINES.getBoolean()) {
|
||||
blockList.add("community_guidelines");
|
||||
}
|
||||
if (SettingsEnum.ADREMOVER_COMPACT_BANNER_REMOVAL.getBoolean()) {
|
||||
blockList.add("compact_banner");
|
||||
}
|
||||
if (SettingsEnum.ADREMOVER_EMERGENCY_BOX_REMOVAL.getBoolean()) {
|
||||
blockList.add("emergency_onebox");
|
||||
}
|
||||
if (SettingsEnum.ADREMOVER_FEED_SURVEY_REMOVAL.getBoolean()) {
|
||||
blockList.add("in_feed_survey");
|
||||
}
|
||||
if (SettingsEnum.ADREMOVER_MEDICAL_PANEL_REMOVAL.getBoolean()) {
|
||||
blockList.add("medical_panel");
|
||||
}
|
||||
if (SettingsEnum.ADREMOVER_PAID_CONTECT_REMOVAL.getBoolean()) {
|
||||
blockList.add("paid_content_overlay");
|
||||
}
|
||||
if (SettingsEnum.ADREMOVER_COMMUNITY_POSTS_REMOVAL.getBoolean()) {
|
||||
blockList.add("post_base_wrapper");
|
||||
}
|
||||
if (SettingsEnum.ADREMOVER_MERCHANDISE_REMOVAL.getBoolean()) {
|
||||
blockList.add("product_carousel");
|
||||
}
|
||||
if (SettingsEnum.ADREMOVER_SHORTS_SHELF.getBoolean()) {
|
||||
blockList.add("shorts_shelf");
|
||||
}
|
||||
if (SettingsEnum.ADREMOVER_INFO_PANEL_REMOVAL.getBoolean()) {
|
||||
blockList.add("publisher_transparency_panel");
|
||||
blockList.add("single_item_information_panel");
|
||||
}
|
||||
if (SettingsEnum.ADREMOVER_HIDE_SUGGESTIONS.getBoolean()) {
|
||||
blockList.add("horizontal_video_shelf");
|
||||
}
|
||||
if (SettingsEnum.ADREMOVER_HIDE_LATEST_POSTS.getBoolean()) {
|
||||
blockList.add("post_shelf");
|
||||
}
|
||||
if (SettingsEnum.ADREMOVER_HIDE_CHANNEL_GUIDELINES.getBoolean()) {
|
||||
blockList.add("channel_guidelines_entry_banner");
|
||||
}
|
||||
|
||||
if (containsAny(path,
|
||||
"home_video_with_context",
|
||||
"related_video_with_context",
|
||||
"search_video_with_context",
|
||||
"menu",
|
||||
"root",
|
||||
"-count",
|
||||
"-space",
|
||||
"-button"
|
||||
)) return false;
|
||||
|
||||
if (anyMatch(blockList, path::contains)) {
|
||||
LogHelper.debug(GeneralBytecodeAdsPatch.class, "Blocking ad: " + path);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean containsAny(String value, String... targets) {
|
||||
@@ -139,13 +104,6 @@ public class GeneralBytecodeAdsPatch {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static String bytesToHex(byte[] bytes) {
|
||||
StringBuilder builder = new StringBuilder(bytes.length * 2);
|
||||
for (byte b : bytes)
|
||||
builder.append(String.format("%02x", b));
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private static <T> boolean anyMatch(List<T> value, APredicate<? super T> predicate) {
|
||||
for (T t : value) {
|
||||
if (predicate.test(t)) return true;
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package app.revanced.integrations.patches;
|
||||
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
|
||||
public class HideEmailAddressPatch {
|
||||
//Used by app.revanced.patches.youtube.layout.personalinformation.patch.HideEmailAddressPatch
|
||||
public static boolean hideEmailAddress() {
|
||||
return SettingsEnum.HIDE_EMAIL_ADDRESS.getBoolean();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package app.revanced.integrations.patches;
|
||||
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
|
||||
public class HideTimeAndSeekbarPatch {
|
||||
//Used by app.revanced.patches.youtube.layout.hidetimeandseekbar.patch.HideTimeAndSeekbarPatch
|
||||
public static boolean hideTimeAndSeekbar() {
|
||||
return SettingsEnum.HIDE_TIME_AND_SEEKBAR.getBoolean();
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ import app.revanced.integrations.utils.ReVancedUtils;
|
||||
|
||||
public class VideoSpeedPatch {
|
||||
|
||||
public static final float[] videoSpeeds = {0.25f, 0.5f, 0.75f, 1.0f, 1.25f, 1.5f, 1.75f, 2.0f, 3.0f, 4.0f, 5.0f};
|
||||
public static final float[] videoSpeeds = { 0, 0 }; // Values are useless as they are being overridden by the respective patch
|
||||
private static Boolean userChangedSpeed = false;
|
||||
|
||||
public static int getDefaultSpeed(Object[] speeds, int speed, Object qInterface) {
|
||||
|
||||
@@ -41,7 +41,6 @@ public enum SettingsEnum {
|
||||
ADREMOVER_INFO_PANEL_REMOVAL("revanced_adremover_info_panel", true, ReturnType.BOOLEAN, true),
|
||||
ADREMOVER_MEDICAL_PANEL_REMOVAL("revanced_adremover_medical_panel", true, ReturnType.BOOLEAN, true),
|
||||
ADREMOVER_PAID_CONTECT_REMOVAL("revanced_adremover_paid_content", true, ReturnType.BOOLEAN, true),
|
||||
ADREMOVER_SUGGESTED_FOR_YOU_REMOVAL("revanced_adremover_suggested", true, ReturnType.BOOLEAN, true),
|
||||
ADREMOVER_HIDE_SUGGESTIONS("revanced_adremover_hide_suggestions", true, ReturnType.BOOLEAN, true),
|
||||
ADREMOVER_HIDE_LATEST_POSTS("revanced_adremover_hide_latest_posts", true, ReturnType.BOOLEAN, true),
|
||||
ADREMOVER_HIDE_CHANNEL_GUIDELINES("revanced_adremover_hide_channel_guidelines", true, ReturnType.BOOLEAN, true),
|
||||
@@ -52,12 +51,15 @@ public enum SettingsEnum {
|
||||
BRANDING_SHOWN("revanced_branding_watermark_enabled", false, ReturnType.BOOLEAN),
|
||||
CAST_BUTTON_SHOWN("revanced_cast_button_enabled", false, ReturnType.BOOLEAN, true),
|
||||
AUTOPLAY_BUTTON_SHOWN("revanced_autoplay_button_enabled", false, ReturnType.BOOLEAN, true),
|
||||
//ToDo: Not used atm, Patch missing
|
||||
USE_TABLET_MINIPLAYER("revanced_tablet_miniplayer", false, ReturnType.BOOLEAN, true),
|
||||
CREATE_BUTTON_ENABLED("revanced_create_button_enabled", false, ReturnType.BOOLEAN, true),
|
||||
WIDE_SEARCHBAR("revanced_wide_searchbar", false, ReturnType.BOOLEAN, true),
|
||||
SHORTS_BUTTON_SHOWN("revanced_shorts_button_enabled", false, ReturnType.BOOLEAN, true),
|
||||
FULLSCREEN_PANELS_SHOWN("revanced_fullscreen_panels_enabled", false, ReturnType.BOOLEAN), //ToDo: Add to prefs
|
||||
PLAYER_POPUP_PANELS("revanced_player_popup_panels_enabled", false, ReturnType.BOOLEAN),
|
||||
HIDE_TIME_AND_SEEKBAR("revanced_hide_time_and_seekbar", false, ReturnType.BOOLEAN),
|
||||
HIDE_EMAIL_ADDRESS("revanced_hide_email_address", false, ReturnType.BOOLEAN),
|
||||
DISABLE_STARTUP_SHORTS_PLAYER("revanced_startup_shorts_player_enabled", false, ReturnType.BOOLEAN),
|
||||
|
||||
//Misc. Settings
|
||||
CAPTIONS_ENABLED("revanced_autocaptions_enabled", false, ReturnType.BOOLEAN, false),
|
||||
@@ -249,5 +251,4 @@ public enum SettingsEnum {
|
||||
public boolean shouldRebootOnChange() {
|
||||
return rebootApp;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
package app.revanced.integrations.shared
|
||||
|
||||
import android.app.Activity
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import app.revanced.integrations.utils.ReVancedUtils
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
/**
|
||||
* default implementation of [PlayerControlsVisibilityObserver]
|
||||
*
|
||||
* @param activity activity that contains the controls_layout view
|
||||
*/
|
||||
class PlayerControlsVisibilityObserverImpl(
|
||||
private val activity: Activity
|
||||
) : PlayerControlsVisibilityObserver {
|
||||
|
||||
/**
|
||||
* id of the direct parent of controls_layout, R.id.youtube_controls_overlay
|
||||
*/
|
||||
private val controlsLayoutParentId =
|
||||
ReVancedUtils.getResourceIdByName(activity, "id", "youtube_controls_overlay")
|
||||
|
||||
/**
|
||||
* id of R.id.controls_layout
|
||||
*/
|
||||
private val controlsLayoutId =
|
||||
ReVancedUtils.getResourceIdByName(activity, "id", "controls_layout")
|
||||
|
||||
/**
|
||||
* reference to the controls layout view
|
||||
*/
|
||||
private var controlsLayoutView = WeakReference<View>(null)
|
||||
|
||||
/**
|
||||
* is the [controlsLayoutView] set to a valid reference of a view?
|
||||
*/
|
||||
private val isAttached: Boolean
|
||||
get() {
|
||||
val view = controlsLayoutView.get()
|
||||
return view != null && view.parent != null
|
||||
}
|
||||
|
||||
/**
|
||||
* find and attach the controls_layout view if needed
|
||||
*/
|
||||
private fun maybeAttach() {
|
||||
if (isAttached) return
|
||||
|
||||
// find parent, then controls_layout view
|
||||
// this is needed because there may be two views where id=R.id.controls_layout
|
||||
// because why should google confine themselves to their own guidelines...
|
||||
activity.findViewById<ViewGroup>(controlsLayoutParentId)?.let { parent ->
|
||||
parent.findViewById<View>(controlsLayoutId)?.let {
|
||||
controlsLayoutView = WeakReference(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val playerControlsVisibility: Int
|
||||
get() {
|
||||
maybeAttach()
|
||||
return controlsLayoutView.get()?.visibility ?: View.GONE
|
||||
}
|
||||
|
||||
override val arePlayerControlsVisible: Boolean
|
||||
get() = playerControlsVisibility == View.VISIBLE
|
||||
}
|
||||
|
||||
/**
|
||||
* provides the visibility status of the fullscreen player controls_layout view.
|
||||
* this can be used for detecting when the player controls are shown
|
||||
*/
|
||||
interface PlayerControlsVisibilityObserver {
|
||||
/**
|
||||
* current visibility int of the controls_layout view
|
||||
*/
|
||||
val playerControlsVisibility: Int
|
||||
|
||||
/**
|
||||
* is the value of [playerControlsVisibility] equal to [View.VISIBLE]?
|
||||
*/
|
||||
val arePlayerControlsVisible: Boolean
|
||||
}
|
||||
@@ -49,6 +49,8 @@ public class PlayerController {
|
||||
private static float sponsorBarThickness = 2f;
|
||||
private static TimerTask skipSponsorTask = null;
|
||||
|
||||
public static boolean shorts_playing = false;
|
||||
|
||||
public static String getCurrentVideoId() {
|
||||
return currentVideoId;
|
||||
}
|
||||
@@ -87,7 +89,6 @@ public class PlayerController {
|
||||
* Called when creating some kind of youtube internal player controlled, every time when new video starts to play
|
||||
*/
|
||||
public static void onCreate(final Object o) {
|
||||
// "Plugin.printStackTrace();
|
||||
|
||||
if (o == null) {
|
||||
LogHelper.printException(PlayerController.class, "onCreate called with null object");
|
||||
@@ -115,8 +116,9 @@ public class PlayerController {
|
||||
public static void executeDownloadSegments(String videoId) {
|
||||
videoHasSegments = false;
|
||||
timeWithoutSegments = "";
|
||||
if (Whitelist.isChannelSBWhitelisted())
|
||||
if (Whitelist.isChannelSBWhitelisted() || shorts_playing) {
|
||||
return;
|
||||
}
|
||||
SponsorSegment[] segments = SBRequester.getSegments(videoId);
|
||||
Arrays.sort(segments);
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import android.widget.RelativeLayout;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import app.revanced.integrations.settings.SettingsEnum;
|
||||
import app.revanced.integrations.sponsorblock.player.PlayerType;
|
||||
import app.revanced.integrations.utils.LogHelper;
|
||||
import app.revanced.integrations.utils.ReVancedUtils;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package app.revanced.integrations.swipecontrols
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.KeyEvent
|
||||
import android.view.MotionEvent
|
||||
@@ -10,8 +11,9 @@ import app.revanced.integrations.swipecontrols.controller.AudioVolumeController
|
||||
import app.revanced.integrations.swipecontrols.controller.ScreenBrightnessController
|
||||
import app.revanced.integrations.swipecontrols.controller.SwipeZonesController
|
||||
import app.revanced.integrations.swipecontrols.controller.VolumeKeysController
|
||||
import app.revanced.integrations.swipecontrols.controller.gesture.NoPtSSwipeGestureController
|
||||
import app.revanced.integrations.swipecontrols.controller.gesture.SwipeGestureController
|
||||
import app.revanced.integrations.swipecontrols.controller.gesture.ClassicSwipeController
|
||||
import app.revanced.integrations.swipecontrols.controller.gesture.PressToSwipeController
|
||||
import app.revanced.integrations.swipecontrols.controller.gesture.core.GestureController
|
||||
import app.revanced.integrations.swipecontrols.misc.Rectangle
|
||||
import app.revanced.integrations.swipecontrols.views.SwipeControlsOverlayLayout
|
||||
import app.revanced.integrations.utils.LogHelper
|
||||
@@ -52,7 +54,7 @@ class SwipeControlsHostActivity : Activity() {
|
||||
/**
|
||||
* main gesture controller
|
||||
*/
|
||||
private lateinit var gesture: SwipeGestureController
|
||||
private lateinit var gesture: GestureController
|
||||
|
||||
/**
|
||||
* main volume keys controller
|
||||
@@ -67,17 +69,66 @@ class SwipeControlsHostActivity : Activity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
initialize()
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
reAttachOverlays()
|
||||
}
|
||||
|
||||
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
|
||||
ensureInitialized()
|
||||
return if ((ev != null) && gesture.submitTouchEvent(ev)) true else {
|
||||
super.dispatchTouchEvent(ev)
|
||||
}
|
||||
}
|
||||
|
||||
override fun dispatchKeyEvent(ev: KeyEvent?): Boolean {
|
||||
ensureInitialized()
|
||||
return if ((ev != null) && keys.onKeyEvent(ev)) true else {
|
||||
super.dispatchKeyEvent(ev)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dispatch a touch event to downstream views
|
||||
*
|
||||
* @param event the event to dispatch
|
||||
* @return was the event consumed?
|
||||
*/
|
||||
fun dispatchDownstreamTouchEvent(event: MotionEvent) =
|
||||
super.dispatchTouchEvent(event)
|
||||
|
||||
/**
|
||||
* ensures that swipe controllers are initialized and attached.
|
||||
* on some ROMs with SDK <= 23, [onCreate] and [onStart] may not be called correctly.
|
||||
* see https://github.com/revanced/revanced-patches/issues/446
|
||||
*/
|
||||
private fun ensureInitialized() {
|
||||
if (!this::config.isInitialized) {
|
||||
LogHelper.printException(
|
||||
this.javaClass,
|
||||
"swipe controls were not initialized in onCreate, initializing on-the-fly (SDK is ${Build.VERSION.SDK_INT})"
|
||||
)
|
||||
initialize()
|
||||
reAttachOverlays()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* initializes controllers, only call once
|
||||
*/
|
||||
private fun initialize() {
|
||||
// create controllers
|
||||
LogHelper.info(this.javaClass, "initializing swipe controls controllers")
|
||||
config = SwipeControlsConfigurationProvider(this)
|
||||
gesture = createGestureController()
|
||||
keys = VolumeKeysController(this)
|
||||
audio = createAudioController()
|
||||
screen = createScreenController()
|
||||
|
||||
// create overlay
|
||||
SwipeControlsOverlayLayout(this).let {
|
||||
SwipeControlsOverlayLayout(this, config).let {
|
||||
overlay = it
|
||||
contentRoot.addView(it)
|
||||
}
|
||||
@@ -92,6 +143,9 @@ class SwipeControlsHostActivity : Activity() {
|
||||
)
|
||||
}
|
||||
|
||||
// create the gesture controller
|
||||
gesture = createGestureController()
|
||||
|
||||
// listen for changes in the player type
|
||||
PlayerType.onChange += this::onPlayerTypeChanged
|
||||
|
||||
@@ -99,36 +153,15 @@ class SwipeControlsHostActivity : Activity() {
|
||||
currentHost = WeakReference(this)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
|
||||
// (re) attach overlay
|
||||
/**
|
||||
* (re) attaches swipe overlays
|
||||
*/
|
||||
private fun reAttachOverlays() {
|
||||
LogHelper.info(this.javaClass, "attaching swipe controls overlay")
|
||||
contentRoot.removeView(overlay)
|
||||
contentRoot.addView(overlay)
|
||||
}
|
||||
|
||||
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
|
||||
return if ((ev != null) && gesture.onTouchEvent(ev)) true else {
|
||||
super.dispatchTouchEvent(ev)
|
||||
}
|
||||
}
|
||||
|
||||
override fun dispatchKeyEvent(ev: KeyEvent?): Boolean {
|
||||
return if((ev != null) && keys.onKeyEvent(ev)) true else {
|
||||
super.dispatchKeyEvent(ev)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dispatch a touch event to downstream views
|
||||
*
|
||||
* @param event the event to dispatch
|
||||
* @return was the event consumed?
|
||||
*/
|
||||
fun dispatchDownstreamTouchEvent(event: MotionEvent) =
|
||||
super.dispatchTouchEvent(event)
|
||||
|
||||
/**
|
||||
* called when the player type changes
|
||||
*
|
||||
@@ -163,8 +196,8 @@ class SwipeControlsHostActivity : Activity() {
|
||||
*/
|
||||
private fun createGestureController() =
|
||||
if (config.shouldEnablePressToSwipe)
|
||||
SwipeGestureController(this)
|
||||
else NoPtSSwipeGestureController(this)
|
||||
PressToSwipeController(this)
|
||||
else ClassicSwipeController(this)
|
||||
|
||||
companion object {
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
package app.revanced.integrations.swipecontrols.controller.gesture
|
||||
|
||||
import android.view.MotionEvent
|
||||
import app.revanced.integrations.shared.PlayerControlsVisibilityObserver
|
||||
import app.revanced.integrations.shared.PlayerControlsVisibilityObserverImpl
|
||||
import app.revanced.integrations.swipecontrols.SwipeControlsHostActivity
|
||||
import app.revanced.integrations.swipecontrols.controller.gesture.core.BaseGestureController
|
||||
import app.revanced.integrations.swipecontrols.controller.gesture.core.SwipeDetector
|
||||
import app.revanced.integrations.swipecontrols.misc.contains
|
||||
import app.revanced.integrations.swipecontrols.misc.toPoint
|
||||
|
||||
/**
|
||||
* provides the classic swipe controls experience, as it was with 'XFenster'
|
||||
*
|
||||
* @param controller reference to the main swipe controller
|
||||
*/
|
||||
class ClassicSwipeController(
|
||||
private val controller: SwipeControlsHostActivity
|
||||
) : BaseGestureController(controller),
|
||||
PlayerControlsVisibilityObserver by PlayerControlsVisibilityObserverImpl(controller) {
|
||||
/**
|
||||
* the last event captured in [onDown]
|
||||
*/
|
||||
private var lastOnDownEvent: MotionEvent? = null
|
||||
|
||||
override val shouldForceInterceptEvents: Boolean
|
||||
get() = currentSwipe == SwipeDetector.SwipeDirection.VERTICAL
|
||||
|
||||
override fun isInSwipeZone(motionEvent: MotionEvent): Boolean {
|
||||
val inVolumeZone = if (controller.config.enableVolumeControls)
|
||||
(motionEvent.toPoint() in controller.zones.volume) else false
|
||||
val inBrightnessZone = if (controller.config.enableBrightnessControl)
|
||||
(motionEvent.toPoint() in controller.zones.brightness) else false
|
||||
|
||||
return inVolumeZone || inBrightnessZone
|
||||
}
|
||||
|
||||
override fun shouldDropMotion(motionEvent: MotionEvent): Boolean {
|
||||
// ignore gestures with more than one pointer
|
||||
// when such a gesture is detected, dispatch the first event of the gesture to downstream
|
||||
if (motionEvent.pointerCount > 1) {
|
||||
lastOnDownEvent?.let {
|
||||
controller.dispatchDownstreamTouchEvent(it)
|
||||
it.recycle()
|
||||
}
|
||||
lastOnDownEvent = null
|
||||
return true
|
||||
}
|
||||
|
||||
// ignore gestures when player controls are visible
|
||||
return arePlayerControlsVisible
|
||||
}
|
||||
|
||||
override fun onDown(motionEvent: MotionEvent): Boolean {
|
||||
// save the event for later
|
||||
lastOnDownEvent?.recycle()
|
||||
lastOnDownEvent = MotionEvent.obtain(motionEvent)
|
||||
|
||||
// must be inside swipe zone
|
||||
return isInSwipeZone(motionEvent)
|
||||
}
|
||||
|
||||
override fun onSingleTapUp(motionEvent: MotionEvent): Boolean {
|
||||
MotionEvent.obtain(motionEvent).let {
|
||||
it.action = MotionEvent.ACTION_DOWN
|
||||
controller.dispatchDownstreamTouchEvent(it)
|
||||
it.recycle()
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onDoubleTapEvent(motionEvent: MotionEvent?): Boolean {
|
||||
MotionEvent.obtain(motionEvent).let {
|
||||
controller.dispatchDownstreamTouchEvent(it)
|
||||
it.recycle()
|
||||
}
|
||||
|
||||
return super.onDoubleTapEvent(motionEvent)
|
||||
}
|
||||
|
||||
override fun onLongPress(motionEvent: MotionEvent?) {
|
||||
MotionEvent.obtain(motionEvent).let {
|
||||
controller.dispatchDownstreamTouchEvent(it)
|
||||
it.recycle()
|
||||
}
|
||||
|
||||
super.onLongPress(motionEvent)
|
||||
}
|
||||
|
||||
override fun onSwipe(
|
||||
from: MotionEvent,
|
||||
to: MotionEvent,
|
||||
distanceX: Double,
|
||||
distanceY: Double
|
||||
): Boolean {
|
||||
// cancel if not vertical
|
||||
if (currentSwipe != SwipeDetector.SwipeDirection.VERTICAL) return false
|
||||
return when (from.toPoint()) {
|
||||
in controller.zones.volume -> {
|
||||
scrollVolume(distanceY)
|
||||
true
|
||||
}
|
||||
in controller.zones.brightness -> {
|
||||
scrollBrightness(distanceY)
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package app.revanced.integrations.swipecontrols.controller.gesture
|
||||
|
||||
import android.view.MotionEvent
|
||||
import app.revanced.integrations.swipecontrols.SwipeControlsHostActivity
|
||||
|
||||
/**
|
||||
* [SwipeGestureController], but with press-to-swipe disabled because a lot of people dislike the feature.
|
||||
* If you want to change something, try to do it in [SwipeGestureController] so that both configurations can benefit from it
|
||||
*/
|
||||
class NoPtSSwipeGestureController(controller: SwipeControlsHostActivity) :
|
||||
SwipeGestureController(controller) {
|
||||
|
||||
/**
|
||||
* to disable press-to-swipe, we have to become press-to-swipe
|
||||
*/
|
||||
override var inSwipeSession
|
||||
get() = true
|
||||
set(_) {}
|
||||
|
||||
override fun onLongPress(e: MotionEvent?) {
|
||||
if (e == null) return
|
||||
|
||||
// send GestureDetector a ACTION_CANCEL event so it will handle further events
|
||||
// if this is left out, swipe-to-dismiss is triggered when scrolling down
|
||||
e.action = MotionEvent.ACTION_CANCEL
|
||||
detector.onTouchEvent(e)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package app.revanced.integrations.swipecontrols.controller.gesture
|
||||
|
||||
import android.view.MotionEvent
|
||||
import app.revanced.integrations.swipecontrols.SwipeControlsHostActivity
|
||||
import app.revanced.integrations.swipecontrols.controller.gesture.core.BaseGestureController
|
||||
import app.revanced.integrations.swipecontrols.controller.gesture.core.SwipeDetector
|
||||
import app.revanced.integrations.swipecontrols.misc.contains
|
||||
import app.revanced.integrations.swipecontrols.misc.toPoint
|
||||
|
||||
/**
|
||||
* provides the press-to-swipe (PtS) swipe controls experience
|
||||
*
|
||||
* @param controller reference to the main swipe controller
|
||||
*/
|
||||
class PressToSwipeController(
|
||||
private val controller: SwipeControlsHostActivity
|
||||
) : BaseGestureController(controller) {
|
||||
/**
|
||||
* monitors if the user is currently in a swipe session.
|
||||
*/
|
||||
private var isInSwipeSession = false
|
||||
|
||||
override val shouldForceInterceptEvents: Boolean
|
||||
get() = currentSwipe == SwipeDetector.SwipeDirection.VERTICAL && isInSwipeSession
|
||||
|
||||
override fun shouldDropMotion(motionEvent: MotionEvent): Boolean = false
|
||||
|
||||
override fun isInSwipeZone(motionEvent: MotionEvent): Boolean {
|
||||
val inVolumeZone = if (controller.config.enableVolumeControls)
|
||||
(motionEvent.toPoint() in controller.zones.volume) else false
|
||||
val inBrightnessZone = if (controller.config.enableBrightnessControl)
|
||||
(motionEvent.toPoint() in controller.zones.brightness) else false
|
||||
|
||||
return inVolumeZone || inBrightnessZone
|
||||
}
|
||||
|
||||
override fun onUp(motionEvent: MotionEvent) {
|
||||
super.onUp(motionEvent)
|
||||
isInSwipeSession = false
|
||||
}
|
||||
|
||||
override fun onLongPress(motionEvent: MotionEvent) {
|
||||
// enter swipe session with feedback
|
||||
isInSwipeSession = true
|
||||
controller.overlay.onEnterSwipeSession()
|
||||
|
||||
// send GestureDetector a ACTION_CANCEL event so it will handle further events
|
||||
motionEvent.action = MotionEvent.ACTION_CANCEL
|
||||
detector.onTouchEvent(motionEvent)
|
||||
}
|
||||
|
||||
override fun onSwipe(
|
||||
from: MotionEvent,
|
||||
to: MotionEvent,
|
||||
distanceX: Double,
|
||||
distanceY: Double
|
||||
): Boolean {
|
||||
// cancel if not in swipe session or vertical
|
||||
if (!isInSwipeSession || currentSwipe != SwipeDetector.SwipeDirection.VERTICAL) return false
|
||||
return when (from.toPoint()) {
|
||||
in controller.zones.volume -> {
|
||||
scrollVolume(distanceY)
|
||||
true
|
||||
}
|
||||
in controller.zones.brightness -> {
|
||||
scrollBrightness(distanceY)
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,232 +0,0 @@
|
||||
package app.revanced.integrations.swipecontrols.controller.gesture
|
||||
|
||||
import android.util.TypedValue
|
||||
import android.view.GestureDetector
|
||||
import android.view.MotionEvent
|
||||
import app.revanced.integrations.swipecontrols.SwipeControlsHostActivity
|
||||
import app.revanced.integrations.swipecontrols.misc.ScrollDistanceHelper
|
||||
import app.revanced.integrations.swipecontrols.misc.applyDimension
|
||||
import app.revanced.integrations.swipecontrols.misc.contains
|
||||
import app.revanced.integrations.swipecontrols.misc.toPoint
|
||||
import app.revanced.integrations.utils.LogHelper
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.pow
|
||||
|
||||
/**
|
||||
* base gesture controller for volume and brightness swipe controls controls, with press-to-swipe enabled
|
||||
* for the controller without press-to-swipe, see [NoPtSSwipeGestureController]
|
||||
*
|
||||
* @param controller reference to main controller instance
|
||||
*/
|
||||
@Suppress("LeakingThis")
|
||||
open class SwipeGestureController(
|
||||
private val controller: SwipeControlsHostActivity
|
||||
) :
|
||||
GestureDetector.SimpleOnGestureListener() {
|
||||
|
||||
/**
|
||||
* the main gesture detector that powers everything
|
||||
*/
|
||||
protected open val detector = GestureDetector(controller, this)
|
||||
|
||||
/**
|
||||
* to enable swipe controls, users must first long- press. this flags monitors that long- press
|
||||
* NOTE: if you dislike press-to-swipe, and want it disabled, have a look at [NoPtSSwipeGestureController]. it does exactly that
|
||||
*/
|
||||
protected open var inSwipeSession = true
|
||||
|
||||
/**
|
||||
* currently in- progress swipe
|
||||
*/
|
||||
protected open var currentSwipe: SwipeDirection = SwipeDirection.NONE
|
||||
|
||||
/**
|
||||
* were downstream event cancelled already? used by [onScroll]
|
||||
*/
|
||||
protected open var didCancelDownstream = false
|
||||
|
||||
/**
|
||||
* should [onTouchEvent] force- intercept all touch events?
|
||||
*/
|
||||
protected open val shouldForceInterceptEvents: Boolean
|
||||
get() = currentSwipe == SwipeDirection.VERTICAL && inSwipeSession
|
||||
|
||||
/**
|
||||
* scroller for volume adjustment
|
||||
*/
|
||||
protected open val volumeScroller = ScrollDistanceHelper(
|
||||
10.applyDimension(
|
||||
controller,
|
||||
TypedValue.COMPLEX_UNIT_DIP
|
||||
)
|
||||
) { _, _, direction ->
|
||||
controller.audio?.apply {
|
||||
volume += direction
|
||||
controller.overlay.onVolumeChanged(volume, maxVolume)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* scroller for screen brightness adjustment
|
||||
*/
|
||||
protected open val brightnessScroller = ScrollDistanceHelper(
|
||||
1.applyDimension(
|
||||
controller,
|
||||
TypedValue.COMPLEX_UNIT_DIP
|
||||
)
|
||||
) { _, _, direction ->
|
||||
controller.screen?.apply {
|
||||
if (screenBrightness > 0 || direction > 0) {
|
||||
screenBrightness += direction
|
||||
} else {
|
||||
restoreDefaultBrightness()
|
||||
}
|
||||
|
||||
controller.overlay.onBrightnessChanged(screenBrightness)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* touch event callback
|
||||
*
|
||||
* @param motionEvent the motion event that was received
|
||||
* @return intercept the event? if true, child views will not receive the event
|
||||
*/
|
||||
fun onTouchEvent(motionEvent: MotionEvent): Boolean {
|
||||
if (!controller.config.enableSwipeControls) {
|
||||
return false
|
||||
}
|
||||
if (motionEvent.action == MotionEvent.ACTION_UP) {
|
||||
onUp(motionEvent)
|
||||
}
|
||||
|
||||
return if (shouldForceInterceptEvents || inSwipeZone(motionEvent)) {
|
||||
detector.onTouchEvent(motionEvent) or shouldForceInterceptEvents
|
||||
} else false
|
||||
}
|
||||
|
||||
/**
|
||||
* check if provided motion event is in any active swipe zone?
|
||||
*
|
||||
* @param e the event to check
|
||||
* @return is the event in any active swipe zone?
|
||||
*/
|
||||
open fun inSwipeZone(e: MotionEvent): Boolean {
|
||||
val inVolumeZone = if (controller.config.enableVolumeControls)
|
||||
(e.toPoint() in controller.zones.volume) else false
|
||||
val inBrightnessZone = if (controller.config.enableBrightnessControl)
|
||||
(e.toPoint() in controller.zones.brightness) else false
|
||||
|
||||
return inVolumeZone || inBrightnessZone
|
||||
}
|
||||
|
||||
/**
|
||||
* custom handler for ACTION_UP event, because GestureDetector doesn't offer that :|
|
||||
* basically just resets all flags to non- swiping values
|
||||
*
|
||||
* @param e the motion event
|
||||
*/
|
||||
open fun onUp(e: MotionEvent) {
|
||||
LogHelper.debug(this.javaClass, "onUp(${e.x}, ${e.y}, ${e.action})")
|
||||
inSwipeSession = false
|
||||
currentSwipe = SwipeDirection.NONE
|
||||
didCancelDownstream = false
|
||||
volumeScroller.reset()
|
||||
brightnessScroller.reset()
|
||||
}
|
||||
|
||||
override fun onLongPress(e: MotionEvent?) {
|
||||
if (e == null) return
|
||||
LogHelper.debug(this.javaClass, "onLongPress(${e.x}, ${e.y}, ${e.action})")
|
||||
|
||||
// enter swipe session with feedback
|
||||
inSwipeSession = true
|
||||
controller.overlay.onEnterSwipeSession()
|
||||
|
||||
// send GestureDetector a ACTION_CANCEL event so it will handle further events
|
||||
e.action = MotionEvent.ACTION_CANCEL
|
||||
detector.onTouchEvent(e)
|
||||
}
|
||||
|
||||
override fun onScroll(
|
||||
eFrom: MotionEvent?,
|
||||
eTo: MotionEvent?,
|
||||
disX: Float,
|
||||
disY: Float
|
||||
): Boolean {
|
||||
if (eFrom == null || eTo == null) return false
|
||||
LogHelper.debug(
|
||||
this.javaClass,
|
||||
"onScroll(from: [${eFrom.x}, ${eFrom.y}, ${eFrom.action}], to: [${eTo.x}, ${eTo.y}, ${eTo.action}], d: [$disX, $disY])"
|
||||
)
|
||||
|
||||
return when (currentSwipe) {
|
||||
// no swipe direction was detected yet, try to detect one
|
||||
// if the user did not swipe far enough, we cannot detect what direction they swiped
|
||||
// so we wait until a greater distance was swiped
|
||||
// NOTE: sqrt() can be high- cost, so using squared magnitudes here
|
||||
SwipeDirection.NONE -> {
|
||||
val deltaX = abs(eTo.x - eFrom.x)
|
||||
val deltaY = abs(eTo.y - eFrom.y)
|
||||
val swipeMagnitudeSquared = deltaX.pow(2) + deltaY.pow(2)
|
||||
if (swipeMagnitudeSquared > controller.config.swipeMagnitudeThreshold.pow(2)) {
|
||||
currentSwipe = if (deltaY > deltaX) {
|
||||
SwipeDirection.VERTICAL
|
||||
} else {
|
||||
SwipeDirection.HORIZONTAL
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// horizontal swipe, we should leave this one for downstream to handle
|
||||
SwipeDirection.HORIZONTAL -> false
|
||||
|
||||
// vertical swipe, could be for us
|
||||
SwipeDirection.VERTICAL -> {
|
||||
if (!inSwipeSession) {
|
||||
// not in swipe session, let downstream handle this one
|
||||
return false
|
||||
}
|
||||
|
||||
// vertical & in swipe session, handle this one:
|
||||
// first, send ACTION_CANCEL to downstream to let them known they should stop tracking events
|
||||
if (!didCancelDownstream) {
|
||||
val eCancel = MotionEvent.obtain(eFrom)
|
||||
eCancel.action = MotionEvent.ACTION_CANCEL
|
||||
controller.dispatchDownstreamTouchEvent(eCancel)
|
||||
eCancel.recycle()
|
||||
didCancelDownstream = true
|
||||
}
|
||||
|
||||
// then, process the event
|
||||
when (eFrom.toPoint()) {
|
||||
in controller.zones.volume -> volumeScroller.add(disY.toDouble())
|
||||
in controller.zones.brightness -> brightnessScroller.add(disY.toDouble())
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* direction of a swipe
|
||||
*/
|
||||
enum class SwipeDirection {
|
||||
/**
|
||||
* swipe has no direction or no swipe
|
||||
*/
|
||||
NONE,
|
||||
|
||||
/**
|
||||
* swipe along the X- Axes
|
||||
*/
|
||||
HORIZONTAL,
|
||||
|
||||
/**
|
||||
* swipe along the Y- Axes
|
||||
*/
|
||||
VERTICAL
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
package app.revanced.integrations.swipecontrols.controller.gesture.core
|
||||
|
||||
import android.view.GestureDetector
|
||||
import android.view.MotionEvent
|
||||
import app.revanced.integrations.swipecontrols.SwipeControlsHostActivity
|
||||
|
||||
/**
|
||||
* the common base of all [GestureController] classes.
|
||||
* handles most of the boilerplate code needed for gesture detection
|
||||
*
|
||||
* @param controller reference to the main swipe controller
|
||||
*/
|
||||
abstract class BaseGestureController(
|
||||
private val controller: SwipeControlsHostActivity
|
||||
) : GestureController,
|
||||
GestureDetector.SimpleOnGestureListener(),
|
||||
SwipeDetector by SwipeDetectorImpl(
|
||||
controller.config.swipeMagnitudeThreshold.toDouble()
|
||||
),
|
||||
VolumeAndBrightnessScroller by VolumeAndBrightnessScrollerImpl(
|
||||
controller,
|
||||
controller.audio,
|
||||
controller.screen,
|
||||
controller.overlay,
|
||||
10,
|
||||
1
|
||||
) {
|
||||
|
||||
/**
|
||||
* the main gesture detector that powers everything
|
||||
*/
|
||||
@Suppress("LeakingThis")
|
||||
protected val detector = GestureDetector(controller, this)
|
||||
|
||||
/**
|
||||
* were downstream event cancelled already? used in [onScroll]
|
||||
*/
|
||||
private var didCancelDownstream = false
|
||||
|
||||
override fun submitTouchEvent(motionEvent: MotionEvent): Boolean {
|
||||
// ignore if swipe is disabled
|
||||
if (!controller.config.enableSwipeControls) {
|
||||
return false
|
||||
}
|
||||
|
||||
// create a copy of the event so we can modify it
|
||||
// without causing any issues downstream
|
||||
val me = MotionEvent.obtain(motionEvent)
|
||||
|
||||
// check if we should drop this motion
|
||||
val dropped = shouldDropMotion(me)
|
||||
if (dropped) {
|
||||
me.action = MotionEvent.ACTION_CANCEL
|
||||
}
|
||||
|
||||
// send the event to the detector
|
||||
// if we force intercept events, the event is always consumed
|
||||
val consumed = detector.onTouchEvent(me) || shouldForceInterceptEvents
|
||||
|
||||
// invoke the custom onUp handler
|
||||
if (me.action == MotionEvent.ACTION_UP || me.action == MotionEvent.ACTION_CANCEL) {
|
||||
onUp(me)
|
||||
}
|
||||
|
||||
// recycle the copy
|
||||
me.recycle()
|
||||
|
||||
// do not consume dropped events
|
||||
// or events outside of any swipe zone
|
||||
return !dropped && consumed && isInSwipeZone(me)
|
||||
}
|
||||
|
||||
/**
|
||||
* custom handler for [MotionEvent.ACTION_UP] event, because GestureDetector doesn't offer that :|
|
||||
*
|
||||
* @param motionEvent the motion event
|
||||
*/
|
||||
open fun onUp(motionEvent: MotionEvent) {
|
||||
didCancelDownstream = false
|
||||
resetSwipe()
|
||||
resetScroller()
|
||||
}
|
||||
|
||||
override fun onScroll(
|
||||
from: MotionEvent,
|
||||
to: MotionEvent,
|
||||
distanceX: Float,
|
||||
distanceY: Float
|
||||
): Boolean {
|
||||
// submit to swipe detector
|
||||
submitForSwipe(from, to, distanceX, distanceY)
|
||||
|
||||
// call swipe callback if in a swipe
|
||||
return if (currentSwipe != SwipeDetector.SwipeDirection.NONE) {
|
||||
val consumed = onSwipe(
|
||||
from,
|
||||
to,
|
||||
distanceX.toDouble(),
|
||||
distanceY.toDouble()
|
||||
)
|
||||
|
||||
// if the swipe was consumed, cancel downstream events once
|
||||
if (consumed && !didCancelDownstream) {
|
||||
didCancelDownstream = true
|
||||
MotionEvent.obtain(from).let {
|
||||
it.action = MotionEvent.ACTION_CANCEL
|
||||
controller.dispatchDownstreamTouchEvent(it)
|
||||
it.recycle()
|
||||
}
|
||||
}
|
||||
|
||||
consumed
|
||||
} else false
|
||||
}
|
||||
|
||||
/**
|
||||
* should [submitTouchEvent] force- intercept all touch events?
|
||||
*/
|
||||
abstract val shouldForceInterceptEvents: Boolean
|
||||
|
||||
/**
|
||||
* check if provided motion event is in any active swipe zone?
|
||||
*
|
||||
* @param motionEvent the event to check
|
||||
* @return is the event in any active swipe zone?
|
||||
*/
|
||||
abstract fun isInSwipeZone(motionEvent: MotionEvent): Boolean
|
||||
|
||||
/**
|
||||
* check if a touch event should be dropped.
|
||||
* when a event is dropped, the gesture detector received a [MotionEvent.ACTION_CANCEL] event and the event is not consumed
|
||||
*
|
||||
* @param motionEvent the event to check
|
||||
* @return should the event be dropped?
|
||||
*/
|
||||
abstract fun shouldDropMotion(motionEvent: MotionEvent): Boolean
|
||||
|
||||
/**
|
||||
* handler for swipe events, once a swipe is detected.
|
||||
* the direction of the swipe can be accessed in [currentSwipe]
|
||||
*
|
||||
* @param from start event of the swipe
|
||||
* @param to end event of the swipe
|
||||
* @param distanceX the horizontal distance of the swipe
|
||||
* @param distanceY the vertical distance of the swipe
|
||||
* @return was the event consumed?
|
||||
*/
|
||||
abstract fun onSwipe(
|
||||
from: MotionEvent,
|
||||
to: MotionEvent,
|
||||
distanceX: Double,
|
||||
distanceY: Double
|
||||
): Boolean
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package app.revanced.integrations.swipecontrols.controller.gesture.core
|
||||
|
||||
import android.view.MotionEvent
|
||||
|
||||
/**
|
||||
* describes a class that accepts motion events and detects gestures
|
||||
*/
|
||||
interface GestureController {
|
||||
/**
|
||||
* accept a touch event and try to detect the desired gestures using it
|
||||
*
|
||||
* @param motionEvent the motion event that was submitted
|
||||
* @return was a gesture detected?
|
||||
*/
|
||||
fun submitTouchEvent(motionEvent: MotionEvent): Boolean
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package app.revanced.integrations.swipecontrols.controller.gesture.core
|
||||
|
||||
import android.view.MotionEvent
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.pow
|
||||
|
||||
/**
|
||||
* describes a class that can detect swipes and their directionality
|
||||
*/
|
||||
interface SwipeDetector {
|
||||
/**
|
||||
* the currently detected swipe
|
||||
*/
|
||||
val currentSwipe: SwipeDirection
|
||||
|
||||
/**
|
||||
* submit a onScroll event for swipe detection
|
||||
*
|
||||
* @param from start event
|
||||
* @param to end event
|
||||
* @param distanceX horizontal scroll distance
|
||||
* @param distanceY vertical scroll distance
|
||||
*/
|
||||
fun submitForSwipe(
|
||||
from: MotionEvent,
|
||||
to: MotionEvent,
|
||||
distanceX: Float,
|
||||
distanceY: Float
|
||||
)
|
||||
|
||||
/**
|
||||
* reset the swipe detection
|
||||
*/
|
||||
fun resetSwipe()
|
||||
|
||||
/**
|
||||
* direction of a swipe
|
||||
*/
|
||||
enum class SwipeDirection {
|
||||
/**
|
||||
* swipe has no direction or no swipe
|
||||
*/
|
||||
NONE,
|
||||
|
||||
/**
|
||||
* swipe along the X- Axes
|
||||
*/
|
||||
HORIZONTAL,
|
||||
|
||||
/**
|
||||
* swipe along the Y- Axes
|
||||
*/
|
||||
VERTICAL
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* detector that can detect swipes and their directionality
|
||||
*
|
||||
* @param swipeMagnitudeThreshold minimum magnitude before a swipe is detected as such
|
||||
*/
|
||||
class SwipeDetectorImpl(
|
||||
private val swipeMagnitudeThreshold: Double
|
||||
) : SwipeDetector {
|
||||
override var currentSwipe = SwipeDetector.SwipeDirection.NONE
|
||||
|
||||
override fun submitForSwipe(
|
||||
from: MotionEvent,
|
||||
to: MotionEvent,
|
||||
distanceX: Float,
|
||||
distanceY: Float
|
||||
) {
|
||||
if (currentSwipe == SwipeDetector.SwipeDirection.NONE) {
|
||||
// no swipe direction was detected yet, try to detect one
|
||||
// if the user did not swipe far enough, we cannot detect what direction they swiped
|
||||
// so we wait until a greater distance was swiped
|
||||
// NOTE: sqrt() can be high- cost, so using squared magnitudes here
|
||||
val deltaX = abs(to.x - from.x)
|
||||
val deltaY = abs(to.y - from.y)
|
||||
val swipeMagnitudeSquared = deltaX.pow(2) + deltaY.pow(2)
|
||||
if (swipeMagnitudeSquared > swipeMagnitudeThreshold.pow(2)) {
|
||||
currentSwipe = if (deltaY > deltaX) {
|
||||
SwipeDetector.SwipeDirection.VERTICAL
|
||||
} else {
|
||||
SwipeDetector.SwipeDirection.HORIZONTAL
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun resetSwipe() {
|
||||
currentSwipe = SwipeDetector.SwipeDirection.NONE
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package app.revanced.integrations.swipecontrols.controller.gesture.core
|
||||
|
||||
import android.content.Context
|
||||
import android.util.TypedValue
|
||||
import app.revanced.integrations.swipecontrols.controller.AudioVolumeController
|
||||
import app.revanced.integrations.swipecontrols.controller.ScreenBrightnessController
|
||||
import app.revanced.integrations.swipecontrols.misc.ScrollDistanceHelper
|
||||
import app.revanced.integrations.swipecontrols.misc.SwipeControlsOverlay
|
||||
import app.revanced.integrations.swipecontrols.misc.applyDimension
|
||||
|
||||
/**
|
||||
* describes a class that controls volume and brightness based on scrolling events
|
||||
*/
|
||||
interface VolumeAndBrightnessScroller {
|
||||
/**
|
||||
* submit a scroll for volume adjustment
|
||||
*
|
||||
* @param distance the scroll distance
|
||||
*/
|
||||
fun scrollVolume(distance: Double)
|
||||
|
||||
/**
|
||||
* submit a scroll for brightness adjustment
|
||||
*
|
||||
* @param distance the scroll distance
|
||||
*/
|
||||
fun scrollBrightness(distance: Double)
|
||||
|
||||
/**
|
||||
* reset all scroll distances to zero
|
||||
*/
|
||||
fun resetScroller()
|
||||
}
|
||||
|
||||
/**
|
||||
* handles scrolling of volume and brightness, adjusts them using the provided controllers and updates the overlay
|
||||
*
|
||||
* @param context context to create the scrollers in
|
||||
* @param volumeController volume controller instance. if null, volume control is disabled
|
||||
* @param screenController screen brightness controller instance. if null, brightness control is disabled
|
||||
* @param overlayController overlay controller instance
|
||||
* @param volumeDistance unit distance for volume scrolling, in dp
|
||||
* @param brightnessDistance unit distance for brightness scrolling, in dp
|
||||
*/
|
||||
class VolumeAndBrightnessScrollerImpl(
|
||||
context: Context,
|
||||
private val volumeController: AudioVolumeController?,
|
||||
private val screenController: ScreenBrightnessController?,
|
||||
private val overlayController: SwipeControlsOverlay,
|
||||
volumeDistance: Int = 10,
|
||||
brightnessDistance: Int = 1
|
||||
) : VolumeAndBrightnessScroller {
|
||||
|
||||
// region volume
|
||||
private val volumeScroller =
|
||||
ScrollDistanceHelper(
|
||||
volumeDistance.applyDimension(
|
||||
context,
|
||||
TypedValue.COMPLEX_UNIT_DIP
|
||||
)
|
||||
) { _, _, direction ->
|
||||
volumeController?.run {
|
||||
volume += direction
|
||||
overlayController.onVolumeChanged(volume, maxVolume)
|
||||
}
|
||||
}
|
||||
|
||||
override fun scrollVolume(distance: Double) = volumeScroller.add(distance)
|
||||
//endregion
|
||||
|
||||
//region brightness
|
||||
private val brightnessScroller =
|
||||
ScrollDistanceHelper(
|
||||
brightnessDistance.applyDimension(
|
||||
context,
|
||||
TypedValue.COMPLEX_UNIT_DIP
|
||||
)
|
||||
) { _, _, direction ->
|
||||
screenController?.run {
|
||||
if (screenBrightness > 0 || direction > 0) {
|
||||
screenBrightness += direction
|
||||
} else {
|
||||
restoreDefaultBrightness()
|
||||
}
|
||||
|
||||
overlayController.onBrightnessChanged(screenBrightness)
|
||||
}
|
||||
}
|
||||
|
||||
override fun scrollBrightness(distance: Double) = brightnessScroller.add(distance)
|
||||
//endregion
|
||||
|
||||
override fun resetScroller() {
|
||||
volumeScroller.reset()
|
||||
brightnessScroller.reset()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package app.revanced.tiktok.download;
|
||||
|
||||
import app.revanced.tiktok.settings.SettingsEnum;
|
||||
|
||||
public class DownloadsPatch {
|
||||
public static String getDownloadPath() {
|
||||
return SettingsEnum.TIK_DOWN_PATH.getString();
|
||||
}
|
||||
|
||||
public static boolean shouldRemoveWatermark() {
|
||||
return SettingsEnum.TIK_DOWN_WATERMARK.getBoolean();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package app.revanced.tiktok.feedfilter;
|
||||
|
||||
import com.ss.android.ugc.aweme.feed.model.Aweme;
|
||||
import com.ss.android.ugc.aweme.feed.model.FeedItemList;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import app.revanced.tiktok.settings.SettingsEnum;
|
||||
|
||||
public class FeedItemsFilter {
|
||||
|
||||
public static void filter(FeedItemList feedItemList) {
|
||||
if (SettingsEnum.TIK_REMOVE_ADS.getBoolean()) removeAds(feedItemList);
|
||||
if (SettingsEnum.TIK_HIDE_LIVE.getBoolean()) removeLive(feedItemList);
|
||||
}
|
||||
|
||||
private static void removeAds(FeedItemList feedItemList) {
|
||||
List<Aweme> items = feedItemList.items;
|
||||
Iterator<Aweme> it = items.iterator();
|
||||
while (it.hasNext()) {
|
||||
Aweme item = it.next();
|
||||
if (item != null && (item.isAd() || item.isWithPromotionalMusic())) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void removeLive(FeedItemList feedItemList) {
|
||||
List<Aweme> items = feedItemList.items;
|
||||
Iterator<Aweme> it = items.iterator();
|
||||
while (it.hasNext()) {
|
||||
Aweme item = it.next();
|
||||
if (item != null && (item.isLive() || item.isLiveReplay())) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package app.revanced.tiktok.settings;
|
||||
|
||||
public enum ReturnType {
|
||||
BOOLEAN, INTEGER, STRING, LONG, FLOAT
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user