Compare commits
65
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e5c407ed13 | ||
|
|
f185668e7e | ||
|
|
6b1e6f07c5 | ||
|
|
5466dd72dd | ||
|
|
f0246b722f | ||
|
|
803c2ffa40 | ||
|
|
51bbcb5305 | ||
|
|
5ac3b9cf6e | ||
|
|
de6edc795a | ||
|
|
19d36272cb | ||
|
|
60277d0d19 | ||
|
|
36f4a348ca | ||
|
|
999f1ccd06 | ||
|
|
d2fe435ad2 | ||
|
|
1f5efdb41e | ||
|
|
18c73d4e48 | ||
|
|
4341804732 | ||
|
|
d7c1ce4b78 | ||
|
|
7a30e2aae6 | ||
|
|
0194f5ede1 | ||
|
|
e5b5467b27 | ||
|
|
982b2bb059 | ||
|
|
bf6c72f2a8 | ||
|
|
5214964e0f | ||
|
|
ade17dd2cf | ||
|
|
a14043c4f3 | ||
|
|
678774c44e | ||
|
|
58f80a5f54 | ||
|
|
f6a2412014 | ||
|
|
cf99b8a838 | ||
|
|
b6e7d24979 | ||
|
|
baa3afc378 | ||
|
|
dbdf5469f5 | ||
|
|
7fc51708f9 | ||
|
|
25cc4720f7 | ||
|
|
00b1fa3cad | ||
|
|
71edb4db24 | ||
|
|
cd6ed0f51f | ||
|
|
c18ea2846f | ||
|
|
de9382cb50 | ||
|
|
d10d5eca4b | ||
|
|
67f1477907 | ||
|
|
18ef4eda21 | ||
|
|
84cf9ba10a | ||
|
|
b05a239b90 | ||
|
|
8959558c64 | ||
|
|
e19ed8845d | ||
|
|
b5ae2662db | ||
|
|
9aa8a3d45c | ||
|
|
d4710663ff | ||
|
|
9efccb37ad | ||
|
|
18f40e0da9 | ||
|
|
9ff8c1d9fe | ||
|
|
91440e4f8b | ||
|
|
a195e05d7b | ||
|
|
8866bf90c7 | ||
|
|
eab5b7074e | ||
|
|
bdee6c08c0 | ||
|
|
0744613aa0 | ||
|
|
f6de4c5bc9 | ||
|
|
f59e93aab6 | ||
|
|
2d97341886 | ||
|
|
b247c5c090 | ||
|
|
fd6e866f6f | ||
|
|
780ebce3ff |
@@ -21,14 +21,21 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up NDK
|
||||
uses: nttld/setup-ndk@v1
|
||||
with:
|
||||
ndk-version: r25c
|
||||
add-to-path: false
|
||||
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'adopt'
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
|
||||
- name: Download tools
|
||||
run: |
|
||||
sudo apt update
|
||||
@@ -47,6 +54,8 @@ jobs:
|
||||
java -jar scripts/apktool.jar b smali -o smali/VTLite.apk --use-aapt2 -p scripts/framework/
|
||||
zipalign -p -f 4 smali/VTLite.apk smali/VTLite.apk_aligned
|
||||
mv smali/VTLite.apk_aligned smali/VTLite.apk
|
||||
env:
|
||||
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
|
||||
|
||||
- name: Sign and verify the apk
|
||||
run: |
|
||||
|
||||
+1
-1
@@ -78,7 +78,7 @@ android {
|
||||
targetCompatibility JavaVersion.VERSION_14
|
||||
}
|
||||
namespace 'ru.vtosters.lite'
|
||||
ndkVersion '26.1.10909125'
|
||||
ndkVersion '25.2.9519653'
|
||||
buildFeatures {
|
||||
aidl true
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -35,7 +35,7 @@
|
||||
-optimizationpasses 5
|
||||
-keepattributes SourceFile, LineNumberTable
|
||||
|
||||
-keep,allowoptimization class ru.vtosters.hooks.**, ru.vtosters.lite.utils.AndroidUtils, ru.vtosters.lite.utils.NetworkUtils, ru.vtosters.lite.utils.CrashReporter, ru.vtosters.lite.ui.activities.**, ru.vtosters.lite.services.**, ru.vtosters.lite.ui.fragments.**, ru.vtosters.lite.themes.**, ru.vtosters.lite.music.hook.**, ru.vtosters.lite.music.cache.injectors.**, ru.vtosters.lite.ui.wallpapers.NativeEffects, com.aefyr.tsg.g2.TelegramStickersService {
|
||||
-keep,allowoptimization class ru.vtosters.hooks.**, ru.vtosters.sponsorpost.internal.Native, ru.vtosters.lite.utils.AndroidUtils, ru.vtosters.lite.utils.NetworkUtils, ru.vtosters.lite.utils.CrashReporter, ru.vtosters.lite.ui.activities.**, ru.vtosters.lite.services.**, ru.vtosters.lite.ui.fragments.**, ru.vtosters.lite.themes.**, ru.vtosters.lite.music.hook.**, ru.vtosters.lite.music.cache.injectors.**, ru.vtosters.lite.ui.wallpapers.NativeEffects, com.aefyr.tsg.g2.TelegramStickersService {
|
||||
public <fields>;
|
||||
public <methods>;
|
||||
public <init>(...);
|
||||
|
||||
+29
-38
@@ -49,6 +49,7 @@ import com.vk.im.ui.views.msg.bubble.MsgBubbleView;
|
||||
import com.vk.im.ui.views.sticker.StickerAnimationState;
|
||||
import kotlin.Unit;
|
||||
import kotlin.jvm.b.Functions;
|
||||
import ru.vtosters.lite.themes.ThemesHacks;
|
||||
|
||||
public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
|
||||
public static final int h0 = Screen.a(124);
|
||||
@@ -133,7 +134,7 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
|
||||
this.h = itemView.findViewById(com.vk.im.ui.h.status_space);
|
||||
this.P = itemView.findViewById(com.vk.im.ui.h.bomb);
|
||||
this.B = vhBase;
|
||||
this.H = new ColorDrawable(context.getResources().getColor(com.vk.im.ui.d.msg_search_selection));
|
||||
this.H = new ColorDrawable(ThemesHacks.getColors(context, com.vk.im.ui.d.msg_search_selection));
|
||||
this.I = ContextExtKt.b(context, com.vk.im.ui.e.msg_bubble_max_width);
|
||||
this.J = ContextExtKt.b(context, com.vk.im.ui.e.msg_reply_max_width);
|
||||
this.K = ContextExtKt.b(context, com.vk.im.ui.e.msg_sticker_max_width);
|
||||
@@ -150,49 +151,39 @@ public class VhMsg extends VhBase implements SwipeToReplyItemTouchCallback.b {
|
||||
var6.right = var7.rightMargin;
|
||||
var6.top = var7.topMargin;
|
||||
var6.bottom = var7.bottomMargin;
|
||||
ViewExtKt.b(this.c, new View.OnClickListener() {
|
||||
public void onClick(View var1) {
|
||||
if (VhMsg.this.c0 != null && VhMsg.this.d0 != null) {
|
||||
VhMsg.this.c0.a(VhMsg.this.d0.getFrom());
|
||||
}
|
||||
|
||||
ViewExtKt.b(this.c, var1 -> {
|
||||
if (VhMsg.this.c0 != null && VhMsg.this.d0 != null) {
|
||||
VhMsg.this.c0.a(VhMsg.this.d0.getFrom());
|
||||
}
|
||||
});
|
||||
this.c.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
public boolean onLongClick(View var1) {
|
||||
if (VhMsg.this.c0 != null && VhMsg.this.d0 != null) {
|
||||
VhMsg.this.c0.a(VhMsg.this.d0.getFrom());
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
ViewExtKt.b(this.g, new View.OnClickListener() {
|
||||
public void onClick(View var1) {
|
||||
if (VhMsg.this.c0 != null && VhMsg.this.d0 != null) {
|
||||
VhMsg.this.c0.a(VhMsg.this.d0);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
ViewExtKt.b(this.itemView, new View.OnClickListener() {
|
||||
public void onClick(View var1) {
|
||||
if (VhMsg.this.c0 != null && VhMsg.this.d0 != null) {
|
||||
VhMsg.this.c0.a(VhMsg.this.d0.getLocalId());
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
this.itemView.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
public boolean onLongClick(View var1) {
|
||||
if (VhMsg.this.c0 != null && VhMsg.this.d0 != null) {
|
||||
VhMsg.this.c0.b(VhMsg.this.d0.getLocalId());
|
||||
}
|
||||
|
||||
this.c.setOnLongClickListener(var1 -> {
|
||||
if (VhMsg.this.c0 != null && VhMsg.this.d0 != null) {
|
||||
VhMsg.this.c0.a(VhMsg.this.d0.getFrom());
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
ViewExtKt.b(this.g, var1 -> {
|
||||
if (VhMsg.this.c0 != null && VhMsg.this.d0 != null) {
|
||||
VhMsg.this.c0.a(VhMsg.this.d0);
|
||||
}
|
||||
|
||||
});
|
||||
ViewExtKt.b(this.itemView, (View.OnClickListener) var1 -> {
|
||||
if (VhMsg.this.c0 != null && VhMsg.this.d0 != null) {
|
||||
VhMsg.this.c0.a(VhMsg.this.d0.getLocalId());
|
||||
}
|
||||
|
||||
});
|
||||
this.itemView.setOnLongClickListener((View.OnLongClickListener) var1 -> {
|
||||
if (VhMsg.this.c0 != null && VhMsg.this.d0 != null) {
|
||||
VhMsg.this.c0.b(VhMsg.this.d0.getLocalId());
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
this.R = ContextExtKt.i(context, com.vk.im.ui.c.im_msg_part_corner_radius_small);
|
||||
this.S = ContextExtKt.i(context, com.vk.im.ui.c.im_msg_part_corner_radius_big);
|
||||
this.c0 = null;
|
||||
|
||||
@@ -10,6 +10,7 @@ import android.util.Log;
|
||||
import androidx.annotation.Keep;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.soloader.SoLoader;
|
||||
import ru.vtosters.sponsorpost.internal.Native;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.lang.ref.WeakReference;
|
||||
@@ -274,6 +275,7 @@ public final class MediaNative {
|
||||
SoLoader.init(context2, false);
|
||||
NativeLibLoader.loadLibrary("gnustl_shared");
|
||||
NativeLibLoader.loadLibrary("vkchronicle");
|
||||
Native.canVote = NativeLibLoader.loadLibrary("sponsorpost");
|
||||
loadVKMediaLibs();
|
||||
f17443d.notifyAll();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
package com.vk.newsfeed.holders;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.vk.core.dialogs.alert.VkAlertDialog;
|
||||
import com.vk.core.ui.themes.VKThemeHelper;
|
||||
import com.vk.dto.newsfeed.entries.NewsEntry;
|
||||
import com.vk.dto.newsfeed.entries.Post;
|
||||
import com.vk.dto.newsfeed.entries.PromoPost;
|
||||
import com.vk.extensions.ViewExtKt;
|
||||
import com.vtosters.lite.R;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.newsfeed.NewsFeedFiltersUtils;
|
||||
import ru.vtosters.sponsorpost.internal.Native;
|
||||
import ru.vtosters.sponsorpost.internal.VotesPreferences;
|
||||
import ru.vtosters.sponsorpost.internal.VotesService;
|
||||
import ru.vtosters.sponsorpost.utils.PostsPreferences;
|
||||
|
||||
public final class AdMarkHolder extends BaseNewsEntryHolder<NewsEntry> {
|
||||
private final TextView F;
|
||||
|
||||
@SuppressLint("ResourceType")
|
||||
public AdMarkHolder(ViewGroup viewGroup) {
|
||||
super(R.layout.marked_as_ads, viewGroup);
|
||||
View view = ((RecyclerView.ViewHolder) this).itemView;
|
||||
this.F = ViewExtKt.a(view, R.id.text, (View.OnClickListener) null);
|
||||
}
|
||||
|
||||
@SuppressLint("ResourceType")
|
||||
public void b(NewsEntry newsEntry) { // onBind
|
||||
String disclamer = null;
|
||||
Drawable drawable = null;
|
||||
int height = 0;
|
||||
|
||||
if (newsEntry instanceof Post) {
|
||||
Post post = ((Post) newsEntry);
|
||||
if (post.L1()) {
|
||||
drawable = VKThemeHelper.a(R.drawable.marked_as_ads, R.attr.icon_tertiary);
|
||||
int ownerId = post.b();
|
||||
int postId = post.P1();
|
||||
int date = post.K();
|
||||
String text = post.getText();
|
||||
|
||||
if (PostsPreferences.isPostAd(ownerId, postId)) {
|
||||
disclamer = "SponsorPost: Реклама";
|
||||
if (Preferences.isValidSignature() && Native.canVote()) {
|
||||
this.F.setOnClickListener(listener -> voteDialog(ownerId, postId, date, this.F.getContext()));
|
||||
}
|
||||
} else if (VotesPreferences.isPostAd(ownerId, postId)) {
|
||||
disclamer = "SponsorPost: Возможно реклама";
|
||||
if (Preferences.isValidSignature() && Native.canVote()) {
|
||||
this.F.setOnClickListener(listener -> voteDialog(ownerId, postId, date, this.F.getContext()));
|
||||
}
|
||||
} else if (NewsFeedFiltersUtils.sponsorFilters(text)) {
|
||||
disclamer = "SponsorPost: Заблокировано фильтрами";
|
||||
this.F.setOnClickListener(listener -> AndroidUtils.sendToast("Заблокировано по выражению: " + NewsFeedFiltersUtils.sponsorFiltersBanWord(text)));
|
||||
} else {
|
||||
disclamer = m(R.string.sponsored_post_in_group);
|
||||
}
|
||||
|
||||
height = e0().getDimensionPixelSize(R.dimen.newsfeed_ad_mark_post_height);
|
||||
}
|
||||
} else if (newsEntry instanceof PromoPost) {
|
||||
PromoPost promoPost = (PromoPost) newsEntry;
|
||||
if (!promoPost.E1().isEmpty()) {
|
||||
height = e0().getDimensionPixelSize(R.dimen.newsfeed_ad_mark_promo_post_height);
|
||||
disclamer = promoPost.E1();
|
||||
}
|
||||
}
|
||||
|
||||
this.F.setCompoundDrawablesRelativeWithIntrinsicBounds(drawable, null, null, null);
|
||||
this.F.setMinHeight(height);
|
||||
this.F.setText(disclamer);
|
||||
}
|
||||
|
||||
public static void voteDialog(int ownerId, int postId, int date, Context ctx) {
|
||||
new VkAlertDialog.Builder(ctx)
|
||||
.setTitle("SponsorPost")
|
||||
.setMessage("Этот пост является рекламным?")
|
||||
.setPositiveButton("Да", ((dialog, which) -> {
|
||||
int resp = VotesService.ratePost(ownerId, postId, date, true).optInt("code");
|
||||
|
||||
if (resp == 201 || resp == 100) {
|
||||
AndroidUtils.sendToast("Спасибо за голос!");
|
||||
} else {
|
||||
AndroidUtils.sendToast("Ваш голос уже учтен");
|
||||
}
|
||||
}))
|
||||
.setNeutralButton("Нет", ((dialog, which) -> {
|
||||
int resp = VotesService.ratePost(ownerId, postId, date, false).optInt("code");
|
||||
|
||||
if (resp == 201 || resp == 100) {
|
||||
AndroidUtils.sendToast("Спасибо за голос!");
|
||||
} else {
|
||||
AndroidUtils.sendToast("Ваш голос уже учтен");
|
||||
}
|
||||
}))
|
||||
.show();
|
||||
}
|
||||
}
|
||||
@@ -13025,7 +13025,7 @@ public final class R {
|
||||
public static final int ic_launcher_shine = 0x7f0f005d; // 2131689565
|
||||
public static final int ic_launcher_shine_background = 0x7f0f005e; // 2131689566
|
||||
public static final int ic_launcher_shine_foreground = 0x7f0f005f; // 2131689567
|
||||
public static final int vt_adaptive_launcher_foneground = 0x7f0f0043; // 2131689539
|
||||
public static final int vt_adaptive_launcher_foreground = 0x7f0f0043; // 2131689539
|
||||
public static final int vt_launcher_round = 0x7f0f0046; // 2131689542
|
||||
public static final int ic_logo_facebook_28 = 0x7f0f0003; // 2131689475
|
||||
public static final int ic_logo_google_28 = 0x7f0f0004; // 2131689476
|
||||
@@ -19661,38 +19661,39 @@ public final class R {
|
||||
public static final int cache_size = 0x7f12188d; // 2131892365
|
||||
public static final int cache_size_summ = 0x7f12188e; // 2131892366
|
||||
public static final int clear_all_cache = 0x7f12188f; // 2131892367
|
||||
public static final int invalidate_theme_cache_each_update_title = 0x7f121890; // 2131892368
|
||||
public static final int invertFilters = 0x7f121891; // 2131892369
|
||||
public static final int invertFilters_summ = 0x7f121892; // 2131892370
|
||||
public static final int invertcached_summ = 0x7f121893; // 2131892371
|
||||
public static final int invertcached_title = 0x7f121894; // 2131892372
|
||||
public static final int microg_dialog1 = 0x7f121895; // 2131892373
|
||||
public static final int microg_dialog2 = 0x7f121896; // 2131892374
|
||||
public static final int microg_dialog3 = 0x7f121897; // 2131892375
|
||||
public static final int serverFeaturesDisable = 0x7f121898; // 2131892376
|
||||
public static final int serverFeaturesDisable_summ = 0x7f121899; // 2131892377
|
||||
public static final int sett_autoupdates = 0x7f12189a; // 2131892378
|
||||
public static final int sett_autoupdates_summ = 0x7f12189b; // 2131892379
|
||||
public static final int sett_battery = 0x7f12189c; // 2131892380
|
||||
public static final int sett_battery_summ1 = 0x7f12189d; // 2131892381
|
||||
public static final int sett_battery_summ2 = 0x7f12189e; // 2131892382
|
||||
public static final int sett_chats = 0x7f12189f; // 2131892383
|
||||
public static final int sett_chats_summ = 0x7f1218a0; // 2131892384
|
||||
public static final int sett_community = 0x7f1218a1; // 2131892385
|
||||
public static final int sett_community_summ = 0x7f1218a2; // 2131892386
|
||||
public static final int sett_missing_links = 0x7f1218a3; // 2131892387
|
||||
public static final int sett_missing_links_summ = 0x7f1218a4; // 2131892388
|
||||
public static final int sett_nogms_summ = 0x7f1218a5; // 2131892389
|
||||
public static final int sett_notifs = 0x7f1218a6; // 2131892390
|
||||
public static final int sett_notifs_summ = 0x7f1218a7; // 2131892391
|
||||
public static final int sett_recommendations = 0x7f1218a8; // 2131892392
|
||||
public static final int tgs_token_missing = 0x7f1218aa; // 2131892394
|
||||
public static final int tgs_token_reset = 0x7f1218ab; // 2131892395
|
||||
public static final int tgs_token_reset_dialog = 0x7f1218ac; // 2131892396
|
||||
public static final int tgs_token_reset_menu = 0x7f1218ad; // 2131892397
|
||||
public static final int update_err = 0x7f1218ae; // 2131892398
|
||||
public static final int update_latest = 0x7f1218af; // 2131892399
|
||||
public static final int APKTOOL_DUMMY_18a9 = 0x7f1218a9; // 2131892393
|
||||
public static final int disable_roaming_state = 0x7f121890; // 2131892368
|
||||
public static final int disable_roaming_state_submit = 0x7f121891; // 2131892369
|
||||
public static final int invalidate_theme_cache_each_update_title = 0x7f121892; // 2131892370
|
||||
public static final int invertFilters = 0x7f121893; // 2131892371
|
||||
public static final int invertFilters_summ = 0x7f121894; // 2131892372
|
||||
public static final int invertcached_summ = 0x7f121895; // 2131892373
|
||||
public static final int invertcached_title = 0x7f121896; // 2131892374
|
||||
public static final int microg_dialog1 = 0x7f121897; // 2131892375
|
||||
public static final int microg_dialog2 = 0x7f121898; // 2131892376
|
||||
public static final int microg_dialog3 = 0x7f121899; // 2131892377
|
||||
public static final int serverFeaturesDisable = 0x7f12189a; // 2131892378
|
||||
public static final int serverFeaturesDisable_summ = 0x7f12189b; // 2131892379
|
||||
public static final int sett_autoupdates = 0x7f12189c; // 2131892380
|
||||
public static final int sett_autoupdates_summ = 0x7f12189d; // 2131892381
|
||||
public static final int sett_battery = 0x7f12189e; // 2131892382
|
||||
public static final int sett_battery_summ1 = 0x7f12189f; // 2131892383
|
||||
public static final int sett_battery_summ2 = 0x7f1218a0; // 2131892384
|
||||
public static final int sett_chats = 0x7f1218a1; // 2131892385
|
||||
public static final int sett_chats_summ = 0x7f1218a2; // 2131892386
|
||||
public static final int sett_community = 0x7f1218a3; // 2131892387
|
||||
public static final int sett_community_summ = 0x7f1218a4; // 2131892388
|
||||
public static final int sett_missing_links = 0x7f1218a5; // 2131892389
|
||||
public static final int sett_missing_links_summ = 0x7f1218a6; // 2131892390
|
||||
public static final int sett_nogms_summ = 0x7f1218a7; // 2131892391
|
||||
public static final int sett_notifs = 0x7f1218a8; // 2131892392
|
||||
public static final int sett_notifs_summ = 0x7f1218a9; // 2131892393
|
||||
public static final int sett_recommendations = 0x7f1218aa; // 2131892394
|
||||
public static final int tgs_token_missing = 0x7f1218ab; // 2131892395
|
||||
public static final int tgs_token_reset = 0x7f1218ac; // 2131892396
|
||||
public static final int tgs_token_reset_dialog = 0x7f1218ad; // 2131892397
|
||||
public static final int tgs_token_reset_menu = 0x7f1218ae; // 2131892398
|
||||
public static final int update_err = 0x7f1218af; // 2131892399
|
||||
public static final int update_latest = 0x7f1218b0; // 2131892400
|
||||
}
|
||||
|
||||
public static final class style {
|
||||
|
||||
+2
-2
@@ -69,10 +69,10 @@ public class BottomNavigationItemView extends FrameLayout implements MenuView.It
|
||||
this.mIcon.getLayoutParams().height = V.a(28.0F);
|
||||
|
||||
this.mSmallLabel = this.findViewById(R.id.smallLabel);
|
||||
mSmallLabel.setTextColor(getCSTDock());
|
||||
mSmallLabel.setTextColor(getCSTDock(this.getContext()));
|
||||
|
||||
this.mLargeLabel = this.findViewById(R.id.largeLabel);
|
||||
mLargeLabel.setTextColor(getCSTDock());
|
||||
mLargeLabel.setTextColor(getCSTDock(this.getContext()));
|
||||
|
||||
LayoutInflater.from(this.getContext()).inflate(R.layout.navigation_bottom_counter, this, true);
|
||||
this.mCounterContainer = this.findViewById(R.id.counter_container);
|
||||
|
||||
@@ -65,7 +65,7 @@ public class DockBarInjector {
|
||||
for (DockBarTab tab : sManager.getSelectedTabs()) {
|
||||
MenuItem add = menu.add(0, tab.id, 0, tab.titleID);
|
||||
|
||||
add.setIcon(new RecoloredDrawable(getResources().getDrawable(tab.iconID), getCSTDock()));
|
||||
add.setIcon(new RecoloredDrawable(getResources().getDrawable(tab.iconID), getCSTDock(navigationView.getContext())));
|
||||
add.setTitle(getGlobalContext().getString(tab.titleID));
|
||||
add.setCheckable(true);
|
||||
}
|
||||
@@ -76,7 +76,7 @@ public class DockBarInjector {
|
||||
item.setStaticMode(true);
|
||||
item.setIconsMode(false);
|
||||
item.setShiftingMode(false);
|
||||
item.setTextColor(getCSTDock());
|
||||
item.setTextColor(getCSTDock(item.getContext()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
public class FirebaseGzipSupport {
|
||||
public static JSONObject getJsonObjectFromConnection(URLConnection connection) throws IOException, JSONException {
|
||||
InputStream inputStream = getDecompressedInputStream(connection);
|
||||
String jsonString = readInputStream(inputStream);
|
||||
return new JSONObject(jsonString);
|
||||
}
|
||||
|
||||
private static InputStream getDecompressedInputStream(URLConnection connection) throws IOException {
|
||||
String contentEncoding = connection.getHeaderField("Content-Encoding");
|
||||
if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip")) {
|
||||
return new GZIPInputStream(connection.getInputStream());
|
||||
}
|
||||
return connection.getInputStream();
|
||||
}
|
||||
|
||||
private static String readInputStream(InputStream inputStream) throws IOException {
|
||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int read;
|
||||
while ((read = bufferedReader.read()) != -1) {
|
||||
sb.append((char) read);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
|
||||
public class GroupCoverHook {
|
||||
public static boolean needToDisableCovers() {
|
||||
return Preferences.getBoolValue("disablevideoscovers", false);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.NetworkInfo;
|
||||
import android.os.PowerManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.vk.core.preference.Preference;
|
||||
@@ -9,13 +11,12 @@ import com.vk.discover.DiscoverItemDecorator;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.concurrent.VTExecutors;
|
||||
import ru.vtosters.lite.utils.NetworkUtils;
|
||||
import ru.vtosters.sponsorpost.internal.VotesPreferences;
|
||||
import ru.vtosters.sponsorpost.internal.VotesService;
|
||||
import ru.vtosters.sponsorpost.services.PostService;
|
||||
import ru.vtosters.sponsorpost.utils.PostsPreferences;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import static java.lang.Long.MAX_VALUE;
|
||||
import static ru.vtosters.hooks.other.Preferences.*;
|
||||
@@ -83,25 +84,33 @@ public class NewsfeedHook {
|
||||
}
|
||||
|
||||
public static void adsParams(HashSet<String> hashSet) {
|
||||
String[] adsParams = {"ads_disabled", "ads_app_slider", "ads_site_slider", "ads_app", "ads_site", "ads_post", "ads_app_video", "ads_post_pretty_cards", "ads_post_snippet_video"};
|
||||
String[] adsParams = {"ads_app_slider", "ads_site_slider", "ads_app", "ads_site", "ads_post", "ads_app_video", "ads_post_pretty_cards", "ads_post_snippet_video"};
|
||||
String noAdParam = "ads_disabled";
|
||||
|
||||
if (ads()) {
|
||||
hashSet.add(adsParams[0]);
|
||||
hashSet.add(adsParams[1]);
|
||||
hashSet.add(noAdParam);
|
||||
|
||||
if (!Preferences.milkshake()) {
|
||||
hashSet.add(adsParams[0]);
|
||||
}
|
||||
} else {
|
||||
Collections.addAll(hashSet, adsParams);
|
||||
}
|
||||
|
||||
if (Preferences.milkshake()) {
|
||||
hashSet.remove(adsParams[1]);
|
||||
}
|
||||
}
|
||||
|
||||
public static void takeOwnerIdSponsorPost(int ownerid) {
|
||||
if (NetworkUtils.isNetworkConnected() && PostsPreferences.isEnabled() && !Preferences.serverFeaturesDisable()) {
|
||||
VTExecutors.getIoScheduler().a(() -> {
|
||||
List<Long> postIds = PostService.getPostIdsByOwnerId((long) ownerid, 0L);
|
||||
PostsPreferences.saveGroupSpecifiedPosts(postIds, (long) ownerid);
|
||||
if (PostsPreferences.isGroupAd(ownerid) || VotesPreferences.isGroupAd(ownerid)) {
|
||||
if (VotesPreferences.isEnabled()) {
|
||||
Map<String, List<String>> postIds = VotesService.getPostIdsByOwnerId((long) ownerid, 0L);
|
||||
VotesPreferences.saveGroupSpecifiedPosts(postIds.get("vote"), (long) ownerid);
|
||||
PostsPreferences.saveGroupSpecifiedPosts(postIds.get("prod"), (long) ownerid);
|
||||
} else {
|
||||
List<Long> postIds = PostService.getPostIdsByOwnerId((long) ownerid, 0L);
|
||||
PostsPreferences.saveGroupSpecifiedPosts(postIds, (long) ownerid);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -110,17 +119,28 @@ public class NewsfeedHook {
|
||||
long ownerid = Long.parseLong(strArr[0].split("_")[0]);
|
||||
long postId = Long.parseLong(strArr[0].split("_")[1]);
|
||||
|
||||
if (PostsPreferences.isPostAd(ownerid, postId)) {
|
||||
if (PostsPreferences.isPostAd(ownerid, postId) || VotesPreferences.isPostAd(ownerid, postId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (NetworkUtils.isNetworkConnected() && PostsPreferences.isEnabled() && !Preferences.serverFeaturesDisable() && PostsPreferences.isGroupAd(ownerid)) {
|
||||
if (NetworkUtils.isNetworkConnected() && PostsPreferences.isEnabled() && !Preferences.serverFeaturesDisable()) {
|
||||
VTExecutors.getIoScheduler().a(() -> {
|
||||
boolean postIds = PostService.isPostAd(ownerid, postId);
|
||||
if (VotesPreferences.isEnabled()) {
|
||||
boolean postIds = VotesService.isPostAd(ownerid, postId);
|
||||
|
||||
if (postIds) {
|
||||
PostsPreferences.saveAdPostInfo(ownerid, postId);
|
||||
sendToast("Этот пост помечен как рекламный");
|
||||
if (postIds) {
|
||||
VotesPreferences.saveAdPostInfo(ownerid, postId);
|
||||
}
|
||||
} else {
|
||||
boolean postIds = PostService.isPostAd(ownerid, postId);
|
||||
|
||||
if (postIds) {
|
||||
PostsPreferences.saveAdPostInfo(ownerid, postId);
|
||||
|
||||
if (!PostsPreferences.isEnabledMarking()) {
|
||||
sendToast("Этот пост помечен как рекламный");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -132,4 +152,12 @@ public class NewsfeedHook {
|
||||
// return !getBoolValue("force_disable_psm", false) && pw.isPowerSaveMode();
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isRoaming(NetworkInfo networkInfo) {
|
||||
return !Preferences.disableForceTrafficSaver() && networkInfo.isRoaming();
|
||||
}
|
||||
|
||||
public static boolean isNetworkRoaming(TelephonyManager telephonyManager) {
|
||||
return !Preferences.disableForceTrafficSaver() && telephonyManager.isNetworkRoaming();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,22 @@
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.util.Log;
|
||||
import com.vk.core.network.Network;
|
||||
import com.vtosters.lite.R;
|
||||
import okhttp3.Call;
|
||||
import okhttp3.Callback;
|
||||
import okhttp3.Response;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.proxy.ProxyUtils;
|
||||
import ru.vtosters.lite.utils.AccountManagerUtils;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static com.vk.core.network.Network.ClientType.CLIENT_API;
|
||||
import static ru.vtosters.hooks.other.Preferences.*;
|
||||
import static ru.vtosters.lite.net.Request.makeRequest;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.getApi;
|
||||
@@ -85,22 +94,34 @@ public class OnlineFormatterHook {
|
||||
|
||||
if (appname != null) return appname;
|
||||
|
||||
makeRequest("https://" + getApi() + "/method/apps.get?app_id=" + appid + "&v=5.99&access_token=" + getUserToken(),
|
||||
response -> {
|
||||
try {
|
||||
JSONObject mainJson = new JSONObject(response);
|
||||
JSONObject responseJson = mainJson.getJSONObject("response");
|
||||
JSONArray itemsJson = responseJson.getJSONArray("items");
|
||||
okhttp3.Request req = new okhttp3.Request.a()
|
||||
.b("https://" + getApi() + "/method/apps.get?app_id=" + appid + "&v=5.99&access_token=" + getUserToken())
|
||||
.a();
|
||||
|
||||
AppName = itemsJson.getJSONObject(0).optString("title", "");
|
||||
Network.b(CLIENT_API).a(req).a(new Callback() {
|
||||
@Override
|
||||
public void a(Call call, IOException e) {
|
||||
e.fillInStackTrace();
|
||||
}
|
||||
|
||||
prefs.edit().putString(String.valueOf(appid), AppName).apply();
|
||||
@Override
|
||||
public void a(Call call, Response response) throws IOException {
|
||||
try {
|
||||
JSONObject mainJson = new JSONObject(response.a().g());
|
||||
JSONObject responseJson = mainJson.getJSONObject("response");
|
||||
JSONArray itemsJson = responseJson.getJSONArray("items");
|
||||
|
||||
AppName = itemsJson.getJSONObject(0).optString("title", "");
|
||||
|
||||
prefs.edit().putString(String.valueOf(appid), AppName).apply();
|
||||
|
||||
if (dev()) sendToast("AppName: " + AppName + " for appid: " + appid);
|
||||
} catch (JSONException e) {
|
||||
e.fillInStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (dev()) sendToast("AppName: " + AppName + " for appid: " + appid);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
|
||||
return AppName;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import android.widget.Toast;
|
||||
import androidx.core.content.FileProvider;
|
||||
import com.vk.core.dialogs.actionspopup.ActionsPopup;
|
||||
import com.vk.core.dialogs.alert.VkAlertDialog;
|
||||
import com.vk.core.network.Network;
|
||||
import com.vk.core.util.ToastUtils;
|
||||
import com.vk.dto.common.AttachmentWithMedia;
|
||||
import com.vk.dto.common.ImageSize;
|
||||
@@ -90,7 +91,7 @@ public class PhotoViewer {
|
||||
var req = new Request.a()
|
||||
.b(getImageUrlFromAttachment(attachment))
|
||||
.a();
|
||||
client.a(req).a(new Callback() {
|
||||
Network.b(Network.ClientType.CLIENT_API).a(req).a(new Callback() {
|
||||
@Override
|
||||
public void a(Call call, IOException e) {
|
||||
e.printStackTrace();
|
||||
@@ -100,7 +101,7 @@ public class PhotoViewer {
|
||||
public void a(Call call, Response response)
|
||||
throws IOException {
|
||||
var tmpImage = new File(AndroidUtils.getGlobalContext().getExternalCacheDir(), attachment.getId() + ".jpg");
|
||||
try (var resp = client.a(req).execute();
|
||||
try (var resp = Network.b(Network.ClientType.CLIENT_IMAGE_LOADER).a(req).execute();
|
||||
var sink = Okio.a(Okio.b(tmpImage))) {
|
||||
sink.a(resp.a().f());
|
||||
var manager = (ClipboardManager) AndroidUtils.getGlobalContext().getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
@@ -175,4 +176,4 @@ public class PhotoViewer {
|
||||
}
|
||||
return max.url;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package ru.vtosters.hooks;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import com.vk.dto.newsfeed.entries.NewsEntry;
|
||||
import com.vk.dto.newsfeed.entries.Post;
|
||||
import com.vk.newsfeed.NewsEntryActionsAdapter;
|
||||
import com.vk.newsfeed.holders.AdMarkHolder;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.utils.AccountManagerUtils;
|
||||
import ru.vtosters.sponsorpost.internal.Native;
|
||||
import ru.vtosters.sponsorpost.utils.PostsPreferences;
|
||||
|
||||
public class PostsMenuHook {
|
||||
private static final int id = 200;
|
||||
|
||||
public static void injectList(NewsEntryActionsAdapter actionsAdapter, NewsEntry newsEntry) {
|
||||
if (newsEntry instanceof Post && Preferences.isValidSignature() && Native.canVote()) {
|
||||
int ownerId = ((Post) newsEntry).b();
|
||||
|
||||
if (ownerId != AccountManagerUtils.getUserId() && PostsPreferences.isEnabled()) {
|
||||
actionsAdapter.a(id, "SponsorPost");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void injectButtons(int i, NewsEntry newsEntry, Context context) {
|
||||
if (newsEntry instanceof Post) {
|
||||
Post post = (Post) newsEntry;
|
||||
int ownerId = post.b();
|
||||
int postId = post.P1();
|
||||
int date = post.K();
|
||||
|
||||
AdMarkHolder.voteDialog(ownerId, postId, date, context);
|
||||
} else {
|
||||
Log.d("PostsMenuHook", "unsupported instance");
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isCustomButton(int i) {
|
||||
return i == id;
|
||||
}
|
||||
}
|
||||
@@ -26,26 +26,15 @@ import static ru.vtosters.lite.utils.LifecycleUtils.restartApplication;
|
||||
|
||||
public class ProxyHook {
|
||||
public static String linkReplacer(String link) {
|
||||
var vkapi = "api.vk.com";
|
||||
var oauth = "oauth.vk.com";
|
||||
var vkstatic = "static.vk.com";
|
||||
String vkapi = "api.vk.com";
|
||||
String oauth = "oauth.vk.com";
|
||||
String vkstatic = "static.vk.com";
|
||||
|
||||
var proxyapi = getString("proxyapi");
|
||||
var proxyoauth = getString("proxyoauth");
|
||||
var proxystatic = getString("proxystatic");
|
||||
String proxyapi = getProxyHost("proxyapi");
|
||||
String proxyoauth = getProxyHost("proxyoauth");
|
||||
String proxystatic = getProxyHost("proxystatic");
|
||||
|
||||
if (isVikaProxyEnabled()) {
|
||||
proxyapi = VikaMobile.getApiHost();
|
||||
proxyoauth = VikaMobile.getOauthHost();
|
||||
proxystatic = VikaMobile.getStaticHost();
|
||||
}
|
||||
|
||||
if (!isAnyProxyEnabled() || link.isEmpty()) {
|
||||
return link;
|
||||
}
|
||||
|
||||
if (proxyapi.isEmpty() || proxyoauth.isEmpty() || proxystatic.isEmpty()) {
|
||||
Log.d("VTLite", "Proxy is not set" + " " + proxyapi + " " + proxyoauth + " " + proxystatic);
|
||||
if (!isAnyProxyEnabled() || link.isEmpty() || areProxyHostsEmpty(proxyapi, proxyoauth, proxystatic)) {
|
||||
return link;
|
||||
}
|
||||
|
||||
@@ -64,6 +53,29 @@ public class ProxyHook {
|
||||
return link;
|
||||
}
|
||||
|
||||
private static String getProxyHost(String hostType) {
|
||||
if (isVikaProxyEnabled()) {
|
||||
return switch (hostType) {
|
||||
case "proxyapi" -> VikaMobile.getApiHost();
|
||||
case "proxyoauth" -> VikaMobile.getOauthHost();
|
||||
case "proxystatic" -> VikaMobile.getStaticHost();
|
||||
default -> "";
|
||||
};
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean areProxyHostsEmpty(String... hosts) {
|
||||
for (String host : hosts) {
|
||||
if (host.isEmpty()) {
|
||||
Log.d("VTLite", "Proxy is not set: " + host);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String staticFix(String str) {
|
||||
var string = getString("proxystatic");
|
||||
|
||||
@@ -108,22 +120,18 @@ public class ProxyHook {
|
||||
|
||||
RadioButton rgDefault = new RadioButton(new ContextThemeWrapper(ctx, com.vtosters.lite.R.style.Widget_AppCompat_CompoundButton_RadioButton));
|
||||
RadioButton rgZaborona = new RadioButton(new ContextThemeWrapper(ctx, com.vtosters.lite.R.style.Widget_AppCompat_CompoundButton_RadioButton));
|
||||
// RadioButton rgRandomProxy = new RadioButton(new ContextThemeWrapper(ctx, com.vtosters.lite.R.style.Widget_AppCompat_CompoundButton_RadioButton));
|
||||
RadioButton rgVika = new RadioButton(new ContextThemeWrapper(ctx, com.vtosters.lite.R.style.Widget_AppCompat_CompoundButton_RadioButton));
|
||||
|
||||
SwitchHook.setCompoundButton(rgDefault);
|
||||
SwitchHook.setCompoundButton(rgZaborona);
|
||||
// SwitchHook.setCompoundButton(rgRandomProxy);
|
||||
SwitchHook.setCompoundButton(rgVika);
|
||||
|
||||
rg.addView(rgDefault);
|
||||
rg.addView(rgVika);
|
||||
rg.addView(rgZaborona);
|
||||
// rg.addView(rgRandomProxy);
|
||||
|
||||
rgDefault.setTextSize(TypedValue.COMPLEX_UNIT_PX, dp2px(14f));
|
||||
rgZaborona.setTextSize(TypedValue.COMPLEX_UNIT_PX, dp2px(14f));
|
||||
// rgRandomProxy.setTextSize(TypedValue.COMPLEX_UNIT_PX, dp2px(14f));
|
||||
rgVika.setTextSize(TypedValue.COMPLEX_UNIT_PX, dp2px(14f));
|
||||
|
||||
rg.setPadding(dp2px(18f), dp2px(12f), dp2px(18f), 0);
|
||||
@@ -134,28 +142,21 @@ public class ProxyHook {
|
||||
rgZaborona.setText(ctx.getString(R.string.proxy_enable) + " (Zaborona)");
|
||||
rgZaborona.setTextColor(getTextAttr());
|
||||
|
||||
// rgRandomProxy.setText(ctx.getString(R.string.proxy_enable) + " (Random Socks Proxy)");
|
||||
// rgRandomProxy.setTextColor(getTextAttr());
|
||||
|
||||
rgVika.setText(ctx.getString(R.string.proxy_enable) + " (Vika Mobile)");
|
||||
rgVika.setTextColor(getTextAttr());
|
||||
|
||||
rgZaborona.setChecked(isZaboronaEnabled());
|
||||
rgDefault.setChecked(!isZaboronaEnabled() && !isRandomProxyEnabled() && !isVikaProxyEnabled());
|
||||
// rgRandomProxy.setChecked(isRandomProxyEnabled());
|
||||
rgDefault.setChecked(!isZaboronaEnabled() && !isVikaProxyEnabled());
|
||||
rgVika.setChecked(isVikaProxyEnabled());
|
||||
|
||||
new VkAlertDialog.Builder(ctx)
|
||||
.setTitle(ctx.getString(R.string.vtlproxy))
|
||||
.setMessage(ctx.getString(R.string.proxy_warning))
|
||||
.setMessage(ctx.getString(R.string.proxy_warning) + "\n\nТак же можно включить встроенный прокси от ВКонтакте перейдя в настройки прокси")
|
||||
.setView(rg)
|
||||
.setPositiveButton(ctx.getString(R.string.vtl_confirm), ((dialog, which) -> { // Применить
|
||||
if (rgZaborona.isChecked()) {
|
||||
Preferences.getPreferences().edit().putString("proxy", "zaborona").commit();
|
||||
restartApplication();
|
||||
// } else if (rgRandomProxy.isChecked()) {
|
||||
// Preferences.getPreferences().edit().putString("proxy", "randomproxy").commit();
|
||||
// restartApplication();
|
||||
} else if (rgVika.isChecked()) {
|
||||
Preferences.getPreferences().edit().putString("proxy", "vika").commit();
|
||||
restartApplication();
|
||||
@@ -169,4 +170,4 @@ public class ProxyHook {
|
||||
})
|
||||
.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import static ru.vtosters.hooks.other.Preferences.*;
|
||||
public class TogglesHook {
|
||||
public static boolean shouldPatch(Features.Type feature) {
|
||||
return switch (feature) {
|
||||
case AB_IM_LONGPOLL_MSG_BATCHING, AB_IM_VIEW_POOL, AB_MULTI_GIFTS, AB_NEWS_VIDEO_LAYOUT_TEXT, AB_STICKERS_DISCOVER, AB_GIFTS_FROM_KEYBOARD, FEATURE_FEED_DEFAULT_LIST_ALWAYS, EXPERIMENT_NEWS_VIDEO_LAYOUT_TEXT, FEATURE_DISCOVER_CATEGORIES, FEATURE_FAVE_PERF_IMPROVE, FEATURE_GROUP_ADMIN_MESSAGES, FEATURE_GROUP_MSG_PUSH_PARAM, FEATURE_IMAGE_QUALITY_UPGRADE, FEATURE_IM_AUDIO_MSG_TRANSCRIPT, FEATURE_IM_CASPER_MSGS, FEATURE_IM_DISABLE_FORCE_OPEN_VK_ME, FEATURE_IM_GIF_AUTOPLAY, FEATURE_IM_MR_IN_VKAPP, FEATURE_MEMORIES_ENABLED, FEATURE_MENU_GAMES_CAROUSEL, FEATURE_MILKSHAKE, FEATURE_MILKSHAKE_CHANGE_FEED_BY_TIMEOUT, FEATURE_MILKSHAKE_NEWS_SCROLL_ON_BACK, FEATURE_MILKSHAKE_SWITCH_THEME_ON_TAP, FEATURE_ML_BRANDS, FEATURE_ML_FEATURES, FEATURE_ML_MODELS_LOADING, FEATURE_MONEY_TRANSFERS_VKPAY, FEATURE_MUSIC_ARTIST_CATALOG, FEATURE_MUSIC_NEW_CATALOG, FEATURE_NARRATIVE_SNIPPET_TYPE, FEATURE_NEWS_GAMES_IN_DISCOVER, FEATURE_NEWS_HEADER_SCROLL, FEATURE_NEW_FORMAT_SHOW_WPB, FEATURE_PODCASTS_PAGE, FEATURE_QR_CREATE_QR, FEATURE_QR_DYNAMIC_FRAME, FEATURE_QR_SCAN_FROM_PHOTO, FEATURE_QR_VISION_DECODER, FEATURE_QUEUE_COUNTERS, FEATURE_REEF, FEATURE_ROAMING_AUTOPLAY, FEATURE_SHARE_MSGS_ON_INVITE, FEATURE_STICKERS_BOT_LINK, FEATURE_STICKERS_NEW_CATALOG, FEATURE_STORIES_AVATAR, FEATURE_STORIES_FEED_TYPE, FEATURE_STORIES_SHOW_ALWAYS, FEATURE_STORY_ANSWER_PUBLIC, FEATURE_STORY_APP_STICKER, FEATURE_STORY_ARCHIVE, FEATURE_STORY_ARCHIVE_POST, FEATURE_STORY_BAKGROUND_ALL, FEATURE_STORY_BOX, FEATURE_STORY_CADRE, FEATURE_STORY_CAMERA_TOOLTIP, FEATURE_STORY_EDITOR_GALLERY, FEATURE_STORY_EDITOR_TYPE, FEATURE_STORY_ENDLESS_VIDEO, FEATURE_STORY_FAST_REACTIONS, FEATURE_STORY_GIF, FEATURE_STORY_GROUPED, FEATURE_STORY_HIGH_QUALITY, FEATURE_STORY_MASKS_FRONTAL, FEATURE_STORY_MENTION_ICON, FEATURE_STORY_MODERN_PUBLISH, FEATURE_STORY_MUSIC_EDITOR, FEATURE_STORY_MUSIC_REPLIES, FEATURE_STORY_MUSIC_REPLIES_2, FEATURE_STORY_NEW_FRAME, FEATURE_STORY_ONE_TIME, FEATURE_STORY_PHOTO_SHARING, FEATURE_STORY_PHOTO_STICKER, FEATURE_STORY_POLLS, FEATURE_STORY_POST_REPOST, FEATURE_STORY_PRELOADING, FEATURE_STORY_QUESTION, FEATURE_STORY_QUESTION_STYLE, FEATURE_STORY_RLOTTIE, FEATURE_STORY_RLOTTIE_CACHE, FEATURE_STORY_SAVE_DEFAULT_ON, FEATURE_STORY_SEND_DIALOG_LIST, FEATURE_STORY_STICKER_PACK, FEATURE_STORY_TIME, FEATURE_STORY_VIEWER_CAMERA, FEATURE_STORY_VOICE_ANSWER, FEATURE_STORY_WITH_CONTEXT, FEATURE_SUPERAPP_MENU, FEATURE_TRAFFIC_SAVER, FEATURE_VKPAY_WIDGET, FEATURE_VKUI_INTERNAL_TO_MINI_APPS, FEATURE_VKUI_TOKEN_CACHE, FEATURE_VK_APPS_SEARCH, FEATURE_VOTES_BALANCE, FEATURE_WEBVIEW_TOKEN_ACTIVE, FEATURE_MILKSHAKE_FORCE_DISABLED, FEATURE_MILKSHAKE_ACTIVATION_DISABLED, EXPERIMENT_NEWS_DISABLE_CACHE ->
|
||||
case AB_MULTI_GIFTS, AB_NEWS_VIDEO_LAYOUT_TEXT, AB_STICKERS_DISCOVER, AB_GIFTS_FROM_KEYBOARD, EXPERIMENT_NEWS_VIDEO_LAYOUT_TEXT, FEATURE_DISCOVER_CATEGORIES, FEATURE_FAVE_PERF_IMPROVE, FEATURE_GROUP_ADMIN_MESSAGES, FEATURE_GROUP_MSG_PUSH_PARAM, FEATURE_IMAGE_QUALITY_UPGRADE, FEATURE_IM_AUDIO_MSG_TRANSCRIPT, FEATURE_IM_CASPER_MSGS, FEATURE_IM_DISABLE_FORCE_OPEN_VK_ME, FEATURE_IM_GIF_AUTOPLAY, FEATURE_IM_MR_IN_VKAPP, FEATURE_MEMORIES_ENABLED, FEATURE_MENU_GAMES_CAROUSEL, FEATURE_MILKSHAKE, FEATURE_MILKSHAKE_NEWS_SCROLL_ON_BACK, FEATURE_MILKSHAKE_SWITCH_THEME_ON_TAP, FEATURE_ML_BRANDS, FEATURE_ML_FEATURES, FEATURE_ML_MODELS_LOADING, FEATURE_MONEY_TRANSFERS_VKPAY, FEATURE_MUSIC_ARTIST_CATALOG, FEATURE_MUSIC_NEW_CATALOG, FEATURE_NARRATIVE_SNIPPET_TYPE, FEATURE_NEWS_GAMES_IN_DISCOVER, FEATURE_NEWS_HEADER_SCROLL, FEATURE_NEW_FORMAT_SHOW_WPB, FEATURE_PODCASTS_PAGE, FEATURE_QR_CREATE_QR, FEATURE_QR_DYNAMIC_FRAME, FEATURE_QR_SCAN_FROM_PHOTO, FEATURE_QR_VISION_DECODER, FEATURE_QUEUE_COUNTERS, FEATURE_REEF, FEATURE_ROAMING_AUTOPLAY, FEATURE_SHARE_MSGS_ON_INVITE, FEATURE_STICKERS_BOT_LINK, FEATURE_STICKERS_NEW_CATALOG, FEATURE_STORIES_AVATAR, FEATURE_STORIES_FEED_TYPE, FEATURE_STORIES_SHOW_ALWAYS, FEATURE_STORY_ANSWER_PUBLIC, FEATURE_STORY_APP_STICKER, FEATURE_STORY_ARCHIVE, FEATURE_STORY_ARCHIVE_POST, FEATURE_STORY_BAKGROUND_ALL, FEATURE_STORY_BOX, FEATURE_STORY_CADRE, FEATURE_STORY_CAMERA_TOOLTIP, FEATURE_STORY_EDITOR_GALLERY, FEATURE_STORY_EDITOR_TYPE, FEATURE_STORY_ENDLESS_VIDEO, FEATURE_STORY_FAST_REACTIONS, FEATURE_STORY_GIF, FEATURE_STORY_GROUPED, FEATURE_STORY_HIGH_QUALITY, FEATURE_STORY_MASKS_FRONTAL, FEATURE_STORY_MENTION_ICON, FEATURE_STORY_MODERN_PUBLISH, FEATURE_STORY_MUSIC_EDITOR, FEATURE_STORY_MUSIC_REPLIES, FEATURE_STORY_MUSIC_REPLIES_2, FEATURE_STORY_NEW_FRAME, FEATURE_STORY_ONE_TIME, FEATURE_STORY_PHOTO_SHARING, FEATURE_STORY_PHOTO_STICKER, FEATURE_STORY_POLLS, FEATURE_STORY_POST_REPOST, FEATURE_STORY_PRELOADING, FEATURE_STORY_QUESTION, FEATURE_STORY_QUESTION_STYLE, FEATURE_STORY_RLOTTIE, FEATURE_STORY_RLOTTIE_CACHE, FEATURE_STORY_SAVE_DEFAULT_ON, FEATURE_STORY_SEND_DIALOG_LIST, FEATURE_STORY_STICKER_PACK, FEATURE_STORY_TIME, FEATURE_STORY_VIEWER_CAMERA, FEATURE_STORY_VOICE_ANSWER, FEATURE_STORY_WITH_CONTEXT, FEATURE_SUPERAPP_MENU, FEATURE_TRAFFIC_SAVER, FEATURE_VKPAY_WIDGET, FEATURE_VKUI_INTERNAL_TO_MINI_APPS, FEATURE_VKUI_TOKEN_CACHE, FEATURE_VK_APPS_SEARCH, FEATURE_VOTES_BALANCE, FEATURE_WEBVIEW_TOKEN_ACTIVE, FEATURE_MILKSHAKE_FORCE_DISABLED, FEATURE_MILKSHAKE_ACTIVATION_DISABLED, EXPERIMENT_NEWS_DISABLE_CACHE ->
|
||||
true;
|
||||
default -> false;
|
||||
};
|
||||
|
||||
@@ -5,19 +5,20 @@ import bruhcollective.itaysonlab.libvkx.client.LibVKXClient;
|
||||
import com.vk.core.network.Network;
|
||||
import com.vk.core.util.DeviceIdProvider;
|
||||
import okhttp3.Headers;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
|
||||
import ru.vtosters.lite.music.cache.MusicCacheImpl;
|
||||
import ru.vtosters.lite.utils.AccountManagerUtils;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.sponsorpost.utils.GzipDecompressor;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static com.vk.core.network.Network.ClientType.CLIENT_API;
|
||||
import static ru.vtosters.hooks.DateHook.getLocale;
|
||||
import static ru.vtosters.hooks.GroupsCatalogInjector.injectIntoCatalog;
|
||||
import static ru.vtosters.hooks.other.Preferences.getBoolValue;
|
||||
@@ -26,8 +27,6 @@ import static ru.vtosters.lite.proxy.ProxyUtils.getApi;
|
||||
import static ru.vtosters.lite.utils.AccountManagerUtils.getUserId;
|
||||
|
||||
public class CatalogJsonInjector {
|
||||
private static final OkHttpClient mClient = VtOkHttpClient.getInstance();
|
||||
|
||||
public static JSONObject music(JSONObject json) throws JSONException {
|
||||
var catalog = json.optJSONObject("catalog");
|
||||
var oldItems = catalog != null ? catalog.optJSONArray("sections") : null;
|
||||
@@ -263,9 +262,10 @@ public class CatalogJsonInjector {
|
||||
+ sectionUrl
|
||||
+ "&access_token="
|
||||
+ AccountManagerUtils.getUserToken())
|
||||
.a("Accept-Encoding", "gzip")
|
||||
.a(Headers.a("User-Agent", Network.l.c().a(), "Content-Type", "application/x-www-form-urlencoded; charset=utf-8")).a();
|
||||
try {
|
||||
var json = new JSONObject(mClient.a(request).execute().a().g()).getJSONObject("response");
|
||||
try (Response resp = Network.b(CLIENT_API).a(request).execute()) {
|
||||
var json = new JSONObject(GzipDecompressor.decompressResponse(resp)).getJSONObject("response");
|
||||
var catalogarr = json.optJSONObject("catalog").optJSONArray("sections").optJSONObject(0);
|
||||
|
||||
var title = catalogarr.optString("title");
|
||||
@@ -279,4 +279,4 @@ public class CatalogJsonInjector {
|
||||
Log.d("VTLMusic", "Error: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -311,6 +311,10 @@ public class Preferences {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String getId() {
|
||||
return String.valueOf(AccountManagerUtils.getUserId());
|
||||
}
|
||||
|
||||
public static void updateBuildNumber() {
|
||||
try {
|
||||
getPreferences().edit().putLong("setupTime", AndroidUtils.getGlobalContext().getPackageManager().getPackageInfo(AndroidUtils.getPackageName(), 0).lastUpdateTime).apply();
|
||||
|
||||
@@ -2,6 +2,7 @@ package ru.vtosters.hooks.other;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Color;
|
||||
@@ -73,7 +74,7 @@ public class ThemesUtils {
|
||||
}
|
||||
|
||||
public static boolean isMonetTheme() {
|
||||
return getBoolValue("monettheme", false) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S;
|
||||
return getBoolValue("monettheme", false);
|
||||
}
|
||||
|
||||
public static boolean isAmoledTheme() {
|
||||
@@ -340,7 +341,7 @@ public class ThemesUtils {
|
||||
}
|
||||
|
||||
public static int getColor(int i) {
|
||||
return ThemesHacks.getHackedColor(getGlobalContext(), i);
|
||||
return ThemesHacks.getHackedColor(LifecycleUtils.getCurrentActivity(), i);
|
||||
} // Android Support color injector + accent color checker
|
||||
|
||||
public static int getAlertStyle() {
|
||||
@@ -391,14 +392,14 @@ public class ThemesUtils {
|
||||
return vkme() ? R.dimen.app_minimumsize_h : Default;
|
||||
}
|
||||
|
||||
public static ColorStateList getCSTDock() {
|
||||
public static ColorStateList getCSTDock(Context ctx) {
|
||||
return new ColorStateList(
|
||||
new int[][]{
|
||||
new int[]{android.R.attr.state_checked},
|
||||
new int[]{-android.R.attr.state_checked}
|
||||
},
|
||||
new int[]{
|
||||
dockbar_accent() ? getAccentColor() : (isDarkTheme() ? getResources().getColor(R.color.white) : getResources().getColor(R.color.gray_700)),
|
||||
dockbar_accent() ? getAccentColor() : (isDarkTheme() ? ThemesHacks.getColors(ctx, R.color.white) : ThemesHacks.getColors(ctx, R.color.gray_700)),
|
||||
getColorFromAttr(R.attr.tabbar_inactive_icon)
|
||||
}
|
||||
);
|
||||
|
||||
@@ -10,4 +10,4 @@ public class VtOkHttpClient extends OkHttpClient {
|
||||
private static class LazyHolder {
|
||||
private static final VtOkHttpClient instance = new VtOkHttpClient();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import com.vk.im.engine.models.dialogs.Dialog;
|
||||
import com.vk.im.engine.models.messages.Msg;
|
||||
import com.vk.im.engine.utils.ImDialogsUtils;
|
||||
import okhttp3.Headers;
|
||||
import okhttp3.OkHttpClient;
|
||||
import ru.vtosters.hooks.other.ThemesUtils;
|
||||
import ru.vtosters.lite.concurrent.VTExecutors;
|
||||
import ru.vtosters.lite.net.Request;
|
||||
@@ -15,21 +14,49 @@ import ru.vtosters.lite.utils.AccountManagerUtils;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.LifecycleUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static com.vk.core.network.Network.ClientType.CLIENT_API;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.getApi;
|
||||
import static ru.vtosters.lite.utils.AccountManagerUtils.getUserToken;
|
||||
|
||||
public class Requests {
|
||||
public static void hookRead(Dialog dialog) {
|
||||
Request.makeRequest("https://" + ProxyUtils.getApi() + "/method/messages.markAsRead?start_message_id=" + dialog.F1() + "&peer_id=" + dialog.getId() + "&v=5.119&access_token=" + AccountManagerUtils.getUserToken(), response -> {
|
||||
});
|
||||
okhttp3.Request req = new okhttp3.Request.a()
|
||||
.b("https://" + ProxyUtils.getApi() + "/method/messages.markAsRead?start_message_id=" + dialog.F1() + "&peer_id=" + dialog.getId() + "&v=5.119&access_token=" + AccountManagerUtils.getUserToken())
|
||||
.a();
|
||||
|
||||
try {
|
||||
Network.b(CLIENT_API).a(req).execute().close();;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void hookReadStartMsgTo(Msg dialog) {
|
||||
Request.makeRequest("https://" + ProxyUtils.getApi() + "/method/messages.markAsRead?start_message_id=" + dialog.C1() + "&peer_id=" + dialog.v1() + "&v=5.119&access_token=" + AccountManagerUtils.getUserToken(), response -> {
|
||||
});
|
||||
okhttp3.Request req = new okhttp3.Request.a()
|
||||
.b("https://" + ProxyUtils.getApi() + "/method/messages.markAsRead?start_message_id=" + dialog.C1() + "&peer_id=" + dialog.v1() + "&v=5.119&access_token=" + AccountManagerUtils.getUserToken())
|
||||
.a();
|
||||
|
||||
try {
|
||||
Network.b(CLIENT_API).a(req).execute().close();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void hookKick(Msg dialog) {
|
||||
if (dialog.getFrom().t1() == AccountManagerUtils.getUserId()) return;
|
||||
Request.makeRequest("https://" + ProxyUtils.getApi() + "/method/messages.removeChatUser?member_id=" + dialog.getFrom().t1() + "&chat_id=" + ImDialogsUtils.c(dialog.v1()) + "&v=5.119&access_token=" + AccountManagerUtils.getUserToken(), response -> {
|
||||
});
|
||||
|
||||
okhttp3.Request req = new okhttp3.Request.a()
|
||||
.b("https://" + ProxyUtils.getApi() + "/method/messages.removeChatUser?member_id=" + dialog.getFrom().t1() + "&chat_id=" + ImDialogsUtils.c(dialog.v1()) + "&v=5.119&access_token=" + AccountManagerUtils.getUserToken())
|
||||
.a();
|
||||
|
||||
try {
|
||||
Network.b(CLIENT_API).a(req).execute().close();;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void hookDialogInfo(Dialog dialog) {
|
||||
@@ -51,7 +78,7 @@ public class Requests {
|
||||
.a(Headers.a("User-Agent", Network.l.c().a(), "Content-Type", "application/x-www-form-urlencoded; charset=utf-8"))
|
||||
.a();
|
||||
|
||||
new OkHttpClient().a(request).execute().a().g();
|
||||
Network.b(CLIENT_API).a(request).execute().a().g();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
package ru.vtosters.lite.downloaders;
|
||||
|
||||
import android.app.DownloadManager;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.media.MediaScannerConnection;
|
||||
import android.os.Environment;
|
||||
import com.vk.core.network.Network;
|
||||
import com.vk.dto.common.ImageSize;
|
||||
import com.vk.dto.stories.model.StoryEntry;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
import static ru.vtosters.lite.downloaders.VideoDownloader.downloadVideo;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
|
||||
|
||||
public class StoryDownloader {
|
||||
|
||||
public static void downloadStory(StoryEntry story) {
|
||||
if (story.T1()) {
|
||||
List<ImageSize> imageSizes = story.E.Q.t1();
|
||||
String url = imageSizes.get(imageSizes.size() - 1).url;
|
||||
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
|
||||
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
|
||||
request.setTitle("photo" + story.E.a + ".jpg");
|
||||
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_PICTURES, "photo" + story.E.a + ".jpg");
|
||||
request.allowScanningByMediaScanner();
|
||||
((DownloadManager) getGlobalContext().getSystemService(Context.DOWNLOAD_SERVICE)).enqueue(request);
|
||||
downloadImage(story);
|
||||
return;
|
||||
}
|
||||
// if story is a video
|
||||
@@ -31,4 +31,55 @@ public class StoryDownloader {
|
||||
downloadVideo(story.F, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void downloadImage(StoryEntry story) {
|
||||
List<ImageSize> imageSizes = story.E.Q.t1();
|
||||
String url = imageSizes.get(imageSizes.size() - 1).url;
|
||||
|
||||
OkHttpClient client = Network.b(Network.ClientType.CLIENT_IMAGE_LOADER);
|
||||
Request request = new Request.a()
|
||||
.b(url)
|
||||
.a();
|
||||
|
||||
try (Response response = client.a(request).execute()) {
|
||||
if (!response.h()) {
|
||||
throw new IOException("Unexpected code " + response);
|
||||
}
|
||||
|
||||
ResponseBody responseBody = response.a();
|
||||
|
||||
if (responseBody == null) {
|
||||
throw new IOException("No response body");
|
||||
}
|
||||
|
||||
String fileName = "photo" + story.E.a + ".jpg";
|
||||
File outputDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "/Stories/");
|
||||
|
||||
if (!outputDir.exists()) {
|
||||
outputDir.mkdirs();
|
||||
}
|
||||
|
||||
File outputFile = new File(outputDir, fileName);
|
||||
|
||||
try (InputStream inputStream = responseBody.a();
|
||||
FileOutputStream outputStream = new FileOutputStream(outputFile)) {
|
||||
|
||||
byte[] buffer = new byte[4096];
|
||||
int bytesRead;
|
||||
|
||||
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||
outputStream.write(buffer, 0, bytesRead);
|
||||
}
|
||||
outputStream.flush();
|
||||
|
||||
MediaScannerConnection.scanFile(AndroidUtils.getGlobalContext(), new String[]{outputFile.toString()}, null, null);
|
||||
|
||||
AndroidUtils.sendToast("Файл скачан в Pictures/Stories");
|
||||
} catch (IOException e) {
|
||||
e.fillInStackTrace();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.fillInStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
package ru.vtosters.lite.downloaders;
|
||||
|
||||
import android.app.DownloadManager;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.media.MediaScannerConnection;
|
||||
import android.os.Environment;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
@@ -13,35 +12,112 @@ import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import com.vk.core.dialogs.alert.VkAlertDialog;
|
||||
import com.vk.core.dialogs.bottomsheet.MenuBottomSheetAction;
|
||||
import com.vk.core.network.Network;
|
||||
import com.vk.core.util.ToastUtils;
|
||||
import com.vk.dto.common.VideoFile;
|
||||
import com.vk.dto.stories.model.StoryEntry;
|
||||
import com.vtosters.lite.R;
|
||||
import okhttp3.*;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.LifecycleUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.vk.core.network.Network.ClientType.CLIENT_API;
|
||||
import static ru.vtosters.hooks.other.ThemesUtils.getTextAttr;
|
||||
import static ru.vtosters.lite.net.Request.makeRequest;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.getApi;
|
||||
import static ru.vtosters.lite.utils.AccountManagerUtils.getUserToken;
|
||||
|
||||
public class VideoDownloader {
|
||||
public static final int DOWNLOAD_ID = 0;
|
||||
public static final int OPEN_EXTERNAL_LINK_ID = 1;
|
||||
public static int DOWNLOAD_ID = 0;
|
||||
public static int OPEN_EXTERNAL_LINK_ID = 1;
|
||||
|
||||
public static void addAction(List<MenuBottomSheetAction> actions, int... ints) {
|
||||
actions.add(new MenuBottomSheetAction(ints[0], ints[1], ints[2], ints[3]));
|
||||
}
|
||||
|
||||
public static void downloadVideo(VideoFile videoFile, Context context) {
|
||||
final List<String> qualities = new ArrayList<>();
|
||||
final List<String> urls = new ArrayList<>();
|
||||
List<String> qualities = new ArrayList<>();
|
||||
List<String> urls = new ArrayList<>();
|
||||
|
||||
addVideos(videoFile, qualities, urls);
|
||||
|
||||
Context finalContext = context != null ? context : LifecycleUtils.getCurrentActivity();
|
||||
|
||||
if (qualities.isEmpty()) {
|
||||
ToastUtils.a(finalContext.getString(R.string.videodownloaderr));
|
||||
return;
|
||||
}
|
||||
|
||||
var adapter = new ArrayAdapter(
|
||||
finalContext,
|
||||
android.R.layout.simple_list_item_1,
|
||||
qualities.toArray(new String[0])) {
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
TextView textView = (TextView) super.getView(position, convertView, parent);
|
||||
textView.setTextColor(getTextAttr());
|
||||
return textView;
|
||||
}
|
||||
};
|
||||
|
||||
new VkAlertDialog.Builder(finalContext)
|
||||
.setAdapter(adapter, (dialog, which) -> {
|
||||
String url = urls.get(which);
|
||||
|
||||
OkHttpClient client = Network.b(Network.ClientType.CLIENT_IMAGE_LOADER);;
|
||||
Request request = new Request.a()
|
||||
.b(url)
|
||||
.a();
|
||||
|
||||
try (Response response = client.a(request).execute()) {
|
||||
if (!response.h()) {
|
||||
throw new IOException("Unexpected code " + response);
|
||||
}
|
||||
|
||||
ResponseBody responseBody = response.a();
|
||||
|
||||
File outputDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES), "/VKVideo/");
|
||||
|
||||
if (!outputDir.exists()) {
|
||||
outputDir.mkdirs();
|
||||
}
|
||||
|
||||
File outputFile = new File(outputDir, videoFile + ".mp4");
|
||||
|
||||
try (InputStream inputStream = responseBody.a();
|
||||
FileOutputStream outputStream = new FileOutputStream(outputFile)) {
|
||||
|
||||
byte[] buffer = new byte[4096];
|
||||
int bytesRead;
|
||||
|
||||
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||
outputStream.write(buffer, 0, bytesRead);
|
||||
}
|
||||
outputStream.flush();
|
||||
|
||||
MediaScannerConnection.scanFile(finalContext, new String[]{outputFile.toString()}, null, null);
|
||||
|
||||
AndroidUtils.sendToast("Файл скачан в Movies/VKVideo");
|
||||
} catch (IOException e) {
|
||||
e.fillInStackTrace();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
})
|
||||
.show();
|
||||
}
|
||||
|
||||
public static void addVideos(VideoFile videoFile, List<String> qualities, List<String> urls) {
|
||||
if (!TextUtils.isEmpty(videoFile.D)) {
|
||||
qualities.add("2160p");
|
||||
urls.add(videoFile.D);
|
||||
@@ -75,40 +151,6 @@ public class VideoDownloader {
|
||||
qualities.add("240p");
|
||||
urls.add(videoFile.e);
|
||||
}
|
||||
|
||||
Context finalContext = context != null ? context : LifecycleUtils.getCurrentActivity();
|
||||
|
||||
if (qualities.isEmpty()) {
|
||||
ToastUtils.a(finalContext.getString(R.string.videodownloaderr));
|
||||
return;
|
||||
}
|
||||
|
||||
var adapter = new ArrayAdapter(
|
||||
finalContext,
|
||||
android.R.layout.simple_list_item_1,
|
||||
qualities.toArray(new String[0])) {
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
TextView textView = (TextView) super.getView(position, convertView, parent);
|
||||
textView.setTextColor(getTextAttr());
|
||||
return textView;
|
||||
}
|
||||
};
|
||||
|
||||
new VkAlertDialog.Builder(finalContext)
|
||||
.setAdapter(adapter, (dialog, which) -> {
|
||||
try {
|
||||
var url = urls.get(which);
|
||||
var request = new DownloadManager.Request(Uri.parse(url))
|
||||
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
|
||||
.setTitle(videoFile.toString())
|
||||
.setDestinationInExternalPublicDir(Environment.DIRECTORY_MOVIES, videoFile + ".mp4");
|
||||
request.allowScanningByMediaScanner();
|
||||
((DownloadManager) finalContext.getSystemService(Context.DOWNLOAD_SERVICE)).enqueue(request);
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
})
|
||||
.show();
|
||||
}
|
||||
|
||||
public static void parseVideoLink(String url, Context ctx) {
|
||||
@@ -124,20 +166,34 @@ public class VideoDownloader {
|
||||
progressDialog.setMessage(ctx.getString(R.string.video_dl_progress));
|
||||
progressDialog.show();
|
||||
|
||||
makeRequest("https://" + getApi() + "/method/stories.getById?stories=" + storyId + "&v=5.99&access_token=" + getUserToken(),
|
||||
response -> {
|
||||
progressDialog.cancel();
|
||||
var req = new Request.a()
|
||||
.b("https://" + getApi() + "/method/stories.getById?stories=" + storyId + "&v=5.99&access_token=" + getUserToken())
|
||||
.a();
|
||||
|
||||
Network.b(CLIENT_API).a(req).a(new Callback() {
|
||||
|
||||
try {
|
||||
JSONObject mainJson = new JSONObject(response);
|
||||
JSONObject responseJson = mainJson.getJSONObject("response").optJSONArray("items").optJSONObject(0);
|
||||
StoryEntry story = new StoryEntry(responseJson);
|
||||
StoryDownloader.downloadStory(story);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
Toast.makeText(ctx, ctx.getString(R.string.video_dl_error), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
@Override
|
||||
public void a(Call call, IOException e) {
|
||||
e.fillInStackTrace();
|
||||
Toast.makeText(ctx, ctx.getString(R.string.video_dl_error), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(Call call, Response response) throws IOException {
|
||||
progressDialog.cancel();
|
||||
|
||||
try {
|
||||
JSONObject mainJson = new JSONObject(response.a().g());
|
||||
JSONObject responseJson = mainJson.getJSONObject("response").optJSONArray("items").optJSONObject(0);
|
||||
StoryEntry story = new StoryEntry(responseJson);
|
||||
StoryDownloader.downloadStory(story);
|
||||
} catch (JSONException e) {
|
||||
e.fillInStackTrace();
|
||||
Toast.makeText(ctx, ctx.getString(R.string.video_dl_error), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -149,25 +205,37 @@ public class VideoDownloader {
|
||||
String videoId = url.split("video")[1];
|
||||
String ownerId = videoId.split("_")[0];
|
||||
|
||||
final ProgressDialog progressDialog = new ProgressDialog(ctx);
|
||||
ProgressDialog progressDialog = new ProgressDialog(ctx);
|
||||
progressDialog.setMessage(ctx.getString(R.string.video_dl_progress));
|
||||
progressDialog.show();
|
||||
|
||||
makeRequest("https://" + getApi() + "/method/video.get?owner_id=" + ownerId + "&videos=" + videoId + "&v=5.99&access_token=" + getUserToken(),
|
||||
response -> {
|
||||
progressDialog.cancel();
|
||||
var req = new Request.a()
|
||||
.b("https://" + getApi() + "/method/video.get?owner_id=" + ownerId + "&videos=" + videoId + "&v=5.99&access_token=" + getUserToken())
|
||||
.a();
|
||||
|
||||
try {
|
||||
JSONObject mainJson = new JSONObject(response);
|
||||
JSONObject responseJson = mainJson.getJSONObject("response");
|
||||
JSONArray itemsJson = responseJson.getJSONArray("items");
|
||||
Network.b(CLIENT_API).a(req).a(new Callback() {
|
||||
@Override
|
||||
public void a(Call call, IOException e) {
|
||||
e.fillInStackTrace();
|
||||
Toast.makeText(ctx, ctx.getString(R.string.video_dl_error), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
VideoFile videoFile = new VideoFile(itemsJson.getJSONObject(0));
|
||||
downloadVideo(videoFile, ctx);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
Toast.makeText(ctx, ctx.getString(R.string.video_dl_error), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
@Override
|
||||
public void a(Call call, Response response) throws IOException {
|
||||
progressDialog.cancel();
|
||||
|
||||
try {
|
||||
JSONObject mainJson = new JSONObject(response.a().g());
|
||||
JSONObject responseJson = mainJson.getJSONObject("response");
|
||||
JSONArray itemsJson = responseJson.getJSONArray("items");
|
||||
|
||||
VideoFile videoFile = new VideoFile(itemsJson.getJSONObject(0));
|
||||
downloadVideo(videoFile, ctx);
|
||||
} catch (JSONException e) {
|
||||
e.fillInStackTrace();
|
||||
Toast.makeText(ctx, ctx.getString(R.string.video_dl_error), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package ru.vtosters.lite.downloaders.messages;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.vk.core.network.Network;
|
||||
import com.vk.core.util.ToastUtils;
|
||||
import com.vtosters.lite.R;
|
||||
import okhttp3.Call;
|
||||
@@ -12,12 +13,12 @@ import okhttp3.Response;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
|
||||
import ru.vtosters.lite.downloaders.messages.items.MiniMsg;
|
||||
import ru.vtosters.lite.downloaders.messages.items.MiniUser;
|
||||
import ru.vtosters.lite.proxy.ProxyUtils;
|
||||
import ru.vtosters.lite.utils.AccountManagerUtils;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.sponsorpost.utils.GzipDecompressor;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
@@ -28,6 +29,8 @@ import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import static com.vk.core.network.Network.ClientType.CLIENT_API;
|
||||
|
||||
public class MessagesDownloader {
|
||||
private static final int[] VIDEO_QUALITIES = {144, 240, 360, 480, 720, 1080, 1440, 2160};
|
||||
|
||||
@@ -104,8 +107,9 @@ public class MessagesDownloader {
|
||||
AccountManagerUtils.getUserToken());
|
||||
var req = new Request.a()
|
||||
.b(url)
|
||||
.a("Accept-Encoding", "gzip")
|
||||
.a();
|
||||
VtOkHttpClient.getInstance().a(req).a(new Callback() {
|
||||
Network.b(CLIENT_API).a(req).a(new Callback() {
|
||||
@Override
|
||||
public void a(Call call, IOException e) {
|
||||
Log.d("MessagesDownloader", e.getMessage());
|
||||
@@ -114,7 +118,7 @@ public class MessagesDownloader {
|
||||
@Override
|
||||
public void a(Call call, Response response) {
|
||||
try {
|
||||
JSONObject obj = new JSONObject(response.a().g()).getJSONObject("response");
|
||||
JSONObject obj = new JSONObject(GzipDecompressor.decompressResponse(response)).getJSONObject("response");
|
||||
|
||||
SparseArray<MiniUser> users = new SparseArray<>();
|
||||
parseUsers(users, obj.optJSONArray("profiles"), false);
|
||||
|
||||
@@ -6,43 +6,44 @@ import android.util.Log;
|
||||
import com.vk.core.dialogs.alert.VkAlertDialog;
|
||||
import com.vtosters.lite.R;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
|
||||
import ru.vtosters.lite.net.Request;
|
||||
import ru.vtosters.lite.proxy.ProxyUtils;
|
||||
import ru.vtosters.lite.proxy.api.VikaMobile;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.LifecycleUtils;
|
||||
import ru.vtosters.sponsorpost.utils.GzipDecompressor;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static android.widget.Toast.LENGTH_SHORT;
|
||||
import static android.widget.Toast.makeText;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.getApi;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.isAnyProxyEnabled;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
|
||||
|
||||
public class FoafBase {
|
||||
private static final Pattern FOAF_REGEX = Pattern.compile("<ya:created dc:date=\"(.+?)\"");
|
||||
private static final String DELETED = "<ya:profileState>deleted</ya:profileState>";
|
||||
private static final String API_VKNEXT = "https://api.vtosters.app/v1/getBypassedOnlineInfo?json=1&ids=";
|
||||
private static final OkHttpClient client = VtOkHttpClient.getInstance();
|
||||
|
||||
public static JSONObject getBypassedOnlineInfo(int id) throws JSONException {
|
||||
var request = new okhttp3.Request.a()
|
||||
Request request = new Request.a()
|
||||
.b(API_VKNEXT + id)
|
||||
.a("Accept-Encoding", "gzip")
|
||||
.a();
|
||||
|
||||
String response;
|
||||
|
||||
var dummy = new JSONObject();
|
||||
JSONObject dummy = new JSONObject();
|
||||
dummy.put("last_seen", 0);
|
||||
|
||||
try {
|
||||
response = client.a(request).execute().a().g();
|
||||
var online_info = new JSONObject(response).optJSONObject("response").optJSONObject(Integer.toString(id));
|
||||
try (Response response = client.a(request).execute()) {
|
||||
JSONObject online_info = new JSONObject(GzipDecompressor.decompressResponse(response)).getJSONObject("response").optJSONObject(Integer.toString(id));
|
||||
return online_info == null ? dummy : online_info;
|
||||
} catch (Exception e) {
|
||||
Log.e("GetBypassedOnlineInfo", e.getMessage());
|
||||
@@ -51,17 +52,15 @@ public class FoafBase {
|
||||
}
|
||||
|
||||
public static JSONObject getBypassedOnlineInfo(String ids) {
|
||||
var request = new okhttp3.Request.a()
|
||||
Request request = new Request.a()
|
||||
.b(API_VKNEXT + ids)
|
||||
.a("Accept-Encoding", "gzip")
|
||||
.a();
|
||||
|
||||
String response;
|
||||
JSONObject dummy = new JSONObject();
|
||||
|
||||
var dummy = new JSONObject();
|
||||
|
||||
try {
|
||||
response = client.a(request).execute().a().g();
|
||||
var online_info = new JSONObject(response).optJSONObject("response");
|
||||
try (Response response = client.a(request).execute()) {
|
||||
JSONObject online_info = new JSONObject(GzipDecompressor.decompressResponse(response)).getJSONObject("response").optJSONObject("response");
|
||||
return online_info == null ? dummy : online_info;
|
||||
} catch (Exception e) {
|
||||
Log.e("GetBypassedOnlineInfo1", e.getMessage());
|
||||
@@ -70,18 +69,8 @@ public class FoafBase {
|
||||
}
|
||||
|
||||
private static String getLink(int i) {
|
||||
String str;
|
||||
StringBuilder sb;
|
||||
if (isAnyProxyEnabled()) {
|
||||
sb = new StringBuilder();
|
||||
str = "https://" + getApi() + "/_/vk.com/foaf.php?id=";
|
||||
} else {
|
||||
sb = new StringBuilder();
|
||||
str = "https://vk.com/foaf.php?id=";
|
||||
}
|
||||
sb.append(str);
|
||||
sb.append(i);
|
||||
return sb.toString();
|
||||
String prefix = (ProxyUtils.isAnyProxyEnabled() || ProxyUtils.isVKProxyEnabled()) ? "https://" + (ProxyUtils.isVKProxyEnabled() ? VikaMobile.getApiHost() : ProxyUtils.getApi()) + "/_/vk.com/foaf.php?id=" : "https://vk.com/foaf.php?id=";
|
||||
return prefix + i;
|
||||
}
|
||||
|
||||
public static void loadAndShow(Context context, int i) {
|
||||
@@ -90,49 +79,69 @@ public class FoafBase {
|
||||
progressDialog.setCancelable(false);
|
||||
progressDialog.show();
|
||||
|
||||
Request.RequestCallback callback = str -> FoafBase.lambdaLoadAndShow(progressDialog, context, i, str);
|
||||
Request.makeRequest(getLink(i), callback);
|
||||
Request request = new Request.a()
|
||||
.b(getLink(i))
|
||||
.a();
|
||||
|
||||
try (Response response = client.a(request).execute()) {
|
||||
LifecycleUtils.getCurrentActivity().runOnUiThread(() -> {
|
||||
try {
|
||||
showFoafInfo(progressDialog, context, i, response.a().g());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
Log.e("FoafBase", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
static void lambdaLoadAndShow(ProgressDialog progressDialog, Context context, int i, String str) {
|
||||
try {
|
||||
progressDialog.cancel();
|
||||
Matcher matcher = FOAF_REGEX.matcher(str);
|
||||
matcher.find();
|
||||
private static void showFoafInfo(ProgressDialog progressDialog, Context context, int i, String str) {
|
||||
progressDialog.cancel();
|
||||
Optional<String> foafDate = findPattern(str, FOAF_REGEX);
|
||||
|
||||
String m = matcher.group(1);
|
||||
Log.e("FoafBase", str);
|
||||
|
||||
if (m == null) {
|
||||
LifecycleUtils.getCurrentActivity().runOnUiThread(() -> makeText(getGlobalContext(), context.getString(R.string.foaferr), LENGTH_SHORT).show());
|
||||
return;
|
||||
}
|
||||
|
||||
String normalHumanDate = getNormalHumanDate(m);
|
||||
|
||||
LifecycleUtils.getCurrentActivity().runOnUiThread(() -> new VkAlertDialog.Builder(context)
|
||||
.setTitle(R.string.addinf)
|
||||
.setMessage(context.getString(R.string.foafid) +
|
||||
" " + i + context.getString(R.string.foafregdate)
|
||||
+ " " + normalHumanDate + context.getString(R.string.foafdate)
|
||||
+ " " + daysPassedFromFoafDate(normalHumanDate))
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.show());
|
||||
} catch (Exception e) {
|
||||
LifecycleUtils.getCurrentActivity().runOnUiThread(() -> makeText(getGlobalContext(), context.getString(R.string.foaferr), LENGTH_SHORT).show());
|
||||
if (foafDate.isPresent()) {
|
||||
String normalHumanDate = getNormalHumanDate(foafDate.get());
|
||||
long daysPassed = daysPassedFromFoafDate(normalHumanDate);
|
||||
showFoafDialog(context, i, normalHumanDate, daysPassed);
|
||||
} else if (str.contains(DELETED)) {
|
||||
AndroidUtils.sendToast("Профиль удален или не существует (аккаунт VK Мессенджера)");
|
||||
} else {
|
||||
AndroidUtils.sendToast(context.getString(R.string.foaferr));
|
||||
}
|
||||
}
|
||||
|
||||
private static Optional<String> findPattern(String str, Pattern pattern) {
|
||||
Matcher matcher = pattern.matcher(str);
|
||||
if (matcher.find() && matcher.groupCount() != 0) {
|
||||
return Optional.ofNullable(matcher.group(1));
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private static void showFoafDialog(Context context, int i, String normalHumanDate, long daysPassed) {
|
||||
String message = String.format("%s %d%s %s%s %d", context.getString(R.string.foafid), i, context.getString(R.string.foafregdate), normalHumanDate, context.getString(R.string.foafdate), daysPassed);
|
||||
new VkAlertDialog.Builder(context)
|
||||
.setTitle(R.string.addinf)
|
||||
.setMessage(message)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.show();
|
||||
}
|
||||
|
||||
private static long daysPassedFromFoafDate(String str) {
|
||||
try {
|
||||
Date parse = new SimpleDateFormat("yyyy-MM-dd").parse(str.split(" ")[1]);
|
||||
return TimeUnit.DAYS.convert(new Date().getTime() - parse.getTime(), TimeUnit.MILLISECONDS);
|
||||
} catch (ParseException e) {
|
||||
LocalDate foafDate = LocalDate.parse(str.split(" ")[1]);
|
||||
return ChronoUnit.DAYS.between(foafDate, LocalDate.now());
|
||||
} catch (DateTimeParseException e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private static String getNormalHumanDate(String str) {
|
||||
String[] split = str.split("T");
|
||||
return split[1].split("\\+")[0] + " " + split[0];
|
||||
OffsetDateTime dateTime = OffsetDateTime.parse(str);
|
||||
return dateTime.format(DateTimeFormatter.ofPattern("HH:mm:ss yyyy-MM-dd"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,9 @@ import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
|
||||
import ru.vtosters.lite.music.downloader.M3UDownloader;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.sponsorpost.utils.GzipDecompressor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
@@ -22,10 +24,10 @@ public class Genius {
|
||||
private static final OkHttpClient client = VtOkHttpClient.getInstance();
|
||||
|
||||
public static String getTextMusic(MusicTrack musictrack) {
|
||||
var uid = musictrack.y1();
|
||||
var artist = removeExtras(musictrack.C);
|
||||
var title = removeExtras(musictrack.f);
|
||||
var duration = musictrack.h;
|
||||
String uid = musictrack.y1();
|
||||
String artist = removeExtras(M3UDownloader.getArtists(musictrack));
|
||||
String title = removeExtras(musictrack.f);
|
||||
int duration = musictrack.h;
|
||||
|
||||
if (TextUtils.isEmpty(uid) || TextUtils.isEmpty(artist) || TextUtils.isEmpty(title) || duration == 0) {
|
||||
Log.d("Genius", "grabTrackInfo: " + "Empty track, info: " + artist + " - " + title + " - " + duration + " - " + uid);
|
||||
@@ -42,17 +44,18 @@ public class Genius {
|
||||
}
|
||||
|
||||
Request request = new Request.a()
|
||||
.b(URL + "/search/songs?q=" + URLEncoder.encode(artist + " " + track) + "&from_background=0" + "&page=1")
|
||||
.a("User-Agent", "Genius/5.14.0 (Android; Android 13; Google Pixel 4 XL)")
|
||||
.b(String.format("%s/search/songs?q=%s&from_background=0&page=1", URL, URLEncoder.encode(artist + " " + track)))
|
||||
.a("User-Agent", "Genius/5.21.3 (Android; Android 13; Google Pixel 4 XL)")
|
||||
.a("Authorization", KEY)
|
||||
.a("x-genius-app-background-request", "0")
|
||||
.a("x-genius-logged-out", "true")
|
||||
.a("host", "api.genius.com")
|
||||
.a("Content-Type", "application/x-www-form-urlencoded")
|
||||
.a("Accept-Encoding", "gzip")
|
||||
.b()
|
||||
.a();
|
||||
try (Response resp = client.a(request).execute()) {
|
||||
String payload = resp.a().g();
|
||||
String payload = GzipDecompressor.decompressResponse(resp);
|
||||
JSONArray sections = new JSONObject(payload).getJSONObject("response").getJSONArray("sections");
|
||||
|
||||
for (int i = 0; i < sections.length(); i++) {
|
||||
@@ -86,17 +89,18 @@ public class Genius {
|
||||
|
||||
private static String getText(String track) {
|
||||
Request request = new Request.a()
|
||||
.b(URL + track + "?text_format=plain")
|
||||
.a("User-Agent", "Genius/5.14.0 (Android; Android 13; Google Pixel 4 XL)")
|
||||
.b(String.format("%s%s?text_format=plain", URL, track))
|
||||
.a("User-Agent", "Genius/5.21.3 (Android; Android 13; Google Pixel 4 XL)")
|
||||
.a("Authorization", KEY)
|
||||
.a("x-genius-app-background-request", "0")
|
||||
.a("x-genius-logged-out", "true")
|
||||
.a("host", "api.genius.com")
|
||||
.a("Content-Type", "application/x-www-form-urlencoded")
|
||||
.a("Accept-Encoding", "gzip")
|
||||
.b()
|
||||
.a();
|
||||
try {
|
||||
JSONObject payload = new JSONObject(client.a(request).execute().a().g());
|
||||
try (Response resp = client.a(request).execute()) {
|
||||
JSONObject payload = new JSONObject(GzipDecompressor.decompressResponse(resp));
|
||||
|
||||
if (!payload.has("response")) {
|
||||
return AndroidUtils.getString("error_no_text");
|
||||
@@ -107,4 +111,4 @@ public class Genius {
|
||||
return AndroidUtils.getString("error_no_text") + "\n\n" + AndroidUtils.getString(R.string.error) + ": \n" + e.getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
|
||||
import ru.vtosters.lite.downloaders.AudioDownloader;
|
||||
import ru.vtosters.lite.music.cache.MusicCacheImpl;
|
||||
import ru.vtosters.lite.music.downloader.M3UDownloader;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -32,7 +33,7 @@ public class LastFMScrobbler {
|
||||
|
||||
public static void grabMusicTrack(MusicTrack musictrack) {
|
||||
var uid = musictrack.y1();
|
||||
var artist = musictrack.C;
|
||||
var artist = M3UDownloader.getArtists(musictrack);
|
||||
var title = musictrack.f;
|
||||
var duration = musictrack.h;
|
||||
var track_id = musictrack.d;
|
||||
@@ -83,12 +84,12 @@ public class LastFMScrobbler {
|
||||
params.put("sk", getSessionKey());
|
||||
params.put("artist[0]", artist);
|
||||
params.put("track[0]", title);
|
||||
if (!TextUtils.isEmpty(album))
|
||||
if (!TextUtils.isEmpty(album)) {
|
||||
params.put("album[0]", album);
|
||||
}
|
||||
params.put("duration[0]", String.valueOf(duration));
|
||||
params.put("timestamp[0]", String.valueOf(System.currentTimeMillis() / 1000));
|
||||
|
||||
|
||||
fetch(params, new Callback() {
|
||||
@Override
|
||||
public void a(Call call, IOException e) {
|
||||
@@ -150,8 +151,9 @@ public class LastFMScrobbler {
|
||||
params.put("format", "json");
|
||||
|
||||
var reqBodyBuilder = new FormBody.a(StandardCharsets.UTF_8);
|
||||
for (var entry : params.entrySet())
|
||||
for (var entry : params.entrySet()) {
|
||||
reqBodyBuilder.a(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
var req = new Request.a()
|
||||
.b(URL)
|
||||
@@ -164,6 +166,7 @@ public class LastFMScrobbler {
|
||||
public static void fetchSession(JSONObject json) throws JSONException {
|
||||
if (!json.has("session")) {
|
||||
Log.d("Scrobbler", "Auth failed - no session");
|
||||
AndroidUtils.sendToast("Ошибка входа");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -177,6 +180,8 @@ public class LastFMScrobbler {
|
||||
.putBoolean("lastfm_enabled", true)
|
||||
.apply();
|
||||
|
||||
AndroidUtils.sendToast("Успешный вход");
|
||||
|
||||
Log.d("Scrobbler", "Auth success as " + name + ", key " + key);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import bruhcollective.itaysonlab.libvkx.ILibVkxService;
|
||||
import bruhcollective.itaysonlab.libvkx.client.LibVKXClient;
|
||||
import bruhcollective.itaysonlab.libvkx.client.LibVKXClientImpl;
|
||||
import com.vk.dto.music.MusicTrack;
|
||||
import ru.vtosters.lite.music.downloader.M3UDownloader;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.music.MusicCacheStorageUtils;
|
||||
|
||||
@@ -19,7 +20,7 @@ public class MusicCacheImpl {
|
||||
track.I != null ? track.I.getId() + "" : "-1",
|
||||
track.f,
|
||||
!TextUtils.isEmpty(track.g) ? track.g : "",
|
||||
track.C,
|
||||
M3UDownloader.getArtists(track),
|
||||
track.I != null ? track.I.getTitle() : "",
|
||||
track.K,
|
||||
track.h,
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.vk.dto.music.AlbumLink;
|
||||
import com.vk.dto.music.MusicTrack;
|
||||
import com.vk.dto.music.Thumb;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.lite.music.downloader.M3UDownloader;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.music.MusicCacheStorageUtils;
|
||||
|
||||
@@ -116,7 +117,7 @@ public class MusicCacheDb extends SQLiteOpenHelper implements AutoCloseable { //
|
||||
vals.put(Constants.COLUMN_ALBUM_ID, track.I != null ? track.I.getId() + "" : "-1");
|
||||
vals.put(Constants.COLUMN_TITLE, track.f);
|
||||
vals.put(Constants.COLUMN_SUBTITLE, track.g);
|
||||
vals.put(Constants.COLUMN_ARTIST, track.C);
|
||||
vals.put(Constants.COLUMN_ARTIST, M3UDownloader.getArtists(track));
|
||||
vals.put(Constants.COLUMN_ALBUM_TITLE, track.I != null ? track.I.getTitle() : "");
|
||||
vals.put(Constants.COLUMN_EXPLICIT, Boolean.compare(track.K, true));
|
||||
vals.put(Constants.COLUMN_DURATION, track.h);
|
||||
|
||||
@@ -7,6 +7,7 @@ import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.lite.music.cache.MusicCacheImpl;
|
||||
import ru.vtosters.lite.music.downloader.M3UDownloader;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.music.MusicCacheStorageUtils;
|
||||
|
||||
@@ -33,7 +34,7 @@ public class PlaylistHelper {
|
||||
return createAlbum(
|
||||
thumb != null ? thumb.h(600) : "",
|
||||
albumLink.getTitle(),
|
||||
track.C,
|
||||
M3UDownloader.getArtists(track),
|
||||
track.y1(),
|
||||
albumLink.getId()
|
||||
);
|
||||
@@ -75,7 +76,7 @@ public class PlaylistHelper {
|
||||
list.add(createAlbum(
|
||||
thumb != null ? thumb.h(600) : "",
|
||||
albumLink.getTitle(),
|
||||
track.C,
|
||||
M3UDownloader.getArtists(track),
|
||||
track.y1(),
|
||||
albumLink.getId()
|
||||
));
|
||||
|
||||
@@ -6,12 +6,13 @@ import com.vk.dto.music.MusicTrack;
|
||||
import com.vk.dto.music.Playlist;
|
||||
import java8.util.concurrent.CompletableFuture;
|
||||
import okhttp3.Headers;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.lite.utils.AccountManagerUtils;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.sponsorpost.utils.GzipDecompressor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
@@ -19,6 +20,7 @@ import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.vk.core.network.Network.ClientType.CLIENT_API;
|
||||
import static ru.vtosters.hooks.DateHook.getLocale;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.getApi;
|
||||
|
||||
@@ -50,17 +52,17 @@ public class PlaylistConverter {
|
||||
|
||||
var request = new Request.a()
|
||||
.b(requestUrl)
|
||||
.a("Accept-Encoding", "gzip")
|
||||
.a(Headers.a("User-Agent", Network.l.c().a(), "Content-Type", "application/x-www-form-urlencoded; charset=utf-8")).a();
|
||||
|
||||
try {
|
||||
var response = CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
return new OkHttpClient().a(request).execute().a().g();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
).get();
|
||||
try (Response resp = Network.b(CLIENT_API).a(request).execute()) {
|
||||
return GzipDecompressor.decompressResponse(resp);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}).get();
|
||||
var jsonObj = new JSONObject(response);
|
||||
if (!jsonObj.has("response"))
|
||||
return null;
|
||||
|
||||
@@ -6,11 +6,12 @@ import com.vk.core.util.DeviceIdProvider;
|
||||
import com.vk.dto.music.MusicTrack;
|
||||
import java8.util.concurrent.CompletableFuture;
|
||||
import okhttp3.Headers;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.sponsorpost.utils.GzipDecompressor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
@@ -18,6 +19,7 @@ import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.vk.core.network.Network.ClientType.CLIENT_API;
|
||||
import static ru.vtosters.hooks.DateHook.getLocale;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.getApi;
|
||||
import static ru.vtosters.lite.utils.AccountManagerUtils.getUserId;
|
||||
@@ -44,12 +46,13 @@ public class AudioGet {
|
||||
|
||||
var request = new Request.a()
|
||||
.b(requestUrl)
|
||||
.a("Accept-Encoding", "gzip")
|
||||
.a(Headers.a("User-Agent", Network.l.c().a(), "Content-Type", "application/x-www-form-urlencoded; charset=utf-8")).a();
|
||||
|
||||
try {
|
||||
var response = CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
return new OkHttpClient().a(request).execute().a().g();
|
||||
try (Response resp = Network.b(CLIENT_API).a(request).execute()) {
|
||||
return GzipDecompressor.decompressResponse(resp);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.util.Log;
|
||||
import com.google.android.exoplayer2.source.hls.playlist.e;
|
||||
import com.google.android.exoplayer2.source.hls.playlist.f;
|
||||
import com.google.android.exoplayer2.source.hls.playlist.f.a;
|
||||
import com.vk.dto.music.Artist;
|
||||
import com.vk.dto.music.MusicTrack;
|
||||
import java8.util.concurrent.CompletableFuture;
|
||||
import java8.util.concurrent.CompletionException;
|
||||
@@ -26,6 +27,7 @@ import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class M3UDownloader
|
||||
implements ITrackDownloader {
|
||||
@@ -151,7 +153,7 @@ public class M3UDownloader
|
||||
}
|
||||
|
||||
static File getResultMp3File(File outDir, boolean cache, MusicTrack track) {
|
||||
return new File(outDir, IOUtils.getValidFileName((cache ? "track" : track.C + " - " + getTitle(track)) + ".mp3"));
|
||||
return new File(outDir, IOUtils.getValidFileName((cache ? "track" : getArtists(track) + " - " + getTitle(track)) + ".mp3"));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -178,4 +180,14 @@ public class M3UDownloader
|
||||
private static class Holder {
|
||||
private static final M3UDownloader INSTANCE = new M3UDownloader();
|
||||
}
|
||||
}
|
||||
|
||||
public static String getArtists(MusicTrack track) {
|
||||
return (track.L == null || track.I == null
|
||||
? normalizeMetadata(track.C)
|
||||
: normalizeMetadata(track.L.stream().map(Artist::w1).collect(Collectors.joining(", "))));
|
||||
}
|
||||
|
||||
private static String normalizeMetadata(String in) {
|
||||
return in.replaceAll("[\\\\/:*?\"<>|]", "");
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package ru.vtosters.lite.proxy;
|
||||
|
||||
import android.util.Log;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class GithubList {
|
||||
private static final OkHttpClient mClient = VtOkHttpClient.getInstance();
|
||||
|
||||
public static ArrayList<String> getProxy(String url, String proxyname) throws IOException {
|
||||
Request link = new Request.a()
|
||||
.b(url)
|
||||
.a();
|
||||
|
||||
try {
|
||||
var response = mClient.a(link).execute().a().g();
|
||||
|
||||
if (!response.contains(":")) {
|
||||
Log.d(proxyname, "No proxy found");
|
||||
return null;
|
||||
}
|
||||
|
||||
Log.d(proxyname, response);
|
||||
|
||||
return new ArrayList<>(Arrays.asList(response.split("\n")));
|
||||
} catch (Exception e) {
|
||||
Log.d(proxyname, "Failed to fetch data, link: " + link);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
import com.vk.core.network.Network;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.proxy.http.CustomHttp;
|
||||
import ru.vtosters.lite.proxy.https.CustomHttps;
|
||||
@@ -62,16 +63,15 @@ public class ProxyUtils {
|
||||
}
|
||||
|
||||
public static Boolean isAnyProxyEnabled() {
|
||||
return isApiProxyEnabled() || isVikaProxyEnabled();
|
||||
return (isApiProxyEnabled() || isVikaProxyEnabled()) && !isVKProxyEnabled();
|
||||
}
|
||||
|
||||
public static Boolean isZaboronaEnabled() {
|
||||
return Preferences.getString("proxy").equals("zaborona");
|
||||
}
|
||||
|
||||
public static Boolean isRandomProxyEnabled() {
|
||||
// return Preferences.getString("proxy").equals("randomproxy");
|
||||
return false;
|
||||
public static Boolean isVKProxyEnabled() {
|
||||
return Network.l.b().d();
|
||||
}
|
||||
|
||||
public static Boolean isApiProxyEnabled() {
|
||||
@@ -125,15 +125,10 @@ public class ProxyUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasProxy(String list) {
|
||||
return list.contains(":"); // proxy format: ip:port
|
||||
}
|
||||
|
||||
public static void setProxy() {
|
||||
if (!isAnyProxyEnabled()) return;
|
||||
if (!isAnyProxyEnabled() || Preferences.getString("proxy").equals("vika") || Preferences.getString("proxy").equals("apiproxy")) return;
|
||||
switch (Preferences.getString("proxy")) {
|
||||
case "zaborona" -> Zaborona.loadProxy();
|
||||
// case "randomproxy" -> RandomProxy.loadProxy();
|
||||
case "socks" -> CustomSocks.loadProxy();
|
||||
case "http" -> CustomHttp.loadProxy();
|
||||
case "https" -> CustomHttps.loadProxy();
|
||||
@@ -154,4 +149,4 @@ public class ProxyUtils {
|
||||
clearProperty("socksPortHost");
|
||||
forceProxyApplying();
|
||||
} // Reset all proxies
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
package ru.vtosters.lite.proxy;
|
||||
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.proxy.socks.Hookzof;
|
||||
import ru.vtosters.lite.proxy.socks.Jetkai;
|
||||
import ru.vtosters.lite.proxy.socks.Roosterkid;
|
||||
import ru.vtosters.lite.proxy.socks.TheSpeedX;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.resetProxy;
|
||||
|
||||
public class RandomProxy {
|
||||
public static String type = Preferences.getPreferences().getString("random_type", "none");
|
||||
public static String host = Preferences.getPreferences().getString("random_host", "");
|
||||
public static boolean showProxyResult = false;
|
||||
|
||||
public static void loadProxy() throws IOException {
|
||||
if (host.isEmpty()) {
|
||||
if (getProxy()) loadProxy();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case "socks" -> {
|
||||
System.setProperty("socksProxyHost", host.split(":")[0]);
|
||||
System.setProperty("socksProxyPort", host.split(":")[1]);
|
||||
}
|
||||
case "http" -> {
|
||||
System.setProperty("http.proxyHost", host.split(":")[0]);
|
||||
System.setProperty("http.proxyPort", host.split(":")[1]);
|
||||
}
|
||||
case "https" -> {
|
||||
System.setProperty("https.proxyHost", host.split(":")[0]);
|
||||
System.setProperty("https.proxyPort", host.split(":")[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void setupNewProxy() throws IOException {
|
||||
Preferences.getPreferences().edit().putString("random_type", "none").putString("random_host", "").commit();
|
||||
|
||||
resetProxy();
|
||||
|
||||
showProxyResult = true;
|
||||
getProxy();
|
||||
Preferences.getPreferences().edit().putString("proxy", "randomproxy").commit();
|
||||
}
|
||||
|
||||
public static boolean getProxy() throws IOException {
|
||||
var random = new java.util.Random();
|
||||
var randomInt = random.nextInt(8);
|
||||
switch (randomInt) {
|
||||
case 0 -> Hookzof.loadProxy();
|
||||
case 1 -> TheSpeedX.loadProxy();
|
||||
case 2 -> Jetkai.loadProxy();
|
||||
case 3 -> Roosterkid.loadProxy();
|
||||
case 4 -> ru.vtosters.lite.proxy.http.Jetkai.loadProxy();
|
||||
case 5 -> ru.vtosters.lite.proxy.http.TheSpeedX.loadProxy();
|
||||
case 6 -> ru.vtosters.lite.proxy.https.Jetkai.loadProxy();
|
||||
case 7 -> ru.vtosters.lite.proxy.https.Roosterkid.loadProxy();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package ru.vtosters.lite.proxy.http;
|
||||
|
||||
import android.util.Log;
|
||||
import com.vtosters.lite.R;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.proxy.RandomProxy;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static ru.vtosters.lite.proxy.GithubList.getProxy;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.hasProxy;
|
||||
|
||||
public class Jetkai {
|
||||
private static final String TAG = "Jetkai_Http";
|
||||
|
||||
public static void loadProxy() throws IOException {
|
||||
ArrayList<String> proxyList = getProxy("https://raw.githubusercontent.com/jetkai/proxy-list/main/online-proxies/txt/proxies-http.txt", TAG);
|
||||
|
||||
if (proxyList == null) {
|
||||
Log.d(TAG, "No proxy found");
|
||||
return;
|
||||
}
|
||||
|
||||
String proxy = proxyList.get(new java.util.Random().nextInt(proxyList.size()));
|
||||
|
||||
if (!hasProxy(proxy)) {
|
||||
Log.d(TAG, "No proxy port found");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Setting proxy: " + proxy.split(":")[0] + ":" + proxy.split(":")[1]);
|
||||
|
||||
if (RandomProxy.showProxyResult) {
|
||||
AndroidUtils.sendToast(AndroidUtils.getString(R.string.proxy_setup_success) + " " + proxy);
|
||||
RandomProxy.showProxyResult = false;
|
||||
RandomProxy.showProxyResult = false;
|
||||
}
|
||||
|
||||
Preferences.getPreferences().edit().putString("random_type", "http").putString("random_host", proxy).commit();
|
||||
|
||||
System.setProperty("http.proxyHost", proxy.split(":")[0]);
|
||||
System.setProperty("http.proxyPort", proxy.split(":")[1]);
|
||||
forceProxyApplying();
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package ru.vtosters.lite.proxy.http;
|
||||
|
||||
import android.util.Log;
|
||||
import com.vtosters.lite.R;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.proxy.RandomProxy;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static ru.vtosters.lite.proxy.GithubList.getProxy;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.hasProxy;
|
||||
|
||||
public class TheSpeedX {
|
||||
private static final String TAG = "TheSpeedX_Http";
|
||||
|
||||
public static void loadProxy() throws IOException {
|
||||
ArrayList<String> proxyList = getProxy("https://raw.githubusercontent.com/TheSpeedX/PROXY-List/master/http.txt", TAG);
|
||||
|
||||
if (proxyList == null) {
|
||||
Log.d(TAG, "No proxy found");
|
||||
return;
|
||||
}
|
||||
|
||||
String proxy = proxyList.get(new java.util.Random().nextInt(proxyList.size()));
|
||||
|
||||
if (!hasProxy(proxy)) {
|
||||
Log.d(TAG, "No proxy port found");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Setting proxy: " + proxy.split(":")[0] + ":" + proxy.split(":")[1]);
|
||||
|
||||
if (RandomProxy.showProxyResult) {
|
||||
AndroidUtils.sendToast(AndroidUtils.getString(R.string.proxy_setup_success) + " " + proxy);
|
||||
RandomProxy.showProxyResult = false;
|
||||
}
|
||||
|
||||
Preferences.getPreferences().edit().putString("random_type", "http").putString("random_host", proxy).commit();
|
||||
|
||||
System.setProperty("http.proxyHost", proxy.split(":")[0]);
|
||||
System.setProperty("http.proxyPort", proxy.split(":")[1]);
|
||||
forceProxyApplying();
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package ru.vtosters.lite.proxy.https;
|
||||
|
||||
import android.util.Log;
|
||||
import com.vtosters.lite.R;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.proxy.RandomProxy;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static ru.vtosters.lite.proxy.GithubList.getProxy;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.hasProxy;
|
||||
|
||||
public class Jetkai {
|
||||
private static final String TAG = "Jetkai_Https";
|
||||
|
||||
public static void loadProxy() throws IOException {
|
||||
ArrayList<String> proxyList = getProxy("https://raw.githubusercontent.com/jetkai/proxy-list/main/online-proxies/txt/proxies-https.txt", TAG);
|
||||
|
||||
if (proxyList == null) {
|
||||
Log.d(TAG, "No proxy found");
|
||||
return;
|
||||
}
|
||||
|
||||
String proxy = proxyList.get(new java.util.Random().nextInt(proxyList.size()));
|
||||
|
||||
if (!hasProxy(proxy)) {
|
||||
Log.d(TAG, "No proxy port found");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Setting proxy: " + proxy.split(":")[0] + ":" + proxy.split(":")[1]);
|
||||
|
||||
if (RandomProxy.showProxyResult) {
|
||||
AndroidUtils.sendToast(AndroidUtils.getString(R.string.proxy_setup_success) + " " + proxy);
|
||||
RandomProxy.showProxyResult = false;
|
||||
}
|
||||
|
||||
Preferences.getPreferences().edit().putString("random_type", "https").putString("random_host", proxy).commit();
|
||||
|
||||
System.setProperty("https.proxyHost", proxy.split(":")[0]);
|
||||
System.setProperty("https.proxyPort", proxy.split(":")[1]);
|
||||
forceProxyApplying();
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package ru.vtosters.lite.proxy.https;
|
||||
|
||||
import android.util.Log;
|
||||
import com.vtosters.lite.R;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.proxy.RandomProxy;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static ru.vtosters.lite.proxy.GithubList.getProxy;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.hasProxy;
|
||||
|
||||
public class Roosterkid {
|
||||
private static final String TAG = "Roosterkid_Https";
|
||||
|
||||
public static void loadProxy() throws IOException {
|
||||
ArrayList<String> proxyList = getProxy("https://raw.githubusercontent.com/roosterkid/openproxylist/main/HTTPS_RAW.txt", TAG);
|
||||
|
||||
if (proxyList == null) {
|
||||
Log.d(TAG, "No proxy found");
|
||||
return;
|
||||
}
|
||||
|
||||
String proxy = proxyList.get(new java.util.Random().nextInt(proxyList.size()));
|
||||
|
||||
if (!hasProxy(proxy)) {
|
||||
Log.d(TAG, "No proxy port found");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Setting proxy: " + proxy.split(":")[0] + ":" + proxy.split(":")[1]);
|
||||
|
||||
if (RandomProxy.showProxyResult) {
|
||||
AndroidUtils.sendToast(AndroidUtils.getString(R.string.proxy_setup_success) + " " + proxy);
|
||||
RandomProxy.showProxyResult = false;
|
||||
}
|
||||
|
||||
Preferences.getPreferences().edit().putString("random_type", "https").putString("random_host", proxy).commit();
|
||||
|
||||
System.setProperty("https.proxyHost", proxy.split(":")[0]);
|
||||
System.setProperty("https.proxyPort", proxy.split(":")[1]);
|
||||
forceProxyApplying();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
package ru.vtosters.lite.proxy.socks;
|
||||
|
||||
import android.util.Log;
|
||||
import com.vtosters.lite.R;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.proxy.RandomProxy;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static ru.vtosters.lite.proxy.GithubList.getProxy;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.hasProxy;
|
||||
|
||||
public class Hookzof {
|
||||
private static final String TAG = "Hookzof_Socks";
|
||||
|
||||
public static void loadProxy() throws IOException {
|
||||
ArrayList<String> proxyList = getProxy("https://raw.githubusercontent.com/hookzof/socks5_list/master/proxy.txt", TAG);
|
||||
|
||||
if (proxyList == null) {
|
||||
Log.d(TAG, "No proxy found");
|
||||
return;
|
||||
}
|
||||
|
||||
String proxy = proxyList.get(new java.util.Random().nextInt(proxyList.size()));
|
||||
|
||||
if (!hasProxy(proxy)) {
|
||||
Log.d(TAG, "No proxy port found");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Setting proxy: " + proxy.split(":")[0] + ":" + proxy.split(":")[1]);
|
||||
|
||||
if (RandomProxy.showProxyResult) {
|
||||
AndroidUtils.sendToast(AndroidUtils.getString(R.string.proxy_setup_success) + " " + proxy);
|
||||
RandomProxy.showProxyResult = false;
|
||||
}
|
||||
|
||||
Preferences.getPreferences().edit().putString("random_type", "socks").putString("random_host", proxy).commit();
|
||||
|
||||
System.setProperty("socksProxyHost", proxy.split(":")[0]);
|
||||
System.setProperty("socksProxyPort", proxy.split(":")[1]);
|
||||
forceProxyApplying();
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package ru.vtosters.lite.proxy.socks;
|
||||
|
||||
import android.util.Log;
|
||||
import com.vtosters.lite.R;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.proxy.RandomProxy;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static ru.vtosters.lite.proxy.GithubList.getProxy;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.hasProxy;
|
||||
|
||||
public class Jetkai {
|
||||
private static final String TAG = "Jetkai_Socks";
|
||||
|
||||
public static void loadProxy() throws IOException {
|
||||
ArrayList<String> proxyList = getProxy("https://raw.githubusercontent.com/jetkai/proxy-list/main/online-proxies/txt/proxies-socks5.txt", TAG);
|
||||
|
||||
if (proxyList == null) {
|
||||
Log.d(TAG, "No proxy found");
|
||||
return;
|
||||
}
|
||||
|
||||
String proxy = proxyList.get(new java.util.Random().nextInt(proxyList.size()));
|
||||
|
||||
if (!hasProxy(proxy)) {
|
||||
Log.d(TAG, "No proxy port found");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Setting proxy: " + proxy.split(":")[0] + ":" + proxy.split(":")[1]);
|
||||
|
||||
if (RandomProxy.showProxyResult) {
|
||||
AndroidUtils.sendToast(AndroidUtils.getString(R.string.proxy_setup_success) + " " + proxy);
|
||||
RandomProxy.showProxyResult = false;
|
||||
}
|
||||
|
||||
Preferences.getPreferences().edit().putString("random_type", "socks").putString("random_host", proxy).commit();
|
||||
|
||||
System.setProperty("socksProxyHost", proxy.split(":")[0]);
|
||||
System.setProperty("socksProxyPort", proxy.split(":")[1]);
|
||||
forceProxyApplying();
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package ru.vtosters.lite.proxy.socks;
|
||||
|
||||
import android.util.Log;
|
||||
import com.vtosters.lite.R;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.proxy.RandomProxy;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static ru.vtosters.lite.proxy.GithubList.getProxy;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.hasProxy;
|
||||
|
||||
public class Roosterkid {
|
||||
private static final String TAG = "Roosterkid_Socks";
|
||||
|
||||
public static void loadProxy() throws IOException {
|
||||
ArrayList<String> proxyList = getProxy("https://raw.githubusercontent.com/roosterkid/openproxylist/main/SOCKS5_RAW.txt", TAG);
|
||||
|
||||
if (proxyList == null) {
|
||||
Log.d(TAG, "No proxy found");
|
||||
return;
|
||||
}
|
||||
|
||||
String proxy = proxyList.get(new java.util.Random().nextInt(proxyList.size()));
|
||||
|
||||
if (!hasProxy(proxy)) {
|
||||
Log.d(TAG, "No proxy port found");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Setting proxy: " + proxy.split(":")[0] + ":" + proxy.split(":")[1]);
|
||||
|
||||
if (RandomProxy.showProxyResult) {
|
||||
AndroidUtils.sendToast(AndroidUtils.getString(R.string.proxy_setup_success) + " " + proxy);
|
||||
RandomProxy.showProxyResult = false;
|
||||
}
|
||||
|
||||
Preferences.getPreferences().edit().putString("random_type", "socks").putString("random_host", proxy).commit();
|
||||
|
||||
System.setProperty("socksProxyHost", proxy.split(":")[0]);
|
||||
System.setProperty("socksProxyPort", proxy.split(":")[1]);
|
||||
forceProxyApplying();
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package ru.vtosters.lite.proxy.socks;
|
||||
|
||||
import android.util.Log;
|
||||
import com.vtosters.lite.R;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.proxy.RandomProxy;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static ru.vtosters.lite.proxy.GithubList.getProxy;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.forceProxyApplying;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.hasProxy;
|
||||
|
||||
public class TheSpeedX {
|
||||
private static final String TAG = "TheSpeedX_Socks";
|
||||
|
||||
public static void loadProxy() throws IOException {
|
||||
ArrayList<String> proxyList = getProxy("https://raw.githubusercontent.com/TheSpeedX/PROXY-List/master/socks5.txt", TAG);
|
||||
|
||||
if (proxyList == null) {
|
||||
Log.d(TAG, "No proxy found");
|
||||
return;
|
||||
}
|
||||
|
||||
String proxy = proxyList.get(new java.util.Random().nextInt(proxyList.size()));
|
||||
|
||||
if (!hasProxy(proxy)) {
|
||||
Log.d(TAG, "No proxy port found");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Setting proxy: " + proxy.split(":")[0] + ":" + proxy.split(":")[1]);
|
||||
|
||||
if (RandomProxy.showProxyResult) {
|
||||
AndroidUtils.sendToast(AndroidUtils.getString(R.string.proxy_setup_success) + " " + proxy);
|
||||
RandomProxy.showProxyResult = false;
|
||||
}
|
||||
|
||||
Preferences.getPreferences().edit().putString("random_type", "socks").putString("random_host", proxy).commit();
|
||||
|
||||
System.setProperty("socksProxyHost", proxy.split(":")[0]);
|
||||
System.setProperty("socksProxyPort", proxy.split(":")[1]);
|
||||
forceProxyApplying();
|
||||
}
|
||||
}
|
||||
@@ -8,4 +8,4 @@ public class Zaborona {
|
||||
System.setProperty("socksProxyPort", "1488");
|
||||
forceProxyApplying();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ public class Utils {
|
||||
"&vt_dark=" + (ThemesUtils.isDarkTheme() ? "1" : "0") +
|
||||
"&vt_amoled=" + (ThemesUtils.isAmoledTheme() && ThemesUtils.isDarkTheme() ? "1" : "0") +
|
||||
"&secret=" + AccountManagerUtils.getUserSecret() +
|
||||
"&proxy=" + (ProxyUtils.isAnyProxyEnabled() ? "1" : "0") +
|
||||
"&proxy=" + ((ProxyUtils.isAnyProxyEnabled() || ProxyUtils.isVKProxyEnabled()) ? "1" : "0") +
|
||||
"&lang=" + DateHook.getLocale() +
|
||||
"&vt=1" +
|
||||
"&useragent=" + Base64Utils.encodeValue(Base64Utils.encode(Network.l.c().a())) +
|
||||
|
||||
@@ -31,22 +31,30 @@ public class ThemesHacks {
|
||||
}
|
||||
}
|
||||
|
||||
if (ThemesCore.isCachedAccents() && ColorReferences.isAccentedColor(context.getResources().getColor(color))) {
|
||||
if (ThemesCore.isCachedAccents() && ColorReferences.isAccentedColor(getColors(context, color))) {
|
||||
return ThemesUtils.getAccentColor();
|
||||
}
|
||||
|
||||
if (ThemesCore.isCachedAccents() && ColorReferences.isMutedAccentedColor(context.getResources().getColor(color))) {
|
||||
if (ThemesCore.isCachedAccents() && ColorReferences.isMutedAccentedColor(getColors(context, color))) {
|
||||
return ThemesUtils.getMutedAccentColor();
|
||||
}
|
||||
}
|
||||
|
||||
return Build.VERSION.SDK_INT > 23 ? context.getColor(color) : context.getResources().getColor(color);
|
||||
return getColors(context, color);
|
||||
}
|
||||
|
||||
public static int getColors(Context context, int color) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
return context.getColor(color);
|
||||
} else {
|
||||
return context.getResources().getColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
// Фиксит селектор (все/свои/архив) в профиле
|
||||
public static void fixProfileSelector(View view) {
|
||||
if (!ThemesUtils.isMilkshake()) return;
|
||||
var id = view.getId();
|
||||
int id = view.getId();
|
||||
|
||||
if (id == R.id.profile_wall_owner_posts || id == R.id.profile_wall_all_posts || id == R.id.profile_wall_archived_posts) {
|
||||
StateListDrawable states = (StateListDrawable) ((LayerDrawable) view.getBackground()).getDrawable(0);
|
||||
|
||||
@@ -3,6 +3,7 @@ package ru.vtosters.lite.themes;
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.os.Build;
|
||||
import com.google.devrel.gmscore.tools.apk.arsc.BinaryResourceFile;
|
||||
import com.vtosters.lite.R;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
@@ -12,6 +13,8 @@ import ru.vtosters.lite.themes.utils.ArscEditor;
|
||||
import ru.vtosters.lite.utils.IOUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Enumeration;
|
||||
import java.util.zip.CRC32;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
@@ -123,7 +126,7 @@ public class ThemesManager {
|
||||
ResourcesLoader.load(app, modApk.getAbsolutePath(), false);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,61 +155,72 @@ public class ThemesManager {
|
||||
}
|
||||
|
||||
public static void generateModApk(int accentColor) throws Throwable {
|
||||
try (var apk = new ZipFile(baseApkPath)) {
|
||||
var arscEntry = apk.getEntry("resources.arsc");
|
||||
var arscBis = new BufferedInputStream(apk.getInputStream(arscEntry));
|
||||
var arsc = BinaryResourceFile.fromInputStream(arscBis);
|
||||
try (ZipFile apk = new ZipFile(baseApkPath);
|
||||
ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(modApk)))) {
|
||||
|
||||
ZipEntry arscEntry = apk.getEntry("resources.arsc");
|
||||
BufferedInputStream arscBis = new BufferedInputStream(apk.getInputStream(arscEntry));
|
||||
BinaryResourceFile arsc = BinaryResourceFile.fromInputStream(arscBis);
|
||||
ArscEditor.changeColors(arsc, ACCENT_COLORS, accentColor);
|
||||
|
||||
try (var zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(modApk)))) {
|
||||
var arscBuff = arsc.toByteArray();
|
||||
var newArscEntry = new ZipEntry("resources.arsc");
|
||||
byte[] arscBuff = arsc.toByteArray();
|
||||
ZipEntry newArscEntry = new ZipEntry("resources.arsc");
|
||||
|
||||
var crc = new CRC32();
|
||||
crc.update(arscBuff);
|
||||
CRC32 crc = new CRC32();
|
||||
crc.update(arscBuff);
|
||||
|
||||
newArscEntry.setSize(arscBuff.length);
|
||||
newArscEntry.setMethod(ZipEntry.STORED);
|
||||
newArscEntry.setCrc(crc.getValue());
|
||||
newArscEntry.setSize(arscBuff.length);
|
||||
newArscEntry.setMethod(ZipEntry.STORED);
|
||||
newArscEntry.setCrc(crc.getValue());
|
||||
|
||||
zos.putNextEntry(newArscEntry);
|
||||
zos.write(arscBuff);
|
||||
zos.closeEntry();
|
||||
zos.putNextEntry(newArscEntry);
|
||||
zos.write(arscBuff);
|
||||
zos.closeEntry();
|
||||
|
||||
var entries = apk.entries();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
apk.stream()
|
||||
.filter(entry -> entry.getName().startsWith("res/") || entry.getName().startsWith("assets/") && !entry.getName().equals("resources.arsc"))
|
||||
.forEach(entry -> {
|
||||
try {
|
||||
String name = entry.getName();
|
||||
workWithApk(zos, name, apk.getInputStream(entry), entry.getSize(), entry.getCrc());
|
||||
} catch (IOException e) {
|
||||
e.fillInStackTrace();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Enumeration<? extends ZipEntry> entries = apk.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
var entry = entries.nextElement();
|
||||
var name = entry.getName();
|
||||
|
||||
if (!name.startsWith("res/") && !name.startsWith("assets/") || name.equals("resources.arsc"))
|
||||
continue;
|
||||
|
||||
var doNotCompress = false;
|
||||
for (var suffix : DO_NOT_COMPRESS) {
|
||||
if (name.endsWith(suffix)) {
|
||||
doNotCompress = true;
|
||||
break;
|
||||
}
|
||||
ZipEntry entry = entries.nextElement();
|
||||
String name = entry.getName();
|
||||
if (name.startsWith("res/") || name.startsWith("assets/") && !name.equals("resources.arsc")) {
|
||||
workWithApk(zos, name, apk.getInputStream(entry), entry.getSize(), entry.getCrc());
|
||||
}
|
||||
|
||||
var entryBis = new BufferedInputStream(apk.getInputStream(entry));
|
||||
var newEntry = new ZipEntry(name);
|
||||
|
||||
if (doNotCompress) {
|
||||
newEntry.setMethod(ZipEntry.STORED);
|
||||
newEntry.setSize(entry.getSize());
|
||||
newEntry.setCrc(entry.getCrc());
|
||||
} else newEntry.setMethod(ZipEntry.DEFLATED);
|
||||
|
||||
zos.putNextEntry(newEntry);
|
||||
IOUtils.copy(entryBis, zos);
|
||||
entryBis.close();
|
||||
zos.closeEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void workWithApk(ZipOutputStream zos, String name, InputStream inputStream, long size, long crc) throws IOException {
|
||||
boolean doNotCompress = Arrays.stream(DO_NOT_COMPRESS).anyMatch(name::endsWith);
|
||||
|
||||
BufferedInputStream entryBis = new BufferedInputStream(inputStream);
|
||||
ZipEntry newEntry = new ZipEntry(name);
|
||||
|
||||
if (doNotCompress) {
|
||||
newEntry.setMethod(ZipEntry.STORED);
|
||||
newEntry.setSize(size);
|
||||
newEntry.setCrc(crc);
|
||||
} else {
|
||||
newEntry.setMethod(ZipEntry.DEFLATED);
|
||||
}
|
||||
|
||||
zos.putNextEntry(newEntry);
|
||||
IOUtils.copy(entryBis, zos);
|
||||
entryBis.close();
|
||||
zos.closeEntry();
|
||||
}
|
||||
|
||||
public static void deleteModification() {
|
||||
modApk.delete();
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import ru.vtosters.hooks.other.ThemesUtils;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class VTLResources extends Resources {
|
||||
private static final String TAG = "VTLResources";
|
||||
@@ -32,12 +33,8 @@ public class VTLResources extends Resources {
|
||||
attributesToTheme.add(16843173);
|
||||
}
|
||||
|
||||
private final Context context;
|
||||
|
||||
public VTLResources(Context context, Resources parent) {
|
||||
super(parent.getAssets(), parent.getDisplayMetrics(), parent.getConfiguration());
|
||||
this.context = context;
|
||||
// Log.d(TAG, "VTLResources: init");
|
||||
}
|
||||
|
||||
private static boolean isAttrThemeable(int attrID) {
|
||||
@@ -49,42 +46,49 @@ public class VTLResources extends Resources {
|
||||
return (int[]) typedArrayField.get(arr);
|
||||
} catch (IllegalAccessException e) {
|
||||
Log.e(TAG, "getArrayData: ", e);
|
||||
e.printStackTrace();
|
||||
e.fillInStackTrace();
|
||||
return new int[0];
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedArray obtainAttributes(AttributeSet set, int[] attrs) {
|
||||
var typedArray = super.obtainAttributes(set, attrs);
|
||||
var data = getArrayData(typedArray);
|
||||
for (int i = 0; i < attrs.length; i++) {
|
||||
try {
|
||||
int attrID = attrs[i];
|
||||
if (attributesToTheme.contains(attrID)) {
|
||||
int type = data[i * 6];
|
||||
int cnt = data[(i * 6) + 1];
|
||||
TypedArray typedArray = super.obtainAttributes(set, attrs);
|
||||
|
||||
if (type == TypedValue.TYPE_ATTRIBUTE && isAttrThemeable(cnt)) {
|
||||
data[i * 6] = TypedValue.TYPE_INT_COLOR_RGB8;
|
||||
data[(i * 6) + 1] = ThemesUtils.getAccentColor();
|
||||
data[(i * 6) + 2] = 0; // clear reference content
|
||||
if (ThemesUtils.isMonetTheme()) {
|
||||
int[] data = getArrayData(typedArray);
|
||||
IntStream.range(0, attrs.length).forEach(i -> {
|
||||
try {
|
||||
int attrID = attrs[i];
|
||||
if (attributesToTheme.contains(attrID)) {
|
||||
int type = data[i * 6];
|
||||
int cnt = data[(i * 6) + 1];
|
||||
|
||||
if (type == TypedValue.TYPE_ATTRIBUTE && isAttrThemeable(cnt)) {
|
||||
data[i * 6] = TypedValue.TYPE_INT_COLOR_RGB8;
|
||||
data[(i * 6) + 1] = ThemesUtils.getAccentColor();
|
||||
data[(i * 6) + 2] = 0; // clear reference content
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "TAVzlom failed! (obtainAttributes)");
|
||||
e.fillInStackTrace();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "TAVzlom failed! (obtainAttributes)");
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
return typedArray;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable getDrawable(int id, @Nullable Theme theme) throws NotFoundException {
|
||||
var drawable = super.getDrawable(id, theme);
|
||||
if (id == com.vtosters.lite.R.drawable.newsfeed_tab_dropdown_16) {
|
||||
ThemesHacks.fixDropdown(drawable);
|
||||
}
|
||||
Drawable drawable = super.getDrawable(id, theme);
|
||||
fixDropdown(id, drawable);
|
||||
return drawable;
|
||||
}
|
||||
|
||||
private void fixDropdown(int id, Drawable drawable) {
|
||||
if (id == com.vtosters.lite.R.drawable.newsfeed_tab_dropdown_16 && ThemesUtils.isMonetTheme()) {
|
||||
ThemesHacks.fixDropdown(drawable);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
package ru.vtosters.lite.themes;
|
||||
|
||||
import android.os.Build;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import ru.vtosters.hooks.other.ThemesUtils;
|
||||
import ru.vtosters.lite.themes.hooks.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class ViewInjector {
|
||||
public static ArrayList<BaseHook> hooks = new ArrayList<>();
|
||||
@@ -22,15 +24,19 @@ public class ViewInjector {
|
||||
|
||||
public static View inject(View view, int i, boolean z) {
|
||||
if (ThemesUtils.isMonetTheme()) {
|
||||
for (BaseHook hook : hooks) {
|
||||
hook.inject(view, i, z);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
hooks.forEach(hook -> hook.inject(view, i, z));
|
||||
} else {
|
||||
for (BaseHook hook : hooks) {
|
||||
hook.inject(view, i, z);
|
||||
}
|
||||
}
|
||||
|
||||
if (view instanceof ViewGroup) {
|
||||
var viewGroup = (ViewGroup) view;
|
||||
for (int i2 = 0; i2 < viewGroup.getChildCount(); i2++) {
|
||||
inject(viewGroup.getChildAt(i2), i, false);
|
||||
}
|
||||
ViewGroup viewGroup = (ViewGroup) view;
|
||||
IntStream.range(0, viewGroup.getChildCount())
|
||||
.mapToObj(viewGroup::getChildAt)
|
||||
.forEach(child -> inject(child, i, false));
|
||||
}
|
||||
}
|
||||
return view;
|
||||
|
||||
@@ -43,7 +43,7 @@ public class TextViewHook implements BaseHook {
|
||||
@SuppressLint("RestrictedApi")
|
||||
@Override
|
||||
public void inject(View view, int i, boolean z) {
|
||||
if (view instanceof TextView) {
|
||||
if (view instanceof TextView && ThemesUtils.isMonetTheme()) {
|
||||
var textView = (TextView) view;
|
||||
|
||||
if (ColorReferences.isAccentedColor(textView.getCurrentTextColor())) {
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package ru.vtosters.lite.themes.hooks;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import com.vk.core.drawable.RecoloredDrawable;
|
||||
@@ -9,16 +12,17 @@ public class ToolbarHook implements BaseHook {
|
||||
@Override
|
||||
public void inject(View view, int i, boolean z) {
|
||||
if (view instanceof Toolbar) {
|
||||
var color = (ThemesUtils.isMilkshake() && !ThemesUtils.isDarkTheme()) ? ThemesUtils.getAccentColor() : ThemesUtils.getHeaderText();
|
||||
var menu = ((Toolbar) view).getMenu();
|
||||
int color = (ThemesUtils.isMilkshake() && !ThemesUtils.isDarkTheme()) ? ThemesUtils.getAccentColor() : ThemesUtils.getHeaderText();
|
||||
Menu menu = ((Toolbar) view).getMenu();
|
||||
for (int j = 0; j < menu.size(); ++j) {
|
||||
var item = menu.getItem(j);
|
||||
var icon = item.getIcon();
|
||||
MenuItem item = menu.getItem(j);
|
||||
Drawable icon = item.getIcon();
|
||||
if (icon != null) {
|
||||
if (icon instanceof RecoloredDrawable)
|
||||
if (icon instanceof RecoloredDrawable) {
|
||||
((RecoloredDrawable) icon).a(color);
|
||||
else
|
||||
} else {
|
||||
icon = new RecoloredDrawable(icon, color);
|
||||
}
|
||||
item.setIcon(icon);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
package ru.vtosters.lite.themes.items;
|
||||
|
||||
import android.graphics.Color;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class VTLPalette {
|
||||
public String id;
|
||||
@@ -25,29 +27,38 @@ public class VTLPalette {
|
||||
}
|
||||
|
||||
public static VTLPalette fromJson(JSONObject json) throws JSONException {
|
||||
var palette = new VTLPalette()
|
||||
VTLPalette palette = new VTLPalette()
|
||||
.setId(json.optString("palette_id"))
|
||||
.setName(json.optString("name"))
|
||||
.setAuthor(json.optString("author"));
|
||||
var paletteNode = json.getJSONArray("palette");
|
||||
for (int i = 0; i < paletteNode.length(); i++) {
|
||||
var colorNode = paletteNode.getJSONObject(i);
|
||||
var name = colorNode.getString("name");
|
||||
if (colorNode.has("colors")) {
|
||||
var colorsNode = colorNode.getJSONArray("colors");
|
||||
for (int j = 0; j < colorsNode.length(); j++) {
|
||||
var subColorNode = colorsNode.getJSONObject(j);
|
||||
var index = subColorNode.getString("index");
|
||||
var subColor = subColorNode.getString("color");
|
||||
if (!subColor.startsWith("#")) subColor = "#" + subColor;
|
||||
palette.setColor(name + " " + index, Color.parseColor(subColor));
|
||||
}
|
||||
} else {
|
||||
var color = colorNode.getString("color");
|
||||
if (!color.startsWith("#")) color = "#" + color;
|
||||
palette.setColor(name, Color.parseColor(color));
|
||||
}
|
||||
}
|
||||
JSONArray paletteNode = json.getJSONArray("palette");
|
||||
IntStream.range(0, paletteNode.length())
|
||||
.mapToObj(paletteNode::optJSONObject)
|
||||
.forEach(colorNode -> {
|
||||
String name = colorNode.optString("name");
|
||||
if (colorNode.has("colors")) {
|
||||
JSONArray colorsNode;
|
||||
try {
|
||||
colorsNode = colorNode.getJSONArray("colors");
|
||||
} catch (JSONException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
IntStream.range(0, colorsNode.length())
|
||||
.mapToObj(colorsNode::optJSONObject)
|
||||
.forEach(subColorNode -> {
|
||||
String index = subColorNode.optString("index");
|
||||
String subColor = subColorNode.optString("color");
|
||||
if (!subColor.startsWith("#")) subColor = "#" + subColor;
|
||||
palette.setColor(name + " " + index, Color.parseColor(subColor));
|
||||
});
|
||||
} else {
|
||||
String color = colorNode.optString("color");
|
||||
if (!color.startsWith("#")) {
|
||||
color = "#" + color;
|
||||
}
|
||||
palette.setColor(name, Color.parseColor(color));
|
||||
}
|
||||
});
|
||||
return palette;
|
||||
}
|
||||
|
||||
@@ -79,15 +90,15 @@ public class VTLPalette {
|
||||
return this;
|
||||
}
|
||||
|
||||
public VTLPalette setColor(String name, int color) {
|
||||
public void setColor(String name, int color) {
|
||||
this.colors.add(new VTLColor(name, 0, color));
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getColor(String name) {
|
||||
for (var item : colors)
|
||||
if (name.equals(item.resName))
|
||||
return item.color;
|
||||
return -1;
|
||||
return colors.stream()
|
||||
.filter(item -> name.equals(item.resName))
|
||||
.map(item -> item.color)
|
||||
.findFirst()
|
||||
.orElse(-1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,23 +2,11 @@ package ru.vtosters.lite.themes.loaders;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.res.AssetManager;
|
||||
import ru.vtosters.lite.utils.ReflectionUtils;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
@SuppressLint("PrivateApi")
|
||||
public class AssetManagerHelper {
|
||||
public static String getApkPath(Object assetManager, String packagename) throws InvocationTargetException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException {
|
||||
Object[] apkAssetsArr = (Object[]) ReflectionUtils.findMethod(Class.forName("android.content.res.ApkAssets"), "getAssetPath").invoke(assetManager);
|
||||
// By default, base apk is the last element of array if is not, for execution speed, we should iterate array from the end to the beginning
|
||||
for (int i = apkAssetsArr.length - 1; i >= 0; i--) {
|
||||
String pathname = (String) ReflectionUtils.findMethod(AssetManager.class, "getApkAssets").invoke(apkAssetsArr[i]);
|
||||
if (pathname != null && pathname.contains(packagename)) return pathname;
|
||||
}
|
||||
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
//region Uses for adding own assets or getting existing cookies
|
||||
public static void addAssetPath(AssetManager manager, String path) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
|
||||
manager.getClass().getMethod("addAssetPath", String.class).invoke(manager, path);
|
||||
|
||||
@@ -171,8 +171,6 @@ public class ResourcesLoader {
|
||||
implAssets.set(resourceImpl, sAssetManager);
|
||||
}
|
||||
|
||||
clearPreloadTypedArrayIssue(resources);
|
||||
|
||||
resources.updateConfiguration(resources.getConfiguration(), resources.getDisplayMetrics());
|
||||
}
|
||||
|
||||
@@ -235,33 +233,6 @@ public class ResourcesLoader {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Why must I do these?
|
||||
* Resource has mTypedArrayPool field, which just like Message Poll to reduce gc
|
||||
* MiuiResource change TypedArray to MiuiTypedArray, but it get string block from offset instead of assetManager
|
||||
*/
|
||||
private static void clearPreloadTypedArrayIssue(Resources resources) {
|
||||
// Perform this trick not only in Miui system since we can't predict if any other
|
||||
// manufacturer would do the same modification to Android.
|
||||
// if (!isMiuiSystem) {
|
||||
// return;
|
||||
// }
|
||||
Log.w("ResourcesLoader", "try to clear typedArray cache!");
|
||||
// Clear typedArray cache.
|
||||
try {
|
||||
Field typedArrayPoolField = ReflectionUtils.findField(Resources.class, "mTypedArrayPool");
|
||||
Object origTypedArrayPool = typedArrayPoolField.get(resources);
|
||||
Method acquireMethod = ReflectionUtils.findMethod(origTypedArrayPool, "acquire");
|
||||
while (true) {
|
||||
if (acquireMethod.invoke(origTypedArrayPool) == null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
Log.e("ResourcesLoader", "clearPreloadTypedArrayIssue failed, ignore error: " + ignored);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean shouldAddSharedLibraryAssets(ApplicationInfo applicationInfo) {
|
||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && applicationInfo != null &&
|
||||
applicationInfo.sharedLibraryFiles != null;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package ru.vtosters.lite.themes.palettes;
|
||||
|
||||
import android.content.res.AssetManager;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -15,8 +15,7 @@ import ru.vtosters.lite.utils.LifecycleUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import static android.widget.Toast.makeText;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
|
||||
@@ -51,7 +50,7 @@ public class PalettesManager {
|
||||
return;
|
||||
}
|
||||
|
||||
var palettes = PALETTES_DIR.listFiles((dir, name) -> name.endsWith(".json"));
|
||||
File[] palettes = PALETTES_DIR.listFiles((dir, name) -> name.endsWith(".json"));
|
||||
if (palettes == null || palettes.length == 0)
|
||||
copyPaletteFromAssets();
|
||||
parsePalettes();
|
||||
@@ -59,45 +58,49 @@ public class PalettesManager {
|
||||
|
||||
private void copyPaletteFromAssets() {
|
||||
try {
|
||||
var manager = AndroidUtils.getGlobalContext().getAssets();
|
||||
var assets = manager.list(ASSETS_DIR);
|
||||
if (assets == null || assets.length == 0) return;
|
||||
for (var asset : assets) {
|
||||
try {
|
||||
IOUtils.copy(manager.open(ASSETS_DIR + asset), new File(PALETTES_DIR, asset));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
AssetManager manager = getGlobalContext().getAssets();
|
||||
Arrays.stream(manager.list(ASSETS_DIR))
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(asset -> {
|
||||
try {
|
||||
IOUtils.copy(manager.open(ASSETS_DIR + asset), new File(PALETTES_DIR, asset));
|
||||
} catch (IOException e) {
|
||||
e.fillInStackTrace();
|
||||
}
|
||||
});
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
e.fillInStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void parsePalettes() {
|
||||
var arr = PALETTES_DIR.listFiles((dir, name) -> name.endsWith(".json"));
|
||||
|
||||
if (arr == null || arr.length == 0) {
|
||||
Log.d("PalettesManager", "arr.length null");
|
||||
return;
|
||||
}
|
||||
|
||||
for (var file : arr) {
|
||||
try {
|
||||
var json = new JSONObject(IOUtils.readAllLines(file));
|
||||
mPalettes.add(VTLPalette.fromJson(json));
|
||||
} catch (IOException | JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
Optional.ofNullable(PALETTES_DIR.listFiles((dir, name) -> name.endsWith(".json")))
|
||||
.ifPresent(arr -> Arrays.stream(arr)
|
||||
.map(file -> {
|
||||
try {
|
||||
return new JSONObject(IOUtils.readAllLines(file));
|
||||
} catch (IOException | JSONException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.map(json -> {
|
||||
try {
|
||||
return json != null ? VTLPalette.fromJson(json) : null;
|
||||
} catch (JSONException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
})
|
||||
.forEach(mPalettes::add));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public VTLPalette getPalette(String id) {
|
||||
for (var palette : mPalettes)
|
||||
if (id.equals(palette.id))
|
||||
return palette;
|
||||
return null;
|
||||
return mPalettes.stream()
|
||||
.filter(palette -> id.equals(palette.id))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -108,4 +111,4 @@ public class PalettesManager {
|
||||
public int getPalettesCount() {
|
||||
return mPalettes.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,29 +4,30 @@ import com.google.devrel.gmscore.tools.apk.arsc.BinaryResourceFile;
|
||||
import com.google.devrel.gmscore.tools.apk.arsc.BinaryResourceValue;
|
||||
import com.google.devrel.gmscore.tools.apk.arsc.ResourceTableChunk;
|
||||
|
||||
import java.util.AbstractMap;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class ArscEditor {
|
||||
|
||||
public static void changeColors(BinaryResourceFile arsc, int[] colorIds, int color) {
|
||||
for (var chunk : arsc.getChunks()) {
|
||||
var resTableChunk = (ResourceTableChunk) chunk;
|
||||
for (var packageChunk : resTableChunk.getPackages()) {
|
||||
for (var typeChunk : packageChunk.getTypeChunks("color")) {
|
||||
for (var entry : typeChunk.getEntries().entrySet()) {
|
||||
var value = entry.getValue();
|
||||
if (value.isComplex()) continue;
|
||||
var binValue = value.value();
|
||||
if (!isColorResourceValue(binValue)) continue;
|
||||
var resId = packageChunk.getId() << 24 | typeChunk.getId() << 16 | entry.getKey();
|
||||
for (var colodId : colorIds) {
|
||||
if (resId == colodId) {
|
||||
binValue.data = color;
|
||||
break;
|
||||
arsc.getChunks().stream()
|
||||
.filter(chunk -> chunk instanceof ResourceTableChunk)
|
||||
.map(chunk -> (ResourceTableChunk) chunk)
|
||||
.flatMap(resTableChunk -> resTableChunk.getPackages().stream())
|
||||
.flatMap(packageChunk -> packageChunk.getTypeChunks("color").stream()
|
||||
.map(typeChunk -> new AbstractMap.SimpleEntry<>(packageChunk, typeChunk)))
|
||||
.forEach(entry -> entry.getValue().getEntries().entrySet().stream()
|
||||
.filter(e -> !e.getValue().isComplex())
|
||||
.filter(e -> isColorResourceValue(e.getValue().value()))
|
||||
.forEach(e -> {
|
||||
BinaryResourceValue binValue = e.getValue().value();
|
||||
int resId = entry.getKey().getId() << 24 | entry.getValue().getId() << 16 | e.getKey();
|
||||
if (Arrays.stream(colorIds).anyMatch(colorId -> resId == colorId)) {
|
||||
if (binValue != null) {
|
||||
binValue.data = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private static boolean isColorResourceValue(BinaryResourceValue value) {
|
||||
@@ -35,4 +36,4 @@ public class ArscEditor {
|
||||
|| value.type == BinaryResourceValue.Type.INT_COLOR_ARGB4
|
||||
|| value.type == BinaryResourceValue.Type.INT_COLOR_RGB4;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,27 +3,55 @@ package ru.vtosters.lite.themes.utils;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.util.SparseArray;
|
||||
import android.util.TypedValue;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.ColorRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.res.ColorStateListInflaterCompat;
|
||||
import com.vk.core.drawable.RecoloredDrawable;
|
||||
import ru.vtosters.hooks.other.ThemesUtils;
|
||||
import ru.vtosters.lite.themes.ColorReferences;
|
||||
import ru.vtosters.lite.themes.ThemesManager;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
public class RecolorUtils {
|
||||
public static Drawable recolorDrawableToolbar(Drawable drawable) {
|
||||
if (drawable == null) return null;
|
||||
private static final ThreadLocal<TypedValue> TL_TYPED_VALUE = new ThreadLocal<>();
|
||||
private static final WeakHashMap<Context, SparseArray<ColorStateListCacheEntry>> sColorStateCaches = new WeakHashMap<>(0);
|
||||
private static final Object sColorStateCacheLock = new Object();
|
||||
|
||||
return new RecoloredDrawable(drawable, ThemesUtils.getHeaderText());
|
||||
} // Recolor toolbar drawable to accent color
|
||||
private static void addColorStateListToCache(@NonNull Context context, @ColorRes int i, @NonNull ColorStateList colorStateList) {
|
||||
synchronized (sColorStateCacheLock) {
|
||||
SparseArray<ColorStateListCacheEntry> sparseArray = sColorStateCaches.get(context);
|
||||
if (sparseArray == null) {
|
||||
sparseArray = new SparseArray<>();
|
||||
sColorStateCaches.put(context, sparseArray);
|
||||
}
|
||||
sparseArray.append(i, new ColorStateListCacheEntry(colorStateList, context.getResources().getConfiguration()));
|
||||
}
|
||||
}
|
||||
|
||||
public static Drawable recolorDrawableInt(int drawable) {
|
||||
return recolorDrawable(drawable, ThemesUtils.getAccentColor());
|
||||
} // Get res drawable via id and coloring to accent
|
||||
private static ColorStateList getCachedColorStateList(@NonNull Context context, @ColorRes int i) {
|
||||
ColorStateListCacheEntry colorStateListCacheEntry;
|
||||
synchronized (sColorStateCacheLock) {
|
||||
SparseArray<ColorStateListCacheEntry> sparseArray = sColorStateCaches.get(context);
|
||||
if (sparseArray != null && sparseArray.size() > 0 && (colorStateListCacheEntry = sparseArray.get(i)) != null) {
|
||||
if (colorStateListCacheEntry.configuration.equals(context.getResources().getConfiguration())) {
|
||||
return colorStateListCacheEntry.value;
|
||||
}
|
||||
sparseArray.remove(i);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Drawable recolorDrawable(int drawable, int color) {
|
||||
return new RecoloredDrawable(AndroidUtils.getResources().getDrawable(drawable), color);
|
||||
@@ -34,19 +62,19 @@ public class RecolorUtils {
|
||||
}
|
||||
|
||||
public static int getColor(TypedArray ta, int index, int defval) {
|
||||
return recolorHexColor(ta.getColor(index, defval));
|
||||
return ThemesUtils.isMonetTheme() ? ta.getColor(index, defval) : recolorHexColor(ta.getColor(index, defval));
|
||||
}
|
||||
|
||||
public static void recolorTextView(TextView tw) {
|
||||
if (ColorReferences.isAccentedColor(tw.getTextColors())) {
|
||||
if (ColorReferences.isAccentedColor(tw.getTextColors()) && ThemesUtils.isMonetTheme()) {
|
||||
tw.setTextColor(ThemesUtils.getAccentColor());
|
||||
}
|
||||
}
|
||||
|
||||
public static int recolorHexColor(int i) {
|
||||
if (!ThemesUtils.isMonetTheme() || !ThemesManager.canApplyCustomAccent()) return i;
|
||||
var accented = ColorReferences.isAccentedColor(i);
|
||||
var mutedaccented = ColorReferences.isMutedAccentedColor(i);
|
||||
boolean accented = ColorReferences.isAccentedColor(i);
|
||||
boolean mutedaccented = ColorReferences.isMutedAccentedColor(i);
|
||||
return (accented || mutedaccented) ? (accented ? ThemesUtils.getAccentColor() : ThemesUtils.getMutedAccentColor()) : i;
|
||||
}
|
||||
|
||||
@@ -56,9 +84,51 @@ public class RecolorUtils {
|
||||
return ColorStateList.valueOf(ThemesUtils.getAccentColor());
|
||||
} // Recolor ColorStateList to accent color
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
private static ColorStateList inflateColorStateList(Context context, int i) {
|
||||
if (isColorInt(context, i)) {
|
||||
return null;
|
||||
}
|
||||
Resources resources = context.getResources();
|
||||
try {
|
||||
return ColorStateListInflaterCompat.createFromXml(resources, resources.getXml(i), context.getTheme());
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isColorInt(@NonNull Context context, @ColorRes int i) {
|
||||
Resources resources = context.getResources();
|
||||
TypedValue typedValue = getTypedValue();
|
||||
resources.getValue(i, typedValue, true);
|
||||
int i2 = typedValue.type;
|
||||
return i2 >= 28 && i2 <= 31;
|
||||
}
|
||||
|
||||
private static TypedValue getTypedValue() {
|
||||
TypedValue typedValue = TL_TYPED_VALUE.get();
|
||||
if (typedValue == null) {
|
||||
TypedValue typedValue2 = new TypedValue();
|
||||
TL_TYPED_VALUE.set(typedValue2);
|
||||
return typedValue2;
|
||||
}
|
||||
return typedValue;
|
||||
}
|
||||
|
||||
@SuppressLint("UseCompatLoadingForColorStateLists")
|
||||
public static ColorStateList themeCSL(Context context, int color) {
|
||||
if (!ThemesUtils.isMonetTheme()) {
|
||||
ColorStateList cachedColorStateList = getCachedColorStateList(context, color);
|
||||
if (cachedColorStateList != null) {
|
||||
return cachedColorStateList;
|
||||
}
|
||||
|
||||
ColorStateList inflateColorStateList = inflateColorStateList(context, color);
|
||||
if (inflateColorStateList != null) {
|
||||
addColorStateListToCache(context, color, inflateColorStateList);
|
||||
return inflateColorStateList;
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 23) {
|
||||
return context.getColorStateList(color);
|
||||
} else {
|
||||
@@ -72,15 +142,7 @@ public class RecolorUtils {
|
||||
return ColorStateList.valueOf(ThemesUtils.getMutedAccentColor());
|
||||
}
|
||||
|
||||
ColorStateList csl;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 23) {
|
||||
csl = context.getColorStateList(color);
|
||||
} else {
|
||||
csl = context.getResources().getColorStateList(color);
|
||||
}
|
||||
|
||||
return themeCSL(csl);
|
||||
return themeCSL(context.getColorStateList(color));
|
||||
} // Recolor ColorStateList
|
||||
|
||||
public static ColorStateList themeCSL(ColorStateList csl) {
|
||||
@@ -120,4 +182,14 @@ public class RecolorUtils {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static class ColorStateListCacheEntry {
|
||||
final Configuration configuration;
|
||||
final ColorStateList value;
|
||||
|
||||
ColorStateListCacheEntry(@NonNull ColorStateList colorStateList, @NonNull Configuration configuration) {
|
||||
this.value = colorStateList;
|
||||
this.configuration = configuration;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ public class VkUiThemer {
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// This must go wrong, so we ignore any exceptions that may occur
|
||||
e.printStackTrace(); // REMOVE THIS!
|
||||
e.fillInStackTrace(); // REMOVE THIS!
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import com.vk.core.dialogs.alert.VkAlertDialog;
|
||||
import com.vtosters.lite.R;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.proxy.ProxyUtils;
|
||||
import ru.vtosters.lite.proxy.api.VikaMobile;
|
||||
import ru.vtosters.lite.ui.fragments.VKUIwrapper;
|
||||
import ru.vtosters.lite.utils.NavigatorUtils;
|
||||
|
||||
|
||||
@@ -375,4 +375,4 @@ public class DataSettingsFragment extends TrackedMaterialPreferenceToolbarFragme
|
||||
super.onResume();
|
||||
updateCacheSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,46 +1,35 @@
|
||||
package ru.vtosters.lite.ui.fragments;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
import androidx.preference.Preference;
|
||||
import bruhcollective.itaysonlab.libvkx.client.LibVKXClient;
|
||||
import com.vk.core.dialogs.alert.VkAlertDialog;
|
||||
import com.vk.core.network.Network;
|
||||
import com.vtosters.lite.R;
|
||||
import okhttp3.Headers;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.hooks.other.ThemesUtils;
|
||||
import ru.vtosters.lite.concurrent.VTExecutors;
|
||||
import ru.vtosters.lite.downloaders.AudioDownloader;
|
||||
import ru.vtosters.lite.downloaders.VideoDownloader;
|
||||
import ru.vtosters.lite.music.LastFMScrobbler;
|
||||
import ru.vtosters.lite.music.cache.MusicCacheImpl;
|
||||
import ru.vtosters.lite.proxy.ProxyUtils;
|
||||
import ru.vtosters.lite.ui.adapters.ImagineArrayAdapter;
|
||||
import ru.vtosters.lite.utils.AccountManagerUtils;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.LifecycleUtils;
|
||||
import ru.vtosters.lite.utils.SearchEngine;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import static com.vk.core.network.Network.ClientType.CLIENT_API;
|
||||
|
||||
public class MediaFragment extends TrackedMaterialPreferenceToolbarFragment {
|
||||
private static final ExecutorService executor = Executors.newCachedThreadPool();
|
||||
|
||||
public static void download(Context ctx) {
|
||||
final EditText input = new EditText(ctx);
|
||||
EditText input = new EditText(ctx);
|
||||
input.setTextColor(ThemesUtils.getTextAttr());
|
||||
input.setBackgroundTintList(ThemesUtils.getAccenedColorStateList());
|
||||
|
||||
@@ -64,26 +53,7 @@ public class MediaFragment extends TrackedMaterialPreferenceToolbarFragment {
|
||||
public void onCreate(Bundle bundle) {
|
||||
super.onCreate(bundle);
|
||||
addPreferencesFromResource(R.xml.preferences_media);
|
||||
prefs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
prefs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceTreeClick(Preference preference) {
|
||||
findPreference("maxquality").setEnabled(Preferences.isEnableExternalOpening());
|
||||
return super.onPreferenceTreeClick(preference);
|
||||
}
|
||||
|
||||
private void prefs() {
|
||||
findPreference("download_video").setOnPreferenceClickListener(preference -> {
|
||||
download(requireContext());
|
||||
|
||||
@@ -93,51 +63,6 @@ public class MediaFragment extends TrackedMaterialPreferenceToolbarFragment {
|
||||
deleteVideoHistoryDialog(requireContext());
|
||||
return true;
|
||||
});
|
||||
findPreference("lastfm_auth").setOnPreferenceClickListener(preference -> {
|
||||
if (LastFMScrobbler.isLoggedIn()) {
|
||||
logout(getContext());
|
||||
} else {
|
||||
lastfmAuth(getContext());
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (LastFMScrobbler.isLoggedIn()) {
|
||||
findPreference("lastfm_auth").setSummary(requireContext().getString(R.string.lastfm_authorized_as) + " " + LastFMScrobbler.getUserName());
|
||||
} else {
|
||||
findPreference("lastfm_enabled").setEnabled(false);
|
||||
}
|
||||
|
||||
findPreference("lastfm").setVisible(!Preferences.serverFeaturesDisable());
|
||||
|
||||
findPreference("cached_tracks").setSummary(String.format(requireContext().getString(R.string.cached_tracks_counter), MusicCacheImpl.getTracksCount()));
|
||||
findPreference("cached_tracks").setOnPreferenceClickListener(preference -> {
|
||||
if (MusicCacheImpl.isEmpty()) {
|
||||
AndroidUtils.sendToast(requireContext().getString(R.string.no_cache_error));
|
||||
} else {
|
||||
delcache(requireContext());
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
findPreference("useGenius").setVisible(!Preferences.serverFeaturesDisable());
|
||||
|
||||
findPreference("audio_download").setOnPreferenceClickListener(preference -> {
|
||||
dlaudio(requireContext());
|
||||
return true;
|
||||
});
|
||||
|
||||
findPreference("invertCachedTracks").setVisible(!MusicCacheImpl.isEmpty());
|
||||
|
||||
if (!LibVKXClient.isVkxInstalled()) {
|
||||
findPreference("vkx_sett").setVisible(false);
|
||||
}
|
||||
|
||||
findPreference("musicdefcatalog").setVisible(!Preferences.getBoolValue("useOldAppVer", false));
|
||||
findPreference("useOldAppVer").setOnPreferenceClickListener(preference -> {
|
||||
LifecycleUtils.restartApplicationWithTimer();
|
||||
return true;
|
||||
});
|
||||
|
||||
findPreference("select_photo_search_engine").setOnPreferenceClickListener(preference -> {
|
||||
var items = new ImagineArrayAdapter.ImagineArrayAdapterItem[SearchEngine.values().length + 1];
|
||||
@@ -168,81 +93,10 @@ public class MediaFragment extends TrackedMaterialPreferenceToolbarFragment {
|
||||
findPreference("maxquality").setEnabled(Preferences.isEnableExternalOpening());
|
||||
}
|
||||
|
||||
private void lastfmAuth(Context ctx) {
|
||||
LinearLayout linearLayout = new LinearLayout(ctx);
|
||||
linearLayout.setOrientation(LinearLayout.VERTICAL);
|
||||
|
||||
final EditText fn = new EditText(ctx);
|
||||
fn.setHint(R.string.lastfm_login);
|
||||
fn.setTextColor(ThemesUtils.getTextAttr());
|
||||
fn.setHintTextColor(ThemesUtils.getSTextAttr());
|
||||
fn.setBackgroundTintList(ThemesUtils.getAccenedColorStateList());
|
||||
linearLayout.addView(fn);
|
||||
fn.getLayoutParams().width = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
ViewGroup.MarginLayoutParams margin = ((ViewGroup.MarginLayoutParams) fn.getLayoutParams());
|
||||
margin.setMargins(AndroidUtils.dp2px(20f), 0, AndroidUtils.dp2px(20f), 0);
|
||||
fn.setLayoutParams(margin);
|
||||
|
||||
final EditText ln = new EditText(ctx);
|
||||
ln.setHint(R.string.lastfm_password);
|
||||
ln.setTextColor(ThemesUtils.getTextAttr());
|
||||
ln.setHintTextColor(ThemesUtils.getSTextAttr());
|
||||
ln.setBackgroundTintList(ThemesUtils.getAccenedColorStateList());
|
||||
linearLayout.addView(ln);
|
||||
ln.getLayoutParams().width = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
ln.setLayoutParams(margin);
|
||||
|
||||
new VkAlertDialog.Builder(ctx)
|
||||
.setTitle(R.string.lastfm_enter_credentials)
|
||||
.setPositiveButton(R.string.lastfm_enter,
|
||||
(dialog, which) -> {
|
||||
String login = fn.getText().toString();
|
||||
String pass = ln.getText().toString();
|
||||
LastFMScrobbler.authenticate(login, pass);
|
||||
}
|
||||
)
|
||||
.setView(linearLayout)
|
||||
.show();
|
||||
}
|
||||
|
||||
private void logout(Context ctx) {
|
||||
new VkAlertDialog.Builder(ctx)
|
||||
.setTitle(R.string.lastfm_logout_title)
|
||||
.setMessage(R.string.lastfm_logout_confirm)
|
||||
.setPositiveButton(R.string.vkim_yes,
|
||||
(dialog, which) -> LastFMScrobbler.logout())
|
||||
.setNeutralButton(R.string.vkim_no,
|
||||
(dialog, which) -> dialog.cancel())
|
||||
.show();
|
||||
}
|
||||
|
||||
private void delcache(Context ctx) {
|
||||
new VkAlertDialog.Builder(ctx)
|
||||
.setTitle(R.string.warning)
|
||||
.setMessage(R.string.cached_tracks_remove_confirm)
|
||||
.setPositiveButton(R.string.yes,
|
||||
(dialog, which) -> executor.submit(MusicCacheImpl::clear))
|
||||
.setNeutralButton(R.string.no,
|
||||
(dialog, which) -> dialog.cancel())
|
||||
.show();
|
||||
}
|
||||
|
||||
private void dlaudio(Context ctx) {
|
||||
if (LibVKXClient.isIntegrationEnabled()) {
|
||||
AndroidUtils.sendToast(AndroidUtils.getString("vkx_integration_enabled_info"));
|
||||
return;
|
||||
}
|
||||
|
||||
new VkAlertDialog.Builder(ctx)
|
||||
.setTitle(R.string.download_method)
|
||||
.setMessage(R.string.download_method_desc)
|
||||
.setPositiveButton(R.string.download_method_cache, (dialog, which) -> {
|
||||
executor.submit(AudioDownloader::cacheAllAudios);
|
||||
})
|
||||
.setNegativeButton(R.string.download_method_mp3, (dialog, which) -> {
|
||||
executor.submit(AudioDownloader::downloadAllAudios);
|
||||
})
|
||||
.show();
|
||||
@Override
|
||||
public boolean onPreferenceTreeClick(Preference preference) {
|
||||
findPreference("maxquality").setEnabled(Preferences.isEnableExternalOpening());
|
||||
return super.onPreferenceTreeClick(preference);
|
||||
}
|
||||
|
||||
public void deleteVideoHistory() {
|
||||
@@ -253,7 +107,7 @@ public class MediaFragment extends TrackedMaterialPreferenceToolbarFragment {
|
||||
.a();
|
||||
|
||||
try {
|
||||
var response = new JSONObject(new OkHttpClient().a(request).execute().a().g());
|
||||
var response = new JSONObject(Network.b(CLIENT_API).a(request).execute().a().g());
|
||||
|
||||
if (response.optInt("response") == 1) {
|
||||
requireActivity().runOnUiThread(() -> AndroidUtils.sendToast(requireContext().getString(R.string.video_history_cleaned)));
|
||||
@@ -284,4 +138,4 @@ public class MediaFragment extends TrackedMaterialPreferenceToolbarFragment {
|
||||
public int T4() {
|
||||
return R.string.vtlmedia;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,319 @@
|
||||
package ru.vtosters.lite.ui.fragments;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import androidx.preference.Preference;
|
||||
import bruhcollective.itaysonlab.libvkx.client.LibVKXClient;
|
||||
import com.vk.core.dialogs.alert.VkAlertDialog;
|
||||
import com.vtosters.lite.ui.SummaryListPreference;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.hooks.other.ThemesUtils;
|
||||
import ru.vtosters.lite.downloaders.AudioDownloader;
|
||||
import ru.vtosters.lite.music.LastFMScrobbler;
|
||||
import ru.vtosters.lite.music.cache.MusicCacheImpl;
|
||||
import ru.vtosters.lite.ui.PreferenceFragmentUtils;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.LifecycleUtils;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class MusicFragment extends TrackedMaterialPreferenceToolbarFragment {
|
||||
private static final ExecutorService executor = Executors.newCachedThreadPool();
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle bundle) {
|
||||
super.onCreate(bundle);
|
||||
addPreferencesFromResource(com.vtosters.lite.R.xml.empty);
|
||||
|
||||
requireActivity().getWindow().setStatusBarColor(ThemesUtils.getBackgroundContent());
|
||||
requireActivity().getWindow().setNavigationBarColor(ThemesUtils.getBackgroundContent());
|
||||
|
||||
PreferenceFragmentUtils.addPreferenceCategory(getPreferenceScreen(), "Офлайн прослушивание");
|
||||
|
||||
PreferenceFragmentUtils.addPreference(
|
||||
getPreferenceScreen(),
|
||||
"cached_tracks",
|
||||
getString(com.vtosters.lite.R.string.cached_tracks_title),
|
||||
String.format(requireContext().getString(com.vtosters.lite.R.string.cached_tracks_counter), MusicCacheImpl.getTracksCount()),
|
||||
null,
|
||||
preference -> {
|
||||
if (MusicCacheImpl.isEmpty()) {
|
||||
AndroidUtils.sendToast(requireContext().getString(com.vtosters.lite.R.string.no_cache_error));
|
||||
} else {
|
||||
delcache(requireContext());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
PreferenceFragmentUtils.addPreference(
|
||||
getPreferenceScreen(),
|
||||
"audio_download",
|
||||
getString(com.vtosters.lite.R.string.audio_download_title),
|
||||
null,
|
||||
null,
|
||||
preference -> {
|
||||
dlaudio(requireContext());
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
PreferenceFragmentUtils.addMaterialSwitchPreference(
|
||||
getPreferenceScreen(),
|
||||
"invertCachedTracks",
|
||||
getString(com.vtosters.lite.R.string.invertcached_title),
|
||||
getString(com.vtosters.lite.R.string.invertcached_summ),
|
||||
null,
|
||||
false,
|
||||
(preference, o) -> {
|
||||
Preferences.getPreferences().edit().putBoolean("invertCachedTracks", (boolean) o).apply();
|
||||
return true;
|
||||
}
|
||||
).setEnabled(!MusicCacheImpl.isEmpty());
|
||||
|
||||
PreferenceFragmentUtils.addMaterialSwitchPreference(
|
||||
getPreferenceScreen(),
|
||||
"autocache",
|
||||
getString(com.vtosters.lite.R.string.autocache_title),
|
||||
getString(com.vtosters.lite.R.string.autocache_summ),
|
||||
null,
|
||||
false,
|
||||
(preference, o) -> {
|
||||
Preferences.getPreferences().edit().putBoolean("autocache", (boolean) o).apply();
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
PreferenceFragmentUtils.addPreferenceCategory(getPreferenceScreen(), "Скачивание аудио в MP3");
|
||||
|
||||
PreferenceFragmentUtils.addMaterialSwitchPreference(
|
||||
getPreferenceScreen(),
|
||||
"dldir",
|
||||
"Альтернативная папка для скачивания",
|
||||
"Использовать папку Downloads вместо Music для скачивания музыки в MP3",
|
||||
null,
|
||||
false,
|
||||
(preference, o) -> {
|
||||
Preferences.getPreferences().edit().putBoolean("dldir", (boolean) o).apply();
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
PreferenceFragmentUtils.addMaterialSwitchPreference(
|
||||
getPreferenceScreen(),
|
||||
"setMetaData",
|
||||
"Сохранять метадату песен",
|
||||
"Сохранять id3v2 теги для песен для MP3",
|
||||
null,
|
||||
true,
|
||||
(preference, o) -> {
|
||||
Preferences.getPreferences().edit().putBoolean("setMetaData", (boolean) o).apply();
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
if (!Preferences.serverFeaturesDisable()) {
|
||||
PreferenceFragmentUtils.addPreferenceCategory(getPreferenceScreen(), "Интеграция Genius");
|
||||
PreferenceFragmentUtils.addMaterialSwitchPreference(
|
||||
getPreferenceScreen(),
|
||||
"useGenius",
|
||||
getString(com.vtosters.lite.R.string.useGenius_title),
|
||||
getString(com.vtosters.lite.R.string.useGenius_summ),
|
||||
null,
|
||||
false,
|
||||
(preference, o) -> {
|
||||
Preferences.getPreferences().edit().putBoolean("useGenius", (boolean) o).apply();
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
PreferenceFragmentUtils.addPreferenceCategory(getPreferenceScreen(), "Интеграция Last.fm");
|
||||
|
||||
PreferenceFragmentUtils.addPreference(
|
||||
getPreferenceScreen(),
|
||||
"lastfm_auth",
|
||||
getString(com.vtosters.lite.R.string.lastfm_auth_title),
|
||||
getString(com.vtosters.lite.R.string.lastfm_auth_summ),
|
||||
null,
|
||||
preference -> {
|
||||
if (LastFMScrobbler.isLoggedIn()) {
|
||||
logout(getContext());
|
||||
} else {
|
||||
lastfmAuth(getContext());
|
||||
}
|
||||
updateLastFmPref();
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
PreferenceFragmentUtils.addMaterialSwitchPreference(
|
||||
getPreferenceScreen(),
|
||||
"lastfm_enabled",
|
||||
AndroidUtils.getString("lastfm_enabled_title"),
|
||||
AndroidUtils.getString("lastfm_enabled_summ"),
|
||||
null,
|
||||
false,
|
||||
(preference, o) -> {
|
||||
Preferences.getPreferences().edit().putBoolean("lastfm_enabled", (boolean) o).apply();
|
||||
return true;
|
||||
}
|
||||
).setEnabled(LastFMScrobbler.isLoggedIn());
|
||||
|
||||
if (LastFMScrobbler.isLoggedIn()) {
|
||||
findPreference("lastfm_auth").setSummary(getString(com.vtosters.lite.R.string.lastfm_authorized_as) + " " + LastFMScrobbler.getUserName());
|
||||
}
|
||||
|
||||
PreferenceFragmentUtils.addPreferenceCategory(getPreferenceScreen(), "Интеграция VK X");
|
||||
|
||||
PreferenceFragmentUtils.addPreference(
|
||||
getPreferenceScreen(),
|
||||
"",
|
||||
getString(com.vtosters.lite.R.string.vkx_why),
|
||||
getString(com.vtosters.lite.R.string.vkx_why_summary),
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
||||
PreferenceFragmentUtils.addMaterialSwitchPreference(
|
||||
getPreferenceScreen(),
|
||||
"libvkx_integration",
|
||||
getString(com.vtosters.lite.R.string.vkx_integration),
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
(preference, o) -> {
|
||||
Preferences.getPreferences().edit().putBoolean("libvkx_integration", (boolean) o).apply();
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
if (!LibVKXClient.isVkxInstalled()) {
|
||||
findPreference("libvkx_integration").setSummary("У вас не установлен VKX. Интеграция работать не будет");
|
||||
findPreference("libvkx_integration").setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
PreferenceFragmentUtils.addPreferenceCategory(getPreferenceScreen(), "Прочее");
|
||||
|
||||
PreferenceFragmentUtils.addMaterialSwitchPreference(
|
||||
getPreferenceScreen(),
|
||||
"useOldAppVer",
|
||||
getString(com.vtosters.lite.R.string.useOldAppVer_title),
|
||||
"Включите если вас не устраивают новые рекомендации и вас интересует только свое аудио",
|
||||
null,
|
||||
false,
|
||||
(preference, o) -> {
|
||||
Preferences.getPreferences().edit().putBoolean("useOldAppVer", (boolean) o).apply();
|
||||
LifecycleUtils.restartApplicationWithTimer();
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
SummaryListPreference list = new SummaryListPreference(getPreferenceScreen().getContext());
|
||||
list.setTitle(com.vtosters.lite.R.string.musicdefcatalog_title);
|
||||
list.setKey("musicdefcatalog");
|
||||
list.setEntryValues(com.vtosters.lite.R.array.musicdefcatalog);
|
||||
list.setEntries(com.vtosters.lite.R.array.musicdefcatalog_value);
|
||||
list.setDialogTitle(com.vtosters.lite.R.string.musicdefcatalog_dialogTitle);
|
||||
list.setDefaultValue("default");
|
||||
list.setVisible(!Preferences.getBoolValue("useOldAppVer", false));
|
||||
|
||||
getPreferenceScreen().addPreference(list);
|
||||
}
|
||||
|
||||
private void lastfmAuth(Context ctx) {
|
||||
LinearLayout linearLayout = new LinearLayout(ctx);
|
||||
linearLayout.setOrientation(LinearLayout.VERTICAL);
|
||||
|
||||
EditText fn = new EditText(ctx);
|
||||
fn.setHint(com.vtosters.lite.R.string.lastfm_login);
|
||||
fn.setTextColor(ThemesUtils.getTextAttr());
|
||||
fn.setHintTextColor(ThemesUtils.getSTextAttr());
|
||||
fn.setBackgroundTintList(ThemesUtils.getAccenedColorStateList());
|
||||
linearLayout.addView(fn);
|
||||
fn.getLayoutParams().width = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
ViewGroup.MarginLayoutParams margin = ((ViewGroup.MarginLayoutParams) fn.getLayoutParams());
|
||||
margin.setMargins(AndroidUtils.dp2px(20f), 0, AndroidUtils.dp2px(20f), 0);
|
||||
fn.setLayoutParams(margin);
|
||||
|
||||
EditText ln = new EditText(ctx);
|
||||
ln.setHint(com.vtosters.lite.R.string.lastfm_password);
|
||||
ln.setTextColor(ThemesUtils.getTextAttr());
|
||||
ln.setHintTextColor(ThemesUtils.getSTextAttr());
|
||||
ln.setBackgroundTintList(ThemesUtils.getAccenedColorStateList());
|
||||
linearLayout.addView(ln);
|
||||
ln.getLayoutParams().width = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
ln.setLayoutParams(margin);
|
||||
|
||||
new VkAlertDialog.Builder(ctx)
|
||||
.setTitle(com.vtosters.lite.R.string.lastfm_enter_credentials)
|
||||
.setPositiveButton(com.vtosters.lite.R.string.lastfm_enter,
|
||||
(dialog, which) -> {
|
||||
String login = fn.getText().toString();
|
||||
String pass = ln.getText().toString();
|
||||
LastFMScrobbler.authenticate(login, pass);
|
||||
}
|
||||
)
|
||||
.setView(linearLayout)
|
||||
.show();
|
||||
}
|
||||
|
||||
public void updateLastFmPref() {
|
||||
if (LastFMScrobbler.isLoggedIn()) {
|
||||
findPreference("lastfm_auth").setSummary(getString(com.vtosters.lite.R.string.lastfm_authorized_as) + " " + LastFMScrobbler.getUserName());
|
||||
findPreference("lastfm_enabled").setEnabled(true);
|
||||
} else {
|
||||
findPreference("lastfm_auth").setSummary(getString(com.vtosters.lite.R.string.lastfm_auth_summ));
|
||||
findPreference("lastfm_enabled").setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void logout(Context ctx) {
|
||||
new VkAlertDialog.Builder(ctx)
|
||||
.setTitle(com.vtosters.lite.R.string.lastfm_logout_title)
|
||||
.setMessage(com.vtosters.lite.R.string.lastfm_logout_confirm)
|
||||
.setPositiveButton(com.vtosters.lite.R.string.vkim_yes,
|
||||
(dialog, which) -> LastFMScrobbler.logout())
|
||||
.setNeutralButton(com.vtosters.lite.R.string.vkim_no,
|
||||
(dialog, which) -> dialog.cancel())
|
||||
.show();
|
||||
}
|
||||
|
||||
private void delcache(Context ctx) {
|
||||
new VkAlertDialog.Builder(ctx)
|
||||
.setTitle(com.vtosters.lite.R.string.warning)
|
||||
.setMessage(com.vtosters.lite.R.string.cached_tracks_remove_confirm)
|
||||
.setPositiveButton(com.vtosters.lite.R.string.yes,
|
||||
(dialog, which) -> executor.submit(MusicCacheImpl::clear))
|
||||
.setNeutralButton(com.vtosters.lite.R.string.no,
|
||||
(dialog, which) -> dialog.cancel())
|
||||
.show();
|
||||
}
|
||||
|
||||
private void dlaudio(Context ctx) {
|
||||
if (LibVKXClient.isIntegrationEnabled()) {
|
||||
AndroidUtils.sendToast(AndroidUtils.getString("vkx_integration_enabled_info"));
|
||||
return;
|
||||
}
|
||||
|
||||
new VkAlertDialog.Builder(ctx)
|
||||
.setTitle(com.vtosters.lite.R.string.download_method)
|
||||
.setMessage(com.vtosters.lite.R.string.download_method_desc)
|
||||
.setPositiveButton(com.vtosters.lite.R.string.download_method_cache, (dialog, which) -> {
|
||||
executor.submit(AudioDownloader::cacheAllAudios);
|
||||
})
|
||||
.setNegativeButton(com.vtosters.lite.R.string.download_method_mp3, (dialog, which) -> {
|
||||
executor.submit(AudioDownloader::downloadAllAudios);
|
||||
})
|
||||
.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int T4() {
|
||||
return com.vtosters.lite.R.string.vtl_music_settings;
|
||||
}
|
||||
}
|
||||
@@ -105,6 +105,7 @@ public class OtherFragment extends TrackedMaterialPreferenceToolbarFragment {
|
||||
|
||||
findPreference("updateverifdata").setOnPreferenceClickListener(preference -> {
|
||||
UsersList.getUsersList();
|
||||
VTVerifications.isLoaded = false;
|
||||
VTVerifications.load(requireContext());
|
||||
AndroidUtils.sendToast(AndroidUtils.getString("data_updated"));
|
||||
return true;
|
||||
|
||||
@@ -1,21 +1,32 @@
|
||||
package ru.vtosters.lite.ui.fragments;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.SwitchPreference;
|
||||
import b.h.g.k.VKProgressDialog;
|
||||
import com.vk.core.network.Network;
|
||||
import com.vk.core.network.proxy.NetworkProxy;
|
||||
import com.vk.core.util.ToastUtils;
|
||||
import com.vtosters.lite.NetworkProxyPreferences;
|
||||
import com.vtosters.lite.R;
|
||||
import com.vtosters.lite.ViewUtils;
|
||||
|
||||
public class ProxySettingsFragment extends TrackedMaterialPreferenceToolbarFragment {
|
||||
@Override
|
||||
public void onCreate(Bundle bundle) {
|
||||
super.onCreate(bundle);
|
||||
addPreferencesFromResource(R.xml.preferences_proxy);
|
||||
// findPreference("random_proxy").setOnPreferenceClickListener(preference -> {
|
||||
// try {
|
||||
// setupNewProxy();
|
||||
// } catch (IOException e) {
|
||||
// sendToast(requireContext().getString(R.string.get_proxy_error));
|
||||
// }
|
||||
// return true;
|
||||
// });
|
||||
initComponents();
|
||||
}
|
||||
|
||||
private void initComponents() {
|
||||
NetworkProxy networkProxy = Network.l.b();
|
||||
boolean isEnabled = networkProxy.d();
|
||||
SwitchPreference switchPreference = (SwitchPreference) findPreference("vkproxy");
|
||||
switchPreference.setChecked(isEnabled);
|
||||
switchPreference.setOnPreferenceChangeListener(new ProxyChangeListener(networkProxy, switchPreference));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -23,3 +34,89 @@ public class ProxySettingsFragment extends TrackedMaterialPreferenceToolbarFragm
|
||||
return R.string.vtlproxy;
|
||||
}
|
||||
}
|
||||
|
||||
class ProxyChangeListener implements Preference.OnPreferenceChangeListener {
|
||||
|
||||
private final NetworkProxy networkProxy;
|
||||
private final SwitchPreference switchPreference;
|
||||
|
||||
ProxyChangeListener(NetworkProxy networkProxy, SwitchPreference switchPreference) {
|
||||
this.networkProxy = networkProxy;
|
||||
this.switchPreference = switchPreference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object obj) {
|
||||
handleProxyChange(preference, (Boolean) obj);
|
||||
return false;
|
||||
}
|
||||
|
||||
private void handleProxyChange(Preference preference, Boolean isEnabled) {
|
||||
if (!networkProxy.d() && isEnabled) {
|
||||
enableProxy(preference);
|
||||
} else {
|
||||
disableProxy();
|
||||
}
|
||||
}
|
||||
|
||||
private void enableProxy(Preference preference) {
|
||||
networkProxy.a(true);
|
||||
VKProgressDialog vKProgressDialog = createProgressDialog(preference.getContext());
|
||||
networkProxy.a((NetworkProxy.c) new ProxyPreferences(vKProgressDialog));
|
||||
}
|
||||
|
||||
private void disableProxy() {
|
||||
Network.l.b().a(false);
|
||||
switchPreference.setChecked(networkProxy.d());
|
||||
}
|
||||
|
||||
private VKProgressDialog createProgressDialog(Context context) {
|
||||
VKProgressDialog vKProgressDialog = new VKProgressDialog(context);
|
||||
vKProgressDialog.setMessage(context.getString(R.string.loading));
|
||||
vKProgressDialog.setOnDismissListener(new OnDismissListener());
|
||||
ViewUtils.b(vKProgressDialog);
|
||||
return vKProgressDialog;
|
||||
}
|
||||
|
||||
private class OnDismissListener implements DialogInterface.OnDismissListener {
|
||||
@Override
|
||||
public void onDismiss(DialogInterface dialogInterface) {
|
||||
switchPreference.setChecked(networkProxy.d());
|
||||
}
|
||||
}
|
||||
|
||||
private class ProxyPreferences extends NetworkProxyPreferences {
|
||||
private final VKProgressDialog progressDialog;
|
||||
|
||||
ProxyPreferences(VKProgressDialog vKProgressDialog) {
|
||||
this.progressDialog = vKProgressDialog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void b(NetworkProxy.Reason reason) {
|
||||
super.b(reason);
|
||||
dismissProgressDialog();
|
||||
switchPreference.setChecked(networkProxy.d());
|
||||
showToast(reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void e() {
|
||||
super.e();
|
||||
dismissProgressDialog();
|
||||
switchPreference.setChecked(networkProxy.d());
|
||||
}
|
||||
|
||||
private void dismissProgressDialog() {
|
||||
ViewUtils.a(progressDialog);
|
||||
}
|
||||
|
||||
private void showToast(NetworkProxy.Reason reason) {
|
||||
if (reason == NetworkProxy.Reason.PROXY_NOT_AVAILABLE) {
|
||||
ToastUtils.a(R.string.sett_proxy_not_available);
|
||||
} else {
|
||||
ToastUtils.a(R.string.sett_no_proxy);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,8 +6,10 @@ import android.os.Bundle;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.hooks.other.ThemesUtils;
|
||||
import ru.vtosters.lite.ui.PreferenceFragmentUtils;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.NetworkUtils;
|
||||
import ru.vtosters.sponsorpost.data.Filter;
|
||||
import ru.vtosters.sponsorpost.internal.VotesPreferences;
|
||||
import ru.vtosters.sponsorpost.services.FilterService;
|
||||
import ru.vtosters.sponsorpost.utils.FiltersPreferences;
|
||||
import ru.vtosters.sponsorpost.utils.PostsPreferences;
|
||||
@@ -35,6 +37,40 @@ public class SponsorPostFragment extends TrackedMaterialPreferenceToolbarFragmen
|
||||
null
|
||||
);
|
||||
|
||||
PreferenceFragmentUtils.addPreferenceCategory(getPreferenceScreen(), "Статистика блокировок");
|
||||
|
||||
PreferenceFragmentUtils.addPreference(
|
||||
getPreferenceScreen(),
|
||||
"",
|
||||
"SponsorPost",
|
||||
"Заблокировано постов: " + PostsPreferences.getNumBlockedPosts(),
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
||||
PreferenceFragmentUtils.addPreference(
|
||||
getPreferenceScreen(),
|
||||
"",
|
||||
"SponsorPost фильтры",
|
||||
"Заблокировано постов: " + FiltersPreferences.getNumBlockedPosts(),
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
||||
PreferenceFragmentUtils.addPreference(
|
||||
getPreferenceScreen(),
|
||||
"",
|
||||
"Сброс статистики",
|
||||
null,
|
||||
null,
|
||||
preference -> {
|
||||
FiltersPreferences.dropNumBlockedPosts();
|
||||
PostsPreferences.dropNumBlockedPosts();
|
||||
AndroidUtils.sendToast("Статистика сброшена");
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
PreferenceFragmentUtils.addPreferenceCategory(getPreferenceScreen(), "Sponsor Post");
|
||||
|
||||
if (Preferences.serverFeaturesDisable()) {
|
||||
@@ -49,9 +85,9 @@ public class SponsorPostFragment extends TrackedMaterialPreferenceToolbarFragmen
|
||||
} else {
|
||||
PreferenceFragmentUtils.addMaterialSwitchPreference(
|
||||
getPreferenceScreen(),
|
||||
"sponsorpost",
|
||||
"",
|
||||
"Фильтр постов",
|
||||
"Получать списки рекламных постов в группах и ленте, которые не блокируются рекламными фильтрами",
|
||||
"Получать списки рекламных постов в группах и ленте, которые не блокируются рекламными фильтрами\n\nРекомендуется использовать совместно со Стандартным фильтром",
|
||||
null,
|
||||
PostsPreferences.isEnabled(),
|
||||
(preference, o) -> {
|
||||
@@ -59,6 +95,61 @@ public class SponsorPostFragment extends TrackedMaterialPreferenceToolbarFragmen
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
PreferenceFragmentUtils.addMaterialSwitchPreference(
|
||||
getPreferenceScreen(),
|
||||
"",
|
||||
"Не скрывать посты",
|
||||
"Помечать посты рекламной пометкой, но не скрывать их полностью",
|
||||
null,
|
||||
PostsPreferences.isEnabledMarking(),
|
||||
(preference, o) -> {
|
||||
PostsPreferences.setEnabledMarking((boolean) o);
|
||||
return true;
|
||||
}
|
||||
).setEnabled(PostsPreferences.isEnabled());
|
||||
|
||||
PreferenceFragmentUtils.addMaterialSwitchPreference(
|
||||
getPreferenceScreen(),
|
||||
"",
|
||||
"Предварительные списки",
|
||||
"Получать дополнительно более свежие списки которые ещё не попали в основной список. Нужно для активного голосования для блокировки постов. Возможно много ошибок!",
|
||||
null,
|
||||
VotesPreferences.isEnabled(),
|
||||
(preference, o) -> {
|
||||
VotesPreferences.setEnabled((boolean) o);
|
||||
return true;
|
||||
}
|
||||
).setEnabled(PostsPreferences.isEnabled());
|
||||
|
||||
if (NetworkUtils.isNetworkConnected()) {
|
||||
PreferenceFragmentUtils.addPreference(
|
||||
getPreferenceScreen(),
|
||||
"",
|
||||
"Обновить списки постов",
|
||||
null,
|
||||
null,
|
||||
preference -> {
|
||||
this.requireActivity().runOnUiThread(() -> {
|
||||
Updates.updatePosts();
|
||||
AndroidUtils.sendToast("Обновлено");
|
||||
});
|
||||
return false;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
PreferenceFragmentUtils.addPreference(
|
||||
getPreferenceScreen(),
|
||||
"",
|
||||
"Телеграм чат",
|
||||
"Помогите улучшить качество блокировки постов в нашем телеграм чате\n\nДля перехода в чат вам необходима последняя версия Telegram",
|
||||
null,
|
||||
preference -> {
|
||||
requireContext().startActivity(new Intent(Intent.ACTION_VIEW).setData(Uri.parse("https://t.me/vtosterschat/3559729")));
|
||||
return false;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
requireActivity().runOnUiThread(() -> {
|
||||
@@ -123,6 +214,31 @@ public class SponsorPostFragment extends TrackedMaterialPreferenceToolbarFragmen
|
||||
);
|
||||
}
|
||||
|
||||
PreferenceFragmentUtils.addMaterialSwitchPreference(
|
||||
getPreferenceScreen(),
|
||||
"",
|
||||
"Не блокировать посты",
|
||||
"Помечать посты заблокированные фильтрами",
|
||||
null,
|
||||
FiltersPreferences.isEnabledMarking(),
|
||||
(preference, o) -> {
|
||||
FiltersPreferences.setEnabledMarking((boolean) o);
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
PreferenceFragmentUtils.addPreference(
|
||||
getPreferenceScreen(),
|
||||
"",
|
||||
"Телеграм чат",
|
||||
"Помогите улучшить качество фильтров обсудив работу в нашем телеграм чате\n\nДля перехода в чат вам необходима последняя версия Telegram",
|
||||
null,
|
||||
preference -> {
|
||||
requireContext().startActivity(new Intent(Intent.ACTION_VIEW).setData(Uri.parse("https://t.me/vtosterschat/3559732")));
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
PreferenceFragmentUtils.addPreference(
|
||||
getPreferenceScreen(),
|
||||
"",
|
||||
@@ -139,6 +255,20 @@ public class SponsorPostFragment extends TrackedMaterialPreferenceToolbarFragmen
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (Preferences.dev()) {
|
||||
PreferenceFragmentUtils.addPreference(
|
||||
getPreferenceScreen(),
|
||||
"",
|
||||
"Сбросить токен пользователя",
|
||||
null,
|
||||
null,
|
||||
preference -> {
|
||||
VotesPreferences.remUserToken();
|
||||
return false;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -109,7 +109,7 @@ public class ThemesFragment extends TrackedMaterialPreferenceToolbarFragment {
|
||||
|
||||
newsfeedNotificationsPreference.setVisible(Preferences.milkshake());
|
||||
|
||||
findPreference("accentprefs").setVisible(!ThemesUtils.isMonetTheme());
|
||||
findPreference("accentprefs").setVisible(!ThemesUtils.isMonetTheme() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M);
|
||||
|
||||
findPreference("systememoji").setOnPreferenceClickListener(preference -> {
|
||||
restart();
|
||||
|
||||
@@ -42,6 +42,7 @@ import ru.vtosters.hooks.ui.SystemThemeChangerHook;
|
||||
import ru.vtosters.lite.BuildConfig;
|
||||
import ru.vtosters.lite.concurrent.VTExecutors;
|
||||
import ru.vtosters.lite.deviceinfo.OEMDetector;
|
||||
import ru.vtosters.lite.proxy.ProxyUtils;
|
||||
import ru.vtosters.lite.ssfs.Utils;
|
||||
import ru.vtosters.lite.themes.utils.RecolorUtils;
|
||||
import ru.vtosters.lite.ui.PreferenceFragmentUtils;
|
||||
@@ -77,9 +78,13 @@ public class VTSettings extends TrackedMaterialPreferenceToolbarFragment {
|
||||
|
||||
public static String getProxysumm() {
|
||||
String type = Preferences.getString("proxy");
|
||||
boolean isVKProxy = ProxyUtils.isVKProxyEnabled();
|
||||
|
||||
if (type.equals("noproxy") || type.isEmpty())
|
||||
if (isVKProxy) {
|
||||
type = "Встроенный";
|
||||
} else if (type.equals("noproxy") || type.isEmpty()) {
|
||||
type = AndroidUtils.getString(R.string.vtlsettdisabled);
|
||||
}
|
||||
|
||||
return AndroidUtils.getString(R.string.vtlproxysumm) + ": " + type;
|
||||
}
|
||||
@@ -466,6 +471,18 @@ public class VTSettings extends TrackedMaterialPreferenceToolbarFragment {
|
||||
}
|
||||
);
|
||||
|
||||
PreferenceFragmentUtils.addPreference(
|
||||
getPreferenceScreen(),
|
||||
"",
|
||||
requireContext().getString(R.string.music),
|
||||
getValAsString(R.string.useGenius_title, Preferences.getBoolValue("useGenius", false)),
|
||||
R.drawable.ic_music_outline_28,
|
||||
preference -> {
|
||||
NavigatorUtils.switchFragment(requireContext(), MusicFragment.class);
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
PreferenceFragmentUtils.addPreference(
|
||||
getPreferenceScreen(),
|
||||
"",
|
||||
|
||||
@@ -8,6 +8,7 @@ import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
import com.vk.core.dialogs.alert.VkAlertDialog;
|
||||
import com.vk.dto.common.VideoFile;
|
||||
import ru.vtosters.lite.downloaders.VideoDownloader;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -77,40 +78,7 @@ public class ExternalLinkParser {
|
||||
* this.D = var66.optString("mp4_2160");
|
||||
*/
|
||||
public static boolean parseVKVideo(VideoFile videoFile, List<String> qualities, List<String> urls) {
|
||||
if (!TextUtils.isEmpty(videoFile.D)) {
|
||||
qualities.add("2160p");
|
||||
urls.add(videoFile.D);
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(videoFile.C)) {
|
||||
qualities.add("1440p");
|
||||
urls.add(videoFile.C);
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(videoFile.B)) {
|
||||
qualities.add("1080p");
|
||||
urls.add(videoFile.B);
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(videoFile.h)) {
|
||||
qualities.add("720p");
|
||||
urls.add(videoFile.h);
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(videoFile.g)) {
|
||||
qualities.add("480p");
|
||||
urls.add(videoFile.g);
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(videoFile.f)) {
|
||||
qualities.add("360p");
|
||||
urls.add(videoFile.f);
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(videoFile.e)) {
|
||||
qualities.add("240p");
|
||||
urls.add(videoFile.e);
|
||||
}
|
||||
VideoDownloader.addVideos(videoFile, qualities, urls);
|
||||
|
||||
return qualities.size() > 0;
|
||||
}
|
||||
|
||||
@@ -6,33 +6,48 @@ import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import com.vk.core.network.Network;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.hooks.other.ThemesUtils;
|
||||
|
||||
import java.net.URL;
|
||||
import java.io.IOException;
|
||||
|
||||
public class ImageUtils {
|
||||
|
||||
// must be called asynchronously
|
||||
public static Drawable getDrawableFromUrl(String url, int placeholderRes, boolean rounded, boolean scaled) {
|
||||
if (NetworkUtils.isNetworkConnected() && !NetworkUtils.isInternetSlow()) {
|
||||
try {
|
||||
var bmp = BitmapFactory.decodeStream(new URL(url).openStream());
|
||||
Bitmap bmp = downloadBitmap(url);
|
||||
|
||||
if (bmp != null) {
|
||||
if (rounded) bmp = getBitmapClippedCircle(bmp);
|
||||
if (scaled)
|
||||
bmp = Bitmap.createScaledBitmap(bmp, AndroidUtils.dp2px(256), AndroidUtils.dp2px(256), true);
|
||||
|
||||
return new BitmapDrawable(AndroidUtils.getResources(), bmp);
|
||||
if (bmp != null) {
|
||||
if (rounded) {
|
||||
bmp = getBitmapClippedCircle(bmp);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
if (scaled) {
|
||||
bmp = Bitmap.createScaledBitmap(bmp, AndroidUtils.dp2px(256), AndroidUtils.dp2px(256), true);
|
||||
}
|
||||
|
||||
return new BitmapDrawable(AndroidUtils.getResources(), bmp);
|
||||
}
|
||||
}
|
||||
return placeholderRes > 0 ? ContextCompat.getDrawable(AndroidUtils.getGlobalContext(), placeholderRes) : null;
|
||||
}
|
||||
|
||||
public static Bitmap downloadBitmap(String url) {
|
||||
Request request = new Request.a()
|
||||
.b(url)
|
||||
.a();
|
||||
|
||||
try (Response resp = Network.b(Network.ClientType.CLIENT_IMAGE_LOADER).a(request).execute()) {
|
||||
return BitmapFactory.decodeStream(resp.a().a());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Bitmap scaleCenterCrop(Bitmap source, int newHeight, int newWidth) {
|
||||
int sourceWidth = source.getWidth();
|
||||
int sourceHeight = source.getHeight();
|
||||
|
||||
@@ -5,6 +5,7 @@ import okhttp3.*;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
|
||||
import ru.vtosters.sponsorpost.utils.GzipDecompressor;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -25,6 +26,7 @@ public class OTAUtils {
|
||||
public void loadData(boolean isManualCheck) {
|
||||
Request release = new Request.a()
|
||||
.b(LATEST_RELEASE_URL)
|
||||
.a("Accept-Encoding", "gzip")
|
||||
.a();
|
||||
|
||||
mClient.a(release).a(new Callback() {
|
||||
@@ -46,12 +48,13 @@ public class OTAUtils {
|
||||
});
|
||||
}
|
||||
|
||||
void setData(Response response, boolean isManualCheck) throws IOException, JSONException {
|
||||
mReleaseJson = new JSONObject(response.a().g());
|
||||
void setData(Response response, boolean isManualCheck) throws JSONException, IOException {
|
||||
mReleaseJson = new JSONObject(GzipDecompressor.decompressResponse(response));
|
||||
|
||||
String tag = mReleaseJson.getString("tag_name");
|
||||
Request commit = new Request.a()
|
||||
.b(String.format(LATEST_RELEASE_COMMIT_URL, tag))
|
||||
.a("Accept-Encoding", "gzip")
|
||||
.a();
|
||||
|
||||
mClient.a(commit).a(new Callback() {
|
||||
@@ -62,15 +65,15 @@ public class OTAUtils {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(Call call, Response response) throws IOException {
|
||||
public void a(Call call, Response response) {
|
||||
try {
|
||||
mCommitJson = new JSONObject(response.a().g());
|
||||
mCommitJson = new JSONObject(GzipDecompressor.decompressResponse(response));
|
||||
mCommitSHA = mCommitJson.getJSONObject("object").getString("sha");
|
||||
if (isNewVersion())
|
||||
mListener.onUpdateApplied(isManualCheck);
|
||||
else
|
||||
mListener.onUpdateLatest(isManualCheck);
|
||||
} catch (NullPointerException | JSONException e) {
|
||||
} catch (NullPointerException | JSONException | IOException e) {
|
||||
e.printStackTrace();
|
||||
mListener.onUpdateError();
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
package ru.vtosters.lite.utils;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.Signature;
|
||||
import android.content.pm.SigningInfo;
|
||||
import android.os.Build;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import static android.content.pm.PackageManager.GET_SIGNATURES;
|
||||
import static android.content.pm.PackageManager.NameNotFoundException;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getPackageName;
|
||||
@@ -36,11 +37,29 @@ public class SignatureChecker {
|
||||
}
|
||||
|
||||
public static boolean validateAppSignature() throws NameNotFoundException, NoSuchAlgorithmException {
|
||||
@SuppressLint("PackageManagerGetSignatures") PackageInfo packageInfo = getGlobalContext().getPackageManager().getPackageInfo(getPackageName(), GET_SIGNATURES);
|
||||
for (Signature signature : packageInfo.signatures) {
|
||||
String sha1 = getSHA1(signature.toByteArray());
|
||||
return Base64Utils.decode(APP_SIGNATURE).equals(sha1);
|
||||
String appSignature = Base64Utils.decode(APP_SIGNATURE);
|
||||
PackageManager pm = getGlobalContext().getPackageManager();
|
||||
if (Build.VERSION.SDK_INT >= 28) {
|
||||
PackageInfo packageInfo = pm.getPackageInfo(getPackageName(), PackageManager.GET_SIGNING_CERTIFICATES);
|
||||
SigningInfo signingInfo = packageInfo.signingInfo;
|
||||
if (signingInfo.hasMultipleSigners() || signingInfo.hasPastSigningCertificates()) {
|
||||
return false;
|
||||
} else {
|
||||
byte[] signatureBytes = signingInfo.getSigningCertificateHistory()[0].toByteArray();
|
||||
String sha1 = getSHA1(signatureBytes);
|
||||
return appSignature.equals(sha1);
|
||||
}
|
||||
} else {
|
||||
PackageInfo packageInfo = pm.getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES);
|
||||
Signature[] signatures = packageInfo.signatures;
|
||||
for (Signature signature : signatures) {
|
||||
byte[] signatureBytes = signature.toByteArray();
|
||||
String sha1 = getSHA1(signatureBytes);
|
||||
if (appSignature.equals(sha1)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
} // Sig check to detect actions builds and etc
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,74 +5,77 @@ import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class SuperAppUtils {
|
||||
public static JSONObject menu(JSONObject orig) throws JSONException {
|
||||
var Special = orig.optJSONArray("special");
|
||||
var Main = orig.getJSONArray("main");
|
||||
var Other = orig.optJSONArray("other");
|
||||
|
||||
if (Special != null) {
|
||||
orig.remove("special");
|
||||
}
|
||||
|
||||
public static JSONObject menu(JSONObject orig) {
|
||||
orig.remove("special");
|
||||
return orig;
|
||||
}
|
||||
|
||||
public static JSONObject superapp(JSONObject json) throws JSONException {
|
||||
var superApps = Preferences.getPreferences().getString("superapp_items", "menu,miniapps,vkpay_slim,greeting,promo,holiday,weather,sport,games,informer,food,event,music,vk_run").split(",");
|
||||
String[] superApps = Preferences.getPreferences().getString("superapp_items", "menu,miniapps,vkpay_slim,greeting,promo,holiday,weather,sport,games,informer,food,event,music,vk_run").split(",");
|
||||
|
||||
if (superApps.length == 0) return json;
|
||||
|
||||
var oldItems = json.optJSONArray("items");
|
||||
var newItems = new JSONArray();
|
||||
JSONArray oldItems = json.optJSONArray("items");
|
||||
JSONArray newItems = new JSONArray();
|
||||
if (oldItems != null) {
|
||||
for (int i = 0; i < oldItems.length(); i++) {
|
||||
var item = oldItems.optJSONObject(i);
|
||||
var type = item.optString("type");
|
||||
for (String superApp : superApps) {
|
||||
if (type.equals(superApp))
|
||||
if (superApp.equals("menu")) { // superapp menu fix
|
||||
String menuitems = "groups,audios,stickers,podcasts,shopping,lives,videos,games,vk_calls,vk_pay,ads_easy_promote,classifieds,events";
|
||||
JSONObject menuItem = new JSONObject();
|
||||
JSONArray menuItems = new JSONArray();
|
||||
Stream<JSONObject> streamOfItems = IntStream.range(0, oldItems.length())
|
||||
.mapToObj(oldItems::optJSONObject)
|
||||
.filter(item -> Arrays.asList(superApps).contains(item.optString("type")));
|
||||
|
||||
generateMenuItems(menuitems, menuItems);
|
||||
streamOfItems = streamOfItems.map(SuperAppUtils::apply);
|
||||
|
||||
JSONObject object = new JSONObject();
|
||||
object.put("count", menuitems.split(",").length);
|
||||
object.put("items", menuItems);
|
||||
streamOfItems = streamOfItems.sorted(Comparator.comparingInt(item -> Arrays.asList(superApps).indexOf(item.optString("type"))));
|
||||
|
||||
menuItem.put("type", "menu");
|
||||
menuItem.put("object", object);
|
||||
|
||||
newItems.put(menuItem);
|
||||
} else {
|
||||
newItems.put(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < superApps.length; i++) {
|
||||
for (int j = i; j < newItems.length(); j++) {
|
||||
var item = newItems.optJSONObject(j);
|
||||
if (superApps[i].equals(item.optString("type")))
|
||||
newItems.put(j, newItems.getJSONObject(i))
|
||||
.put(i, item);
|
||||
}
|
||||
}
|
||||
streamOfItems.forEach(newItems::put);
|
||||
}
|
||||
|
||||
return json.putOpt("items", newItems);
|
||||
}
|
||||
|
||||
|
||||
private static void generateMenuItems(String str, JSONArray jsonArray) throws JSONException {
|
||||
String[] strings = str.split(",");
|
||||
Stream<String> streamOfStrings = Arrays.stream(str.split(","));
|
||||
|
||||
for (String string : strings) {
|
||||
streamOfStrings.map(string -> {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
try {
|
||||
jsonObject.put("name", string);
|
||||
} catch (JSONException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return jsonObject;
|
||||
}).forEach(jsonArray::put);
|
||||
}
|
||||
|
||||
jsonObject.put("name", string);
|
||||
private static JSONObject apply(JSONObject item) {
|
||||
if (item.optString("type").equals("menu")) {
|
||||
String menuitems = "groups,audios,stickers,podcasts,shopping,lives,videos,games,vk_calls,ads_easy_promote,classifieds"; // vk_pay,events
|
||||
JSONObject menuItem = new JSONObject();
|
||||
JSONArray menuItems = new JSONArray();
|
||||
|
||||
jsonArray.put(jsonObject);
|
||||
try {
|
||||
JSONObject object = new JSONObject();
|
||||
|
||||
object.put("count", menuitems.split(",").length);
|
||||
object.put("items", menuItems);
|
||||
|
||||
menuItem.put("type", "menu");
|
||||
menuItem.put("object", object);
|
||||
|
||||
generateMenuItems(menuitems, menuItems);
|
||||
} catch (JSONException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return menuItem;
|
||||
} else {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -70,19 +70,22 @@ public class VKAccountDB {
|
||||
LifecycleUtils.getCurrentActivity().requestPermissions(new String[]{"android.permission.WRITE_EXTERNAL_STORAGE"}, 228);
|
||||
}
|
||||
|
||||
var db = getDatabase().getReadableDatabase();
|
||||
var dateFormat = new SimpleDateFormat("yyyy-MM-dd.HH-mm-ss", Locale.getDefault());
|
||||
var dir = new File(getExternalStoragePublicDirectory(DIRECTORY_DOWNLOADS), "/VTLBackups/");
|
||||
var file = new File(dir, "saved_accounts_" + dateFormat.format(new Date()) + ".vtl");
|
||||
SQLiteDatabase db = getDatabase().getReadableDatabase();
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd.HH-mm-ss", Locale.getDefault());
|
||||
File dir = new File(getExternalStoragePublicDirectory(DIRECTORY_DOWNLOADS), "/VTLBackups/");
|
||||
File file = new File(dir, "saved_accounts_" + dateFormat.format(new Date()) + ".vtl");
|
||||
|
||||
try (InputStream inputStream = new FileInputStream(db.getPath())) {
|
||||
dir.mkdirs();
|
||||
if (!dir.exists()) {
|
||||
dir.mkdirs();
|
||||
}
|
||||
|
||||
FileOutputStream outputStream = new FileOutputStream(file);
|
||||
byte[] buff = new byte[1024];
|
||||
int read;
|
||||
while ((read = inputStream.read(buff, 0, buff.length)) > 0)
|
||||
while ((read = inputStream.read(buff, 0, buff.length)) > 0) {
|
||||
outputStream.write(buff, 0, read);
|
||||
}
|
||||
inputStream.close();
|
||||
outputStream.close();
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package ru.vtosters.lite.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
import com.vk.core.network.Network;
|
||||
import com.vk.navigation.NavigatorKeys;
|
||||
import okhttp3.*;
|
||||
import org.json.JSONArray;
|
||||
@@ -9,6 +11,7 @@ import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
|
||||
import ru.vtosters.sponsorpost.utils.GzipDecompressor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
@@ -20,12 +23,11 @@ public class VTVerifications {
|
||||
public static final List<Integer> sVerifications = new ArrayList<>();
|
||||
public static final List<Integer> sPrometheuses = new ArrayList<>();
|
||||
public static final List<Integer> sDevelopers = new ArrayList<>();
|
||||
public static final List<Integer> sServiceAccounts = new ArrayList<>();
|
||||
private static final OkHttpClient sClient = VtOkHttpClient.getInstance();
|
||||
public static boolean isLoaded = false;
|
||||
|
||||
public static void load(Context context) {
|
||||
var prefs = context.getSharedPreferences("vt_another_data", 0);
|
||||
SharedPreferences prefs = context.getSharedPreferences("vt_another_data", 0);
|
||||
|
||||
if (isLoaded) {
|
||||
Log.d("VTVerifications", "already loaded");
|
||||
@@ -39,16 +41,17 @@ public class VTVerifications {
|
||||
return;
|
||||
}
|
||||
|
||||
var request = new Request.a()
|
||||
Request request = new Request.a()
|
||||
.b("https://vtosters.app/vktoaster/getGalo4kiBatch")
|
||||
.a(RequestBody.a(MediaType.b("application/json; charset=UTF-8"), "{\"types\":[0,228,404,1337]}"))
|
||||
.a(RequestBody.a(MediaType.b("application/json; charset=UTF-8"), "{\"types\":[0,228,404]}"))
|
||||
.a("Accept-Encoding", "gzip")
|
||||
.a();
|
||||
|
||||
sClient.a(request).a(new Callback() {
|
||||
@Override
|
||||
public void a(Call call, Response response) {
|
||||
try {
|
||||
var payload = response.a().g();
|
||||
String payload = GzipDecompressor.decompressResponse(response);
|
||||
parseJson(payload);
|
||||
prefs.edit()
|
||||
.putString("ids", payload)
|
||||
@@ -80,17 +83,15 @@ public class VTVerifications {
|
||||
* 0 - Verifications
|
||||
* 228 - Prometheus
|
||||
* 404 - Developer
|
||||
* 1337 - Service account
|
||||
*/
|
||||
private static void parseJson(String payload) {
|
||||
try {
|
||||
var json = new JSONObject(payload);
|
||||
JSONObject json = new JSONObject(payload);
|
||||
processIds(json.optJSONArray("0"), sVerifications);
|
||||
processIds(json.optJSONArray("228"), sPrometheuses);
|
||||
processIds(json.optJSONArray("404"), sDevelopers);
|
||||
processIds(json.optJSONArray("1337"), sServiceAccounts);
|
||||
} catch (JSONException e) {
|
||||
// ignored
|
||||
e.getStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,9 +101,9 @@ public class VTVerifications {
|
||||
|
||||
for (int i = 0; i < jsonIds.length(); i++) {
|
||||
try {
|
||||
member.add(jsonIds.optInt(i));
|
||||
} catch (Exception ignored) {
|
||||
// ignored
|
||||
member.add(jsonIds.getInt(i));
|
||||
} catch (JSONException e) {
|
||||
e.fillInStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,20 +116,13 @@ public class VTVerifications {
|
||||
return sDevelopers.contains(id);
|
||||
}
|
||||
|
||||
public static boolean isServiceAccount(int id) {
|
||||
return sServiceAccounts.contains(id);
|
||||
}
|
||||
|
||||
public static int getId(JSONObject json) {
|
||||
var id = json.optInt("id", 0);
|
||||
if (!json.optString(NavigatorKeys.e).equals("group") && !json.optString(NavigatorKeys.e).equals("page")
|
||||
|| json.optString(NavigatorKeys.e).isEmpty())
|
||||
return id;
|
||||
else
|
||||
return -id;
|
||||
int id = json.optInt("id", 0);
|
||||
String type = json.optString(NavigatorKeys.e);
|
||||
return isGroupOrPage(type) ? -id : id;
|
||||
}
|
||||
|
||||
// public static boolean haveDonateButton() {
|
||||
// return hasVerification() || new Random().nextInt(6) != 1;
|
||||
// }
|
||||
}
|
||||
private static boolean isGroupOrPage(String type) {
|
||||
return type.equals("group") || type.equals("page");
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package ru.vtosters.lite.utils;
|
||||
import android.webkit.WebView;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import static ru.vtosters.hooks.other.ThemesUtils.*;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getGlobalContext;
|
||||
@@ -13,25 +14,42 @@ public class WebViewColoringUtils {
|
||||
public static String loadedCSSAmoled = "";
|
||||
|
||||
private static String readCSS(String str) {
|
||||
try (var is = getGlobalContext().getAssets().open(str)) {
|
||||
return IOUtils.readAllLines(is)
|
||||
.replace("%header_background%", hex(getHeaderBackground()))
|
||||
.replace("%background_content%", hex(getBackgroundContent()))
|
||||
.replace("%header_text%", hex(getHeaderText()))
|
||||
.replace("%accent%", hex(getAccentColor()))
|
||||
.replace("%background_page%", hex(getBackgroundPage()))
|
||||
.replace("%content_tint_background%", hex(getColorFromAttr(com.vtosters.lite.R.attr.content_tint_background)))
|
||||
.replace("%button_primary_background%", hex(getColorFromAttr(com.vtosters.lite.R.attr.button_primary_background)))
|
||||
.replace("%button_outline_foreground%", hex(getColorFromAttr(com.vtosters.lite.R.attr.button_outline_foreground)))
|
||||
.replace("%button_outline_border%", hex(getColorFromAttr(com.vtosters.lite.R.attr.button_outline_border)))
|
||||
.replace("%field_background%", hex(getColorFromAttr(com.vtosters.lite.R.attr.field_background)))
|
||||
.replace("%field_border%", hex(getColorFromAttr(com.vtosters.lite.R.attr.field_border)))
|
||||
.replace("%text_primary%", hex(getTextAttr()));
|
||||
try (InputStream is = getGlobalContext().getAssets().open(str)) {
|
||||
return replaceWebAttrs(IOUtils.readAllLines(is));
|
||||
} catch (IOException e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private static String replaceWebAttrs(String css) {
|
||||
int headerBackground = getHeaderBackground();
|
||||
int backgroundContent = getBackgroundContent();
|
||||
int headerText = getHeaderText();
|
||||
int accentColor = getAccentColor();
|
||||
int backgroundPage = getBackgroundPage();
|
||||
int contentTintBackground = getColorFromAttr(com.vtosters.lite.R.attr.content_tint_background);
|
||||
int buttonPrimaryBackground = getColorFromAttr(com.vtosters.lite.R.attr.button_primary_background);
|
||||
int buttonOutlineForeground = getColorFromAttr(com.vtosters.lite.R.attr.button_outline_foreground);
|
||||
int buttonOutlineBorder = getColorFromAttr(com.vtosters.lite.R.attr.button_outline_border);
|
||||
int fieldBackground = getColorFromAttr(com.vtosters.lite.R.attr.field_background);
|
||||
int fieldBorder = getColorFromAttr(com.vtosters.lite.R.attr.field_border);
|
||||
int textPrimary = getTextAttr();
|
||||
|
||||
return css
|
||||
.replace("%header_background%", hex(headerBackground))
|
||||
.replace("%background_content%", hex(backgroundContent))
|
||||
.replace("%header_text%", hex(headerText))
|
||||
.replace("%accent%", hex(accentColor))
|
||||
.replace("%background_page%", hex(backgroundPage))
|
||||
.replace("%content_tint_background%", hex(contentTintBackground))
|
||||
.replace("%button_primary_background%", hex(buttonPrimaryBackground))
|
||||
.replace("%button_outline_foreground%", hex(buttonOutlineForeground))
|
||||
.replace("%button_outline_border%", hex(buttonOutlineBorder))
|
||||
.replace("%field_background%", hex(fieldBackground))
|
||||
.replace("%field_border%", hex(fieldBorder))
|
||||
.replace("%text_primary%", hex(textPrimary));
|
||||
}
|
||||
|
||||
public static void load() {
|
||||
loadedCSS = readCSS("vt_ui_accent.css");
|
||||
loadedCSSAmoled = readCSS("vt_ui_oled.css");
|
||||
@@ -39,6 +57,8 @@ public class WebViewColoringUtils {
|
||||
}
|
||||
|
||||
public static void inject(WebView webView, String str) {
|
||||
webView.loadUrl("javascript:(function() {let parent = document.head || document.documentElement; let style = document.getElementById('custom-style'); if (!style) {style = parent.appendChild(document.createElement('style')); style.id = 'custom-style';} style.innerText = window.atob('" + str + "');})()");
|
||||
String injectOwnStyles = "javascript:(function() {let parent = document.head || document.documentElement; let style = document.getElementById('custom-style'); if (!style) {style = parent.appendChild(document.createElement('style')); style.id = 'custom-style';} style.innerText = window.atob('%s');})()";
|
||||
String jsStyleInjector = String.format(injectOwnStyles, str);
|
||||
webView.evaluateJavascript(jsStyleInjector, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.lite.utils.AccountManagerUtils;
|
||||
import ru.vtosters.sponsorpost.internal.VotesPreferences;
|
||||
import ru.vtosters.sponsorpost.utils.FiltersPreferences;
|
||||
import ru.vtosters.sponsorpost.utils.PostsPreferences;
|
||||
|
||||
@@ -185,7 +186,7 @@ public class NewsFeedFiltersUtils {
|
||||
return json;
|
||||
}
|
||||
|
||||
private static boolean needToSave(JSONObject post, String source, boolean needToShowToast) throws JSONException {
|
||||
private static boolean needToSave(JSONObject post, String source, boolean needToNotifyBlock) throws JSONException {
|
||||
String type = post.optString("type");
|
||||
|
||||
if (isAds(post, type)) {
|
||||
@@ -198,58 +199,84 @@ public class NewsFeedFiltersUtils {
|
||||
|| type.endsWith("playlists")
|
||||
|| type.endsWith("groups")))) {
|
||||
|
||||
logRemovedPost(post, source, "authors", needToShowToast);
|
||||
logRemovedPost(post, source, "authors", needToNotifyBlock);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (postsrecomm() && (type.equals("inline_user_rec") || type.equals("live_recommended"))) {
|
||||
logRemovedPost(post, source, "postsrecomm", needToShowToast);
|
||||
logRemovedPost(post, source, "postsrecomm", needToNotifyBlock);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (friendsrecomm() && (type.equals("user_rec") || type.equals("friends_recomm"))) {
|
||||
logRemovedPost(post, source, "friendsrecomm", needToShowToast);
|
||||
logRemovedPost(post, source, "friendsrecomm", needToNotifyBlock);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (adsgroup() && post.optInt("marked_as_ads") == 1 && !isWhitelistedAd(post)) {
|
||||
logRemovedPost(post, source, "marked_as_ads", needToShowToast);
|
||||
return false;
|
||||
if (adsgroup() && post.optInt("marked_as_ads") == 1 && !post.optBoolean("sponsorpost") && !isWhitelistedAd(post)) {
|
||||
logRemovedPost(post, source, "marked_as_ads", needToNotifyBlock);
|
||||
return needToNotifyBlock;
|
||||
}
|
||||
|
||||
if (PostsPreferences.isPostAd(getOwnerId(post), getPostId(post)) && !isWhitelistedAd(post)) {
|
||||
logRemovedPost(post, source, "sponsorpost", needToShowToast);
|
||||
return false;
|
||||
if (PostsPreferences.isPostAd(getOwnerId(post), getPostId(post)) && !post.optBoolean("sponsorpost") && !isWhitelistedAd(post)) {
|
||||
logRemovedPost(post, source, "sponsorpost", needToNotifyBlock);
|
||||
PostsPreferences.incrementNumBlockedPosts();
|
||||
|
||||
if (PostsPreferences.isEnabledMarking() || needToNotifyBlock) {
|
||||
addSponsorPostMark(post);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (sponsorFilters(post.optString("text")) && !isWhitelistedFilters(post)) {
|
||||
logRemovedPost(post, source, "sponsorpost filter", needToShowToast);
|
||||
return false;
|
||||
if (VotesPreferences.isPostAd(getOwnerId(post), getPostId(post)) && !post.optBoolean("sponsorpost") && !isWhitelistedAd(post)) {
|
||||
logRemovedPost(post, source, "sponsorpost vote base", needToNotifyBlock);
|
||||
addSponsorPostMark(post);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (sponsorFilters(post.optString("text")) && !post.optBoolean("sponsorpost") && !isWhitelistedFilters(post)) {
|
||||
logRemovedPost(post, source, "sponsorpost filter", needToNotifyBlock);
|
||||
FiltersPreferences.incrementNumBlockedPosts();
|
||||
|
||||
if (FiltersPreferences.isEnabledMarking() || needToNotifyBlock) {
|
||||
addSponsorPostMark(post);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (checkCopyright(post)) {
|
||||
logRemovedPost(post, source, "copyright filters", needToShowToast);
|
||||
return false;
|
||||
logRemovedPost(post, source, "copyright filters", needToNotifyBlock);
|
||||
FiltersPreferences.incrementNumBlockedPosts();
|
||||
return needToNotifyBlock;
|
||||
}
|
||||
|
||||
if (checkCaption(post)) {
|
||||
logRemovedPost(post, source, "caption filters", needToShowToast);
|
||||
return false;
|
||||
logRemovedPost(post, source, "caption filters", needToNotifyBlock);
|
||||
return needToNotifyBlock;
|
||||
}
|
||||
|
||||
if (hasMiniAppAds(post) && !isWhitelistedFilters(post)) {
|
||||
logRemovedPost(post, source, "miniapps ban", needToShowToast);
|
||||
return false;
|
||||
logRemovedPost(post, source, "miniapps ban", needToNotifyBlock);
|
||||
return needToNotifyBlock;
|
||||
}
|
||||
|
||||
if (NewsFeedFiltersUtils.injectFiltersReposts(post) && !isWhitelistedFilters(post)) {
|
||||
logRemovedPost(post, source, "repost ad", needToShowToast);
|
||||
return false;
|
||||
logRemovedPost(post, source, "repost ad", needToNotifyBlock);
|
||||
return needToNotifyBlock;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void addSponsorPostMark(JSONObject post) throws JSONException {
|
||||
post.putOpt("marked_as_ads", 1);
|
||||
post.putOpt("sponsorpost", true);
|
||||
}
|
||||
|
||||
public static JSONArray feedInject(JSONArray items, boolean needToShowToast) {
|
||||
if (items.length() == 0) return items;
|
||||
|
||||
@@ -276,24 +303,26 @@ public class NewsFeedFiltersUtils {
|
||||
|
||||
public static boolean sponsorFilters(String text) {
|
||||
String textInLowerCase = text.toLowerCase();
|
||||
Set<String> list = filters.stream()
|
||||
.filter(adword -> !adword.isEmpty())
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if (!list.isEmpty()) {
|
||||
return list.stream().anyMatch(adword -> {
|
||||
if (textInLowerCase.contains(adword.toLowerCase())) {
|
||||
return filters.stream()
|
||||
.map(String::toLowerCase)
|
||||
.filter(adword -> !adword.isEmpty() && textInLowerCase.contains(adword))
|
||||
.peek(adword -> {
|
||||
if (dev()) {
|
||||
Log.d("NewsfeedAdBlockV2", text);
|
||||
Log.d("NewsfeedAdBlockV2", "Block word: " + adword);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
})
|
||||
.findAny()
|
||||
.isPresent();
|
||||
}
|
||||
|
||||
return false;
|
||||
public static String sponsorFiltersBanWord(String text) {
|
||||
String textInLowerCase = text.toLowerCase();
|
||||
return filters.stream()
|
||||
.map(String::toLowerCase)
|
||||
.filter(adword -> !adword.isEmpty() && textInLowerCase.contains(adword))
|
||||
.findAny()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package ru.vtosters.sponsorpost.internal;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class Native {
|
||||
public static boolean canVote;
|
||||
|
||||
public static boolean canVote() {
|
||||
return canVote;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static native String sig();
|
||||
|
||||
@Nullable
|
||||
public static native String time();
|
||||
|
||||
@Nullable
|
||||
public static native String pkey();
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package ru.vtosters.sponsorpost.internal;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class VotesPreferences {
|
||||
private static final SharedPreferences preferences;
|
||||
|
||||
static {
|
||||
preferences = getPreferences();
|
||||
}
|
||||
|
||||
private static SharedPreferences getPreferences() {
|
||||
return AndroidUtils.getGlobalContext().getSharedPreferences("ru.vtosters.sponsorpost.votes.prefs", Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
public static boolean isEnabled() {
|
||||
return preferences.getBoolean("sponsortesting", false);
|
||||
}
|
||||
|
||||
public static void setEnabled(boolean status) {
|
||||
preferences.edit().putBoolean("sponsortesting", status).apply();
|
||||
}
|
||||
|
||||
public static void setUserToken(String token) {
|
||||
preferences.edit()
|
||||
.putString("token", token)
|
||||
.apply();
|
||||
}
|
||||
|
||||
public static void remUserToken() {
|
||||
preferences.edit()
|
||||
.remove("token")
|
||||
.apply();
|
||||
}
|
||||
|
||||
public static String getUserToken() {
|
||||
return preferences.getString("token", "");
|
||||
}
|
||||
|
||||
public static void savePosts(List<String> posts) {
|
||||
preferences.edit()
|
||||
.putStringSet("posts", new HashSet<>(posts))
|
||||
.apply();
|
||||
}
|
||||
|
||||
public static void saveGroupsIds(List<String> ids) {
|
||||
preferences.edit()
|
||||
.putStringSet("groupIds", new HashSet<>(ids))
|
||||
.apply();
|
||||
}
|
||||
|
||||
public static void saveGroupSpecifiedPosts(List<String> postsIds, Long ownerId) {
|
||||
Set<String> stringSet = postsIds.stream()
|
||||
.map(post -> ownerId + "_" + post)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
preferences.edit()
|
||||
.putStringSet(ownerId + "_posts", stringSet)
|
||||
.apply();
|
||||
}
|
||||
|
||||
public static void saveAdPostInfo(long ownerId, long postId) {
|
||||
Set<String> currentStringSet = preferences.getStringSet("posts", new HashSet<>());
|
||||
Set<String> newStringSet = new HashSet<>(currentStringSet);
|
||||
|
||||
newStringSet.add(ownerId + "_" + postId);
|
||||
|
||||
Log.d("SponsorPost", ownerId + "_" + postId);
|
||||
|
||||
preferences.edit()
|
||||
.putStringSet("posts", newStringSet)
|
||||
.apply();
|
||||
}
|
||||
|
||||
public static boolean isGroupAd(long ownerId) {
|
||||
Set<String> isGroupAd = preferences.getStringSet("groupIds", new HashSet<>());
|
||||
|
||||
if (!isGroupAd.isEmpty() && isEnabled()) {
|
||||
return isGroupAd.contains(Long.toString(ownerId));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isPostAd(long ownerId, long postId) {
|
||||
if (isEnabled() && isGroupAd(ownerId)) {
|
||||
Set<String> hasSpecifiedGroupPosts = preferences.getStringSet(ownerId + "_posts", new HashSet<>());
|
||||
Set<String> hasPost = preferences.getStringSet("posts", new HashSet<>());
|
||||
|
||||
return hasPost.contains(ownerId + "_" + postId) || hasSpecifiedGroupPosts.contains(ownerId + "_" + postId);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
package ru.vtosters.sponsorpost.internal;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import ru.vtosters.sponsorpost.utils.ApiUtils;
|
||||
import ru.vtosters.sponsorpost.utils.GzipDecompressor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class VotesService {
|
||||
private static final OkHttpClient client = new OkHttpClient();
|
||||
private static final String apiPath = ApiUtils.getURL() + "/votes";
|
||||
private static final String userPath = ApiUtils.getURL() + "/users";
|
||||
|
||||
public static Map<String, List<String>> getPosts(Long date) {
|
||||
String getFromDate = date > 0 ? ("&date=" + date) : "";
|
||||
Request request = new Request.a()
|
||||
.b(apiPath + "/getAllPostIds" + "?needProd=true" + getFromDate)
|
||||
.a("Content-Type", "application/json")
|
||||
.a("Accept-Encoding", "gzip")
|
||||
.a();
|
||||
try (Response response = client.a(request).execute()) {
|
||||
if (response.h()) {
|
||||
return parseJSON(new JSONObject(GzipDecompressor.decompressResponse(response)));
|
||||
} else {
|
||||
throw new RuntimeException("Failed to get posts: " + response.l());
|
||||
}
|
||||
} catch (IOException | JSONException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<String, List<String>> parseJSON(JSONObject object) throws JSONException {
|
||||
String PROD_KEY = "prod";
|
||||
String VOTE_KEY = "vote";
|
||||
|
||||
JSONArray prodBase = object.getJSONArray(PROD_KEY);
|
||||
JSONArray testBase = object.getJSONArray(VOTE_KEY);
|
||||
|
||||
if (prodBase.length() == 0 && testBase.length() == 0) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
List<String> prodList = IntStream.range(0, prodBase.length())
|
||||
.mapToObj(prodBase::optString)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<String> voteList = IntStream.range(0, testBase.length())
|
||||
.mapToObj(testBase::optString)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return Map.of(PROD_KEY, prodList, VOTE_KEY, voteList);
|
||||
}
|
||||
|
||||
public static Map<String, List<String>> getPostIdsByOwnerId(Long ownerId, Long date) {
|
||||
String getFromDate = date > 0 ? ("&date=" + date) : "";
|
||||
String requestUrl = apiPath + "/getPostIdsByOwnerId" + "?ownerId=" + ownerId + getFromDate + "&needProd=true";
|
||||
Request request = new Request.a()
|
||||
.b(requestUrl)
|
||||
.a("Content-Type", "application/json")
|
||||
.a("Accept-Encoding", "gzip")
|
||||
.a();
|
||||
try (Response response = client.a(request).execute()) {
|
||||
if (response.h()) {
|
||||
return parseJSON(new JSONObject(GzipDecompressor.decompressResponse(response)));
|
||||
} else {
|
||||
throw new RuntimeException("Failed to get postIdsByOwnerId: " + response.l());
|
||||
}
|
||||
} catch (IOException | JSONException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Map<String, List<String>> getOwnerIds() {
|
||||
String requestUrl = apiPath + "/getOwnerIds" + "?needProd=true";
|
||||
Request request = new Request.a()
|
||||
.b(requestUrl)
|
||||
.a("Content-Type", "application/json")
|
||||
.a("Accept-Encoding", "gzip")
|
||||
.a();
|
||||
try (Response response = client.a(request).execute()) {
|
||||
if (response.h()) {
|
||||
return parseJSON(new JSONObject(GzipDecompressor.decompressResponse(response)));
|
||||
} else {
|
||||
throw new RuntimeException("Failed to get ownersIds: " + response.l());
|
||||
}
|
||||
} catch (IOException | JSONException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static JSONObject ratePost(int ownerId, int postId, int date, boolean isAd) {
|
||||
String token = VotesPreferences.getUserToken() == null || VotesPreferences.getUserToken().isEmpty() ? getVoteToken() : VotesPreferences.getUserToken();
|
||||
String requestUrl = apiPath + (isAd ? "/dislike" : "/like") + "?ownerId=" + ownerId + "&postId=" + postId+ "&postDate=" + date + "&token=" + Uri.encode(token);
|
||||
Request request = new Request.a()
|
||||
.b(requestUrl)
|
||||
.a("Content-Type", "application/json")
|
||||
.a();
|
||||
try (Response response = client.a(request).execute()) {
|
||||
return new JSONObject(GzipDecompressor.decompressResponse(response));
|
||||
} catch (IOException | JSONException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getVoteToken() {
|
||||
String requestUrl = userPath + "/getUserToken" + "?private_key=" + Uri.encode(Native.pkey());
|
||||
Request request = new Request.a()
|
||||
.b(requestUrl)
|
||||
.a("Content-Type", "application/json")
|
||||
.a("Timestamp", Native.time())
|
||||
.a("Signature", Native.sig())
|
||||
.a();
|
||||
try (Response response = client.a(request).execute()) {
|
||||
String userToken = new JSONObject(GzipDecompressor.decompressResponse(response)).getString("token");
|
||||
VotesPreferences.setUserToken(userToken);
|
||||
return userToken;
|
||||
} catch (IOException | JSONException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isPostAd(long ownerId, long postId) {
|
||||
String requestUrl = apiPath + "/isPostAdvert?post=" + ownerId + "_" + postId + "&needProd=true";
|
||||
Request request = new Request.a()
|
||||
.b(requestUrl)
|
||||
.a("Content-Type", "application/json")
|
||||
.a();
|
||||
try (Response response = client.a(request).execute()) {
|
||||
if (response.h()) {
|
||||
return Boolean.parseBoolean(GzipDecompressor.decompressResponse(response));
|
||||
} else {
|
||||
throw new RuntimeException("Failed to check post for ad status: " + response.l());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,20 +42,7 @@ public class FilterService {
|
||||
try (Response response = client.a(request).execute()) {
|
||||
// Check if the response is successful
|
||||
if (response.h()) {
|
||||
// Determine the response encoding
|
||||
String encoding = response.a("Content-Encoding");
|
||||
String resp;
|
||||
|
||||
if (encoding != null && encoding.equals("gzip")) {
|
||||
// Decompress the response body
|
||||
resp = GzipDecompressor.decompress(response.a().b());
|
||||
} else {
|
||||
// Retrieve the response body directly
|
||||
resp = response.a().g();
|
||||
}
|
||||
|
||||
// Parse the response body as a JSONArray and extract filter objects
|
||||
return parseJSON(new JSONArray(resp));
|
||||
return parseJSON(new JSONArray(GzipDecompressor.decompressResponse(response)));
|
||||
} else {
|
||||
if (!FiltersPreferences.getAllFilterIds().isEmpty()) {
|
||||
return FiltersPreferences.getAllDownloadedFilters(); // check for offline server to get local filters
|
||||
@@ -75,11 +62,12 @@ public class FilterService {
|
||||
public static Set<String> downloadFilter(String link) {
|
||||
Request request = new Request.a()
|
||||
.b(link)
|
||||
.a("Accept-Encoding", "gzip")
|
||||
.a();
|
||||
|
||||
try (Response response = client.a(request).execute()) {
|
||||
if (response.h()) {
|
||||
return stringToSet(response.a().g());
|
||||
return stringToSet(GzipDecompressor.decompressResponse(response));
|
||||
} else {
|
||||
throw new RuntimeException("Failed to download filter: " + response.l());
|
||||
}
|
||||
|
||||
@@ -39,17 +39,7 @@ public class PostService {
|
||||
try (Response response = client.a(request).execute()) {
|
||||
// Check if the response is successful
|
||||
if (response.h()) {
|
||||
// Determine the response encoding
|
||||
String encoding = response.a("Content-Encoding");
|
||||
|
||||
// Handle GZIP-compressed responses
|
||||
if (encoding != null && encoding.equals("gzip")) {
|
||||
// Decompress the response body and parse JSON data
|
||||
return parseJSONPosts(new JSONArray(GzipDecompressor.decompress(response.a().b())));
|
||||
} else {
|
||||
// Parse JSON data from the response body
|
||||
return parseJSONPosts(new JSONArray(response.a().g()));
|
||||
}
|
||||
return parseJSONPosts(new JSONArray(GzipDecompressor.decompressResponse(response)));
|
||||
} else {
|
||||
// Handle error response
|
||||
throw new RuntimeException("Failed to get posts: " + response.l());
|
||||
@@ -78,20 +68,7 @@ public class PostService {
|
||||
try (Response response = client.a(request).execute()) {
|
||||
// Check if the response is successful
|
||||
if (response.h()) {
|
||||
// Determine the response encoding
|
||||
String encoding = response.a("Content-Encoding");
|
||||
String resp;
|
||||
|
||||
if (encoding != null && encoding.equals("gzip")) {
|
||||
// Decompress the response body
|
||||
resp = GzipDecompressor.decompress(response.a().b());
|
||||
} else {
|
||||
// Retrieve the response body directly
|
||||
resp = response.a().g();
|
||||
}
|
||||
|
||||
// Extract the boolean value indicating whether the post is an ad
|
||||
return Boolean.parseBoolean(resp);
|
||||
return Boolean.parseBoolean(GzipDecompressor.decompressResponse(response));
|
||||
} else {
|
||||
// Handle error response
|
||||
throw new RuntimeException("Failed to check post for ad status: " + response.l());
|
||||
@@ -101,10 +78,19 @@ public class PostService {
|
||||
}
|
||||
}
|
||||
|
||||
public static List<String> getAllPostsIds() {
|
||||
public static List<String> getAllPostsIds(Long date) {
|
||||
String getFromDate;
|
||||
// Get posts older than the specified date (if positive) or all posts (if zero or negative or empty)
|
||||
if (date > 0) {
|
||||
getFromDate = ("?date=" + date);
|
||||
} else {
|
||||
// No date parameter for retrieving all posts
|
||||
getFromDate = "";
|
||||
}
|
||||
|
||||
// Create a GET request for retrieving all post IDs
|
||||
Request request = new Request.a()
|
||||
.b(apiPath + "/getAllPostIds")
|
||||
.b(apiPath + "/getAllPostIds" + getFromDate)
|
||||
.a("Content-Type", "application/json")
|
||||
.a("Accept-Encoding", "gzip")
|
||||
.a();
|
||||
@@ -112,17 +98,7 @@ public class PostService {
|
||||
try (Response response = client.a(request).execute()) {
|
||||
// Check if the response is successful
|
||||
if (response.h()) {
|
||||
// Determine the response encoding
|
||||
String encoding = response.a("Content-Encoding");
|
||||
|
||||
// Handle GZIP-compressed responses
|
||||
if (encoding != null && encoding.equals("gzip")) {
|
||||
// Decompress the response body and extract the first element as a list of post IDs
|
||||
return new ArrayList<>(Collections.singleton(GzipDecompressor.decompress(response.a().b())));
|
||||
} else {
|
||||
// Extract the first element as a list of post IDs
|
||||
return new ArrayList<>(Collections.singleton(response.a().g()));
|
||||
}
|
||||
return new ArrayList<>(Collections.singleton(GzipDecompressor.decompressResponse(response)));
|
||||
} else {
|
||||
// Handle error response
|
||||
throw new RuntimeException("Failed to get posts IDs: " + response.l());
|
||||
@@ -137,7 +113,7 @@ public class PostService {
|
||||
// Retrieve post IDs for a specific owner and date
|
||||
// If date is positive, get posts older than the specified date
|
||||
// Otherwise, get all posts for the owner
|
||||
String getFromDate = date > 0 ? ("?date=" + date) : "";
|
||||
String getFromDate = date > 0 ? ("&date=" + date) : "";
|
||||
|
||||
// Construct the API request URL
|
||||
String requestUrl = apiPath + "/getPostIdsByOwnerId" + "?ownerId=" + ownerId + getFromDate;
|
||||
@@ -152,20 +128,7 @@ public class PostService {
|
||||
try (Response response = client.a(request).execute()) {
|
||||
// Check if the response is successful
|
||||
if (response.h()) {
|
||||
// Determine the response encoding
|
||||
String encoding = response.a("Content-Encoding");
|
||||
String resp;
|
||||
|
||||
if (encoding != null && encoding.equals("gzip")) {
|
||||
// Decompress the response body
|
||||
resp = GzipDecompressor.decompress(response.a().b());
|
||||
} else {
|
||||
// Retrieve the response body directly
|
||||
resp = response.a().g();
|
||||
}
|
||||
|
||||
// Parse the response body as a JSONArray and extract post IDs
|
||||
return parseJSONIds(new JSONArray(resp));
|
||||
return parseJSONIds(new JSONArray(GzipDecompressor.decompressResponse(response)));
|
||||
} else {
|
||||
// Handle error response
|
||||
throw new RuntimeException("Failed to get postIdsByOwnerId: " + response.l());
|
||||
@@ -192,20 +155,7 @@ public class PostService {
|
||||
try (Response response = client.a(request).execute()) {
|
||||
// Check if the response is successful
|
||||
if (response.h()) {
|
||||
// Determine the response encoding
|
||||
String encoding = response.a("Content-Encoding");
|
||||
String resp;
|
||||
|
||||
if (encoding != null && encoding.equals("gzip")) {
|
||||
// Decompress the response body
|
||||
resp = GzipDecompressor.decompress(response.a().b());
|
||||
} else {
|
||||
// Retrieve the response body directly
|
||||
resp = response.a().g();
|
||||
}
|
||||
|
||||
// Parse the response body as a JSONArray and extract owner IDs
|
||||
return parseJSONIds(new JSONArray(resp));
|
||||
return parseJSONIds(new JSONArray(GzipDecompressor.decompressResponse(response)));
|
||||
} else {
|
||||
// Handle error response
|
||||
throw new RuntimeException("Failed to get ownersIds: " + response.l());
|
||||
|
||||
@@ -31,8 +31,34 @@ public class FiltersPreferences {
|
||||
return AndroidUtils.getGlobalContext().getSharedPreferences("ru.vtosters.sponsorpost.filters.prefs", Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
public static void clearAll() {
|
||||
preferences.edit().clear().apply();
|
||||
public static boolean isEnabledMarking() {
|
||||
return preferences.getBoolean("sponsorpost_filters_marking", false);
|
||||
}
|
||||
|
||||
public static void setEnabledMarking(boolean status) {
|
||||
preferences.edit().putBoolean("sponsorpost_filters_marking", status).apply();
|
||||
}
|
||||
|
||||
public static int getNumBlockedPosts() {
|
||||
return preferences.getInt("numBlockedPosts", 0);
|
||||
}
|
||||
|
||||
public static void incrementNumBlockedPosts() {
|
||||
preferences.edit().putInt("numBlockedPosts", getNumBlockedPosts() + 1).apply();
|
||||
}
|
||||
|
||||
public static void dropNumBlockedPosts() {
|
||||
preferences.edit().putInt("numBlockedPosts", 0).apply();
|
||||
}
|
||||
|
||||
public static void clearAllCachedLists() {
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
|
||||
preferences.getAll().keySet().stream()
|
||||
.filter(key -> key.endsWith(":" + PREF_KEY_LIST))
|
||||
.forEach(editor::remove);
|
||||
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static boolean getSavedKeyValue(int id) {
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package ru.vtosters.sponsorpost.utils;
|
||||
|
||||
import android.util.Log;
|
||||
import okhttp3.Response;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
@@ -26,4 +29,17 @@ public class GzipDecompressor {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static String decompressResponse(Response response) throws IOException {
|
||||
String encoding = response.a("Content-Encoding");
|
||||
if (encoding != null && encoding.equals("gzip")) {
|
||||
// Decompress the response body
|
||||
Log.d("GZIP", "true, link " + response.o().g());
|
||||
return GzipDecompressor.decompress(response.a().b());
|
||||
} else {
|
||||
// Retrieve the response body directly
|
||||
Log.d("GZIP", "false, link " + response.o().g());
|
||||
return response.a().g();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,14 @@ public class PostsPreferences {
|
||||
preferences.edit().putBoolean("sponsorpost", status).apply();
|
||||
}
|
||||
|
||||
public static boolean isEnabledMarking() {
|
||||
return preferences.getBoolean("sponsorpost_marking", false);
|
||||
}
|
||||
|
||||
public static void setEnabledMarking(boolean status) {
|
||||
preferences.edit().putBoolean("sponsorpost_marking", status).apply();
|
||||
}
|
||||
|
||||
public static void savePosts(List<Post> posts) {
|
||||
Set<String> stringSet = posts.stream()
|
||||
.map(post -> post.getOwnerId() + "_" + post.getPostId())
|
||||
@@ -40,7 +48,13 @@ public class PostsPreferences {
|
||||
.apply();
|
||||
}
|
||||
|
||||
public static void saveGroupSpecifiedPosts(List<Long> postsIds, Long ownerId) {
|
||||
public static void savePostsStr(List<String> posts) {
|
||||
preferences.edit()
|
||||
.putStringSet("posts", new HashSet<>(posts))
|
||||
.apply();
|
||||
}
|
||||
|
||||
public static void saveGroupSpecifiedPosts(List<?> postsIds, Long ownerId) {
|
||||
Set<String> stringSet = postsIds.stream()
|
||||
.map(post -> ownerId + "_" + post)
|
||||
.collect(Collectors.toSet());
|
||||
@@ -50,7 +64,7 @@ public class PostsPreferences {
|
||||
.apply();
|
||||
}
|
||||
|
||||
public static void saveGroupsIds(List<Long> ids) {
|
||||
public static void saveGroupsIds(List<?> ids) {
|
||||
Set<String> stringSet = ids.stream().map(String::valueOf).collect(Collectors.toSet());
|
||||
|
||||
preferences.edit()
|
||||
@@ -81,6 +95,18 @@ public class PostsPreferences {
|
||||
}
|
||||
}
|
||||
|
||||
public static int getNumBlockedPosts() {
|
||||
return preferences.getInt("numBlockedPosts", 0);
|
||||
}
|
||||
|
||||
public static void incrementNumBlockedPosts() {
|
||||
preferences.edit().putInt("numBlockedPosts", getNumBlockedPosts() + 1).apply();
|
||||
}
|
||||
|
||||
public static void dropNumBlockedPosts() {
|
||||
preferences.edit().putInt("numBlockedPosts", 0).apply();
|
||||
}
|
||||
|
||||
public static boolean isPostAd(long ownerId, long postId) {
|
||||
if (isEnabled() && isGroupAd(ownerId)) {
|
||||
Set<String> hasSpecifiedGroupPosts = preferences.getStringSet(ownerId + "_posts", new HashSet<>());
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
package ru.vtosters.sponsorpost.utils;
|
||||
|
||||
import ru.vtosters.hooks.other.Preferences;
|
||||
import ru.vtosters.lite.utils.NetworkUtils;
|
||||
import ru.vtosters.lite.utils.newsfeed.NewsFeedFiltersUtils;
|
||||
import ru.vtosters.sponsorpost.data.Filter;
|
||||
import ru.vtosters.sponsorpost.data.Post;
|
||||
import ru.vtosters.sponsorpost.internal.VotesPreferences;
|
||||
import ru.vtosters.sponsorpost.internal.VotesService;
|
||||
import ru.vtosters.sponsorpost.services.FilterService;
|
||||
import ru.vtosters.sponsorpost.services.PostService;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -23,7 +26,7 @@ public class Updates {
|
||||
List<Filter> localFilters = FiltersPreferences.getAllDownloadedFilters();
|
||||
|
||||
if (!filters.isEmpty()) {
|
||||
FiltersPreferences.clearAll(); // removes deleted filters from server
|
||||
FiltersPreferences.clearAllCachedLists(); // removes deleted filters from server and cache
|
||||
|
||||
for (Filter filter : filters) {
|
||||
Filter localFilter = findLocalFilterById(localFilters, filter.getId());
|
||||
@@ -39,6 +42,8 @@ public class Updates {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NewsFeedFiltersUtils.updateFilters();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,16 +61,31 @@ public class Updates {
|
||||
long weekAgo = currentTime - TimeUnit.DAYS.toMillis(7);
|
||||
|
||||
if (PostsPreferences.isEnabled() && NetworkUtils.isNetworkConnected()) {
|
||||
List<Post> posts = PostService.getPosts(weekAgo);
|
||||
List<Long> groupIds = PostService.getOwnerIds();
|
||||
if (VotesPreferences.isEnabled()) {
|
||||
Map<String, List<String>> posts = VotesService.getPosts(weekAgo / 1000);
|
||||
Map<String, List<String>> groupIds = VotesService.getOwnerIds();
|
||||
|
||||
if (!posts.isEmpty()) {
|
||||
PostsPreferences.savePosts(posts);
|
||||
}
|
||||
if (!posts.isEmpty()) {
|
||||
PostsPreferences.savePostsStr(posts.get("prod"));
|
||||
VotesPreferences.savePosts(posts.get("vote"));
|
||||
}
|
||||
|
||||
if (!groupIds.isEmpty()) {
|
||||
PostsPreferences.saveGroupsIds(groupIds);
|
||||
if (!groupIds.isEmpty()) {
|
||||
PostsPreferences.saveGroupsIds(groupIds.get("prod"));
|
||||
VotesPreferences.saveGroupsIds(groupIds.get("vote"));
|
||||
}
|
||||
} else {
|
||||
List<String> posts = PostService.getAllPostsIds(weekAgo / 1000);
|
||||
List<Long> groupIds = PostService.getOwnerIds();
|
||||
|
||||
if (!posts.isEmpty()) {
|
||||
PostsPreferences.savePostsStr(posts);
|
||||
}
|
||||
|
||||
if (!groupIds.isEmpty()) {
|
||||
PostsPreferences.saveGroupsIds(groupIds);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2055,13 +2055,20 @@
|
||||
android:name="com.google.android.gms.auth.api.signin.RevocationBoundService"
|
||||
android:exported="true"
|
||||
android:permission="com.google.android.gms.auth.api.signin.permission.REVOCATION_NOTIFICATION" />
|
||||
|
||||
<service
|
||||
android:name="com.google.firebase.components.ComponentDiscoveryService"
|
||||
android:directBootAware="true"
|
||||
android:exported="false">
|
||||
<meta-data
|
||||
android:name="com.google.firebase.components:com.google.firebase.remoteconfig.RemoteConfigRegistrar"
|
||||
android:value="com.google.firebase.components.ComponentRegistrar" />
|
||||
<meta-data
|
||||
android:name="com.google.firebase.components:com.google.firebase.iid.Registrar"
|
||||
android:value="com.google.firebase.components.ComponentRegistrar" />
|
||||
<meta-data
|
||||
android:name="com.google.firebase.components:com.google.firebase.abt.component.AbtRegistrar"
|
||||
android:value="com.google.firebase.components.ComponentRegistrar" />
|
||||
</service>
|
||||
<service
|
||||
android:name="com.google.firebase.messaging.FirebaseMessagingService"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/iclauncher" />
|
||||
<foreground android:drawable="@mipmap/vt_adaptive_launcher_foneground" />
|
||||
<foreground android:drawable="@mipmap/vt_adaptive_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/vt_mono" />
|
||||
</adaptive-icon>
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/iclauncher" />
|
||||
<foreground android:drawable="@mipmap/vt_adaptive_launcher_foneground" />
|
||||
<foreground android:drawable="@mipmap/vt_adaptive_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/vt_mono" />
|
||||
</adaptive-icon>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 6.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
@@ -12980,7 +12980,7 @@
|
||||
<public type="mipmap" name="ic_launcher_shine" id="0x7f0f005d" />
|
||||
<public type="mipmap" name="ic_launcher_shine_background" id="0x7f0f005e" />
|
||||
<public type="mipmap" name="ic_launcher_shine_foreground" id="0x7f0f005f" />
|
||||
<public type="mipmap" name="vt_adaptive_launcher_foneground" id="0x7f0f0043" />
|
||||
<public type="mipmap" name="vt_adaptive_launcher_foreground" id="0x7f0f0043" />
|
||||
<public type="mipmap" name="vt_launcher_round" id="0x7f0f0046" />
|
||||
<public type="mipmap" name="ic_logo_facebook_28" id="0x7f0f0003" />
|
||||
<public type="mipmap" name="ic_logo_google_28" id="0x7f0f0004" />
|
||||
|
||||
@@ -1308,11 +1308,11 @@ and organize it with the help of tags"</string>
|
||||
<string name="goods_picker_text_no_goods">Add products to favorites, and attach them to photos, videos and stories!</string>
|
||||
<string name="goods_picker_title_no_goods">Product list empty</string>
|
||||
<string name="goods_picker_title_photo">Tag product</string>
|
||||
<string name="google_api_key">AIzaSyBf1M4--c04jJtKSWI2w5DgUTst1_V20D4</string>
|
||||
<string name="google_api_key">AIzaSyCL17U2Q5i1NVwIcXgMOZMidSRFHyGYgwM</string>
|
||||
<string name="google_app_id">1:841415684880:android:632f429381141121</string>
|
||||
<string name="google_assistant_verification_channel_name">Assistant verifier</string>
|
||||
<string name="google_assistant_verification_notification_title">Google Assistant sending message</string>
|
||||
<string name="google_crash_reporting_api_key">AIzaSyBf1M4--c04jJtKSWI2w5DgUTst1_V20D4</string>
|
||||
<string name="google_crash_reporting_api_key"></string>
|
||||
<string name="google_storage_bucket">api-project-841415684880.appspot.com</string>
|
||||
<string name="group">Community</string>
|
||||
<string name="group_accept_member">Accept</string>
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<network-security-config>
|
||||
<debug-overrides>
|
||||
<trust-anchors>
|
||||
<certificates src="system"/>
|
||||
<certificates src="user"/>
|
||||
</trust-anchors>
|
||||
<trust-anchors>
|
||||
<!-- Trust user added CAs while debuggable only -->
|
||||
<certificates src="user" />
|
||||
<certificates src="system" />
|
||||
</trust-anchors>
|
||||
</debug-overrides>
|
||||
</network-security-config>
|
||||
|
||||
<base-config cleartextTrafficPermitted="true">
|
||||
<trust-anchors>
|
||||
<certificates src="system" />
|
||||
<certificates src="user" />
|
||||
</trust-anchors>
|
||||
</base-config>
|
||||
</network-security-config>
|
||||
@@ -2,7 +2,6 @@
|
||||
<network-security-config>
|
||||
<debug-overrides>
|
||||
<trust-anchors>
|
||||
<!-- Trust user added CAs while debuggable only -->
|
||||
<certificates src="user"/>
|
||||
<certificates src="system"/>
|
||||
</trust-anchors>
|
||||
@@ -13,18 +12,14 @@
|
||||
</trust-anchors>
|
||||
</base-config>
|
||||
<domain-config>
|
||||
<!-- Make sure your URL Server here -->
|
||||
<domain includeSubdomains="true">vk.com</domain>
|
||||
<trust-anchors>
|
||||
<certificates src="user"/>
|
||||
<certificates src="system"/>
|
||||
</trust-anchors>
|
||||
</domain-config>
|
||||
<domain-config>
|
||||
<!-- Make sure your URL Server here -->
|
||||
<domain includeSubdomains="true">api.vk.com</domain>
|
||||
<trust-anchors>
|
||||
<certificates src="user"/>
|
||||
<certificates src="system"/>
|
||||
</trust-anchors>
|
||||
</domain-config>
|
||||
|
||||
@@ -2,52 +2,56 @@
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<PreferenceCategory android:title="@string/group_info">
|
||||
<Preference
|
||||
android:key="phone"
|
||||
android:persistent="false"
|
||||
android:title="@string/phone_number"/>
|
||||
android:key="phone"
|
||||
android:persistent="false"
|
||||
android:title="@string/phone_number" />
|
||||
<Preference
|
||||
android:key="email"
|
||||
android:persistent="false"
|
||||
android:title="@string/email"/>
|
||||
android:key="email"
|
||||
android:persistent="false"
|
||||
android:title="@string/email" />
|
||||
<Preference
|
||||
android:key="changePassword"
|
||||
android:persistent="false"
|
||||
android:title="@string/change_password"/>
|
||||
android:key="changePassword"
|
||||
android:persistent="false"
|
||||
android:title="@string/change_password" />
|
||||
<Preference
|
||||
android:key="domain"
|
||||
android:persistent="false"
|
||||
android:title="@string/page_address"/>
|
||||
<com.vtosters.lite.ui.MaterialSectionDividerPreference/>
|
||||
android:key="domain"
|
||||
android:persistent="false"
|
||||
android:title="@string/page_address" />
|
||||
<com.vtosters.lite.ui.MaterialSectionDividerPreference />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/sett_posts">
|
||||
<com.vtosters.lite.ui.SummaryListPreference
|
||||
android:entries="@array/sett_posts_default_items"
|
||||
android:entryValues="@array/on_off"
|
||||
android:key="onlyMyPosts"
|
||||
android:title="@string/sett_posts_default"/>
|
||||
android:entries="@array/sett_posts_default_items"
|
||||
android:entryValues="@array/on_off"
|
||||
android:key="onlyMyPosts"
|
||||
android:title="@string/sett_posts_default" />
|
||||
<com.vtosters.lite.ui.MaterialSwitchPreference
|
||||
android:key="enableComments"
|
||||
android:persistent="false"
|
||||
android:title="@string/sett_enable_comments"/>
|
||||
<com.vtosters.lite.ui.MaterialSectionDividerPreference/>
|
||||
android:key="enableComments"
|
||||
android:persistent="false"
|
||||
android:title="@string/sett_enable_comments" />
|
||||
<com.vtosters.lite.ui.MaterialSectionDividerPreference />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/community_comments_settings_block_title">
|
||||
<Preference
|
||||
android:key="community_comments"
|
||||
android:summary=""
|
||||
android:title="@string/community_comments_settings_title_new"/>
|
||||
android:key="community_comments"
|
||||
android:summary=""
|
||||
android:title="@string/community_comments_settings_title_new" />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/account_settings_comments">
|
||||
<Preference
|
||||
android:key="comment_order"
|
||||
android:summary=""
|
||||
android:title="@string/account_settings_comment_order"/>
|
||||
android:key="comment_order"
|
||||
android:summary=""
|
||||
android:title="@string/account_settings_comment_order" />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/sett_other">
|
||||
<Preference
|
||||
android:key="newsBanned"
|
||||
android:summary="@string/sett_news_banned_summary"
|
||||
android:title="@string/sett_news_banned"/>
|
||||
<com.vtosters.lite.ui.MaterialSectionDividerPreference/>
|
||||
android:key="sync"
|
||||
android:summary=""
|
||||
android:title="@string/sett_sync" />
|
||||
<Preference
|
||||
android:key="newsBanned"
|
||||
android:summary="@string/sett_news_banned_summary"
|
||||
android:title="@string/sett_news_banned" />
|
||||
<com.vtosters.lite.ui.MaterialSectionDividerPreference />
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
@@ -2,54 +2,58 @@
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<PreferenceCategory android:title="@string/group_info">
|
||||
<Preference
|
||||
android:key="phone"
|
||||
android:layout="@layout/preference_with_value"
|
||||
android:persistent="false"
|
||||
android:title="@string/phone_number"/>
|
||||
android:key="phone"
|
||||
android:layout="@layout/preference_with_value"
|
||||
android:persistent="false"
|
||||
android:title="@string/phone_number" />
|
||||
<Preference
|
||||
android:key="email"
|
||||
android:layout="@layout/preference_with_value"
|
||||
android:persistent="false"
|
||||
android:title="@string/email"/>
|
||||
android:key="email"
|
||||
android:layout="@layout/preference_with_value"
|
||||
android:persistent="false"
|
||||
android:title="@string/email" />
|
||||
<Preference
|
||||
android:key="changePassword"
|
||||
android:layout="@layout/preference_with_value"
|
||||
android:persistent="false"
|
||||
android:title="@string/change_password"/>
|
||||
android:key="changePassword"
|
||||
android:layout="@layout/preference_with_value"
|
||||
android:persistent="false"
|
||||
android:title="@string/change_password" />
|
||||
<Preference
|
||||
android:key="domain"
|
||||
android:layout="@layout/preference_with_value"
|
||||
android:persistent="false"
|
||||
android:title="@string/page_address"/>
|
||||
android:key="domain"
|
||||
android:layout="@layout/preference_with_value"
|
||||
android:persistent="false"
|
||||
android:title="@string/page_address" />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/sett_posts">
|
||||
<com.vtosters.lite.ui.SummaryListPreference
|
||||
android:entries="@array/sett_posts_default_items"
|
||||
android:entryValues="@array/on_off"
|
||||
android:key="onlyMyPosts"
|
||||
android:layout="@layout/preference_with_value"
|
||||
android:title="@string/sett_posts_default"/>
|
||||
android:entries="@array/sett_posts_default_items"
|
||||
android:entryValues="@array/on_off"
|
||||
android:key="onlyMyPosts"
|
||||
android:layout="@layout/preference_with_value"
|
||||
android:title="@string/sett_posts_default" />
|
||||
<com.vtosters.lite.ui.MaterialSwitchPreference
|
||||
android:key="enableComments"
|
||||
android:persistent="false"
|
||||
android:title="@string/sett_enable_comments"/>
|
||||
android:key="enableComments"
|
||||
android:persistent="false"
|
||||
android:title="@string/sett_enable_comments" />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/community_comments_settings_block_title">
|
||||
<Preference
|
||||
android:key="community_comments"
|
||||
android:summary=""
|
||||
android:title="@string/community_comments_settings_title_new"/>
|
||||
android:key="community_comments"
|
||||
android:summary=""
|
||||
android:title="@string/community_comments_settings_title_new" />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/account_settings_comments">
|
||||
<Preference
|
||||
android:key="comment_order"
|
||||
android:summary=""
|
||||
android:title="@string/account_settings_comment_order"/>
|
||||
android:key="comment_order"
|
||||
android:summary=""
|
||||
android:title="@string/account_settings_comment_order" />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/sett_other">
|
||||
<Preference
|
||||
android:key="newsBanned"
|
||||
android:summary="@string/sett_news_banned_summary"
|
||||
android:title="@string/sett_news_banned"/>
|
||||
android:key="sync"
|
||||
android:summary=""
|
||||
android:title="@string/sett_sync" />
|
||||
<Preference
|
||||
android:key="newsBanned"
|
||||
android:summary="@string/sett_news_banned_summary"
|
||||
android:title="@string/sett_news_banned" />
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
@@ -243,7 +243,7 @@
|
||||
android:key="__dbg_proxy_enable"
|
||||
android:title="@string/debug_proxy_enable_title"/>
|
||||
<com.vtosters.lite.ui.MaterialSwitchPreference
|
||||
android:defaultValue="true"
|
||||
android:defaultValue="false"
|
||||
android:key="__dbg_use_libverify_for_auth"
|
||||
android:title="@string/debug_use_libverify_for_auth_title"/>
|
||||
</PreferenceCategory>
|
||||
|
||||
@@ -1,103 +1,116 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:custom="http://schemas.android.com/apk/res-auto">
|
||||
xmlns:custom="http://schemas.android.com/apk/res-auto">
|
||||
<PreferenceCategory
|
||||
android:key="app"
|
||||
android:title="@string/sett_app">
|
||||
android:key="app"
|
||||
android:title="@string/sett_app">
|
||||
<com.vtosters.lite.ui.SummaryListPreference
|
||||
android:defaultValue="firstname"
|
||||
android:dialogTitle="@string/sett_flist_sort"
|
||||
android:entries="@array/sett_friends_order"
|
||||
android:entryValues="@array/sett_friends_order_v"
|
||||
android:key="friendsOrderNew"
|
||||
android:textColor="?text_secondary"
|
||||
android:title="@string/sett_flist_sort"/>
|
||||
android:defaultValue="firstname"
|
||||
android:dialogTitle="@string/sett_flist_sort"
|
||||
android:entries="@array/sett_friends_order"
|
||||
android:entryValues="@array/sett_friends_order_v"
|
||||
android:key="friendsOrderNew"
|
||||
android:textColor="?text_secondary"
|
||||
android:title="@string/sett_flist_sort" />
|
||||
<com.vtosters.lite.ui.SummaryListPreference
|
||||
android:defaultValue="0"
|
||||
android:dialogTitle="@string/sett_font_size"
|
||||
android:entries="@array/sett_font_size_options"
|
||||
android:entryValues="@array/sett_font_size_values"
|
||||
android:key="fontSize"
|
||||
android:title="@string/sett_font_size"/>
|
||||
android:defaultValue="0"
|
||||
android:dialogTitle="@string/sett_font_size"
|
||||
android:entries="@array/sett_font_size_options"
|
||||
android:entryValues="@array/sett_font_size_values"
|
||||
android:key="fontSize"
|
||||
android:title="@string/sett_font_size" />
|
||||
<com.vtosters.lite.ui.MaterialSwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="sendByEnter"
|
||||
android:summary="@string/sett_send_by_enter_summary"
|
||||
android:title="@string/sett_send_by_enter"/>
|
||||
android:defaultValue="false"
|
||||
android:key="sendByEnter"
|
||||
android:summary="@string/sett_send_by_enter_summary"
|
||||
android:title="@string/sett_send_by_enter" />
|
||||
<com.vtosters.lite.ui.MaterialSwitchPreference
|
||||
android:defaultValue="true"
|
||||
android:key="useChromeCustomTabs"
|
||||
android:summary="@string/sett_chrome_custom_tabs_summary"
|
||||
android:title="@string/sett_chrome_custom_tabs"/>
|
||||
android:defaultValue="true"
|
||||
android:key="useChromeCustomTabs"
|
||||
android:summary="@string/sett_chrome_custom_tabs_summary"
|
||||
android:title="@string/sett_chrome_custom_tabs" />
|
||||
<com.vtosters.lite.ui.MaterialSwitchPreference
|
||||
android:defaultValue="true"
|
||||
android:key="trackInstalledApps"
|
||||
android:summary="@string/sett_mytracker_location_crap_summary"
|
||||
android:title="@string/sett_mytracker_apps"/>
|
||||
android:defaultValue="true"
|
||||
android:key="trackInstalledApps"
|
||||
android:summary="@string/sett_mytracker_location_crap_summary"
|
||||
android:title="@string/sett_mytracker_apps" />
|
||||
<!-- <com.vtosters.lite.ui.MaterialSwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="useProxyServer"
|
||||
android:title="@string/sett_use_proxy"
|
||||
android:visibility="gone" /> -->
|
||||
<com.vtosters.lite.ui.MaterialSwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="isRoamingState"
|
||||
android:summary="@string/sett_roaming_state_submit"
|
||||
android:title="@string/sett_roaming_state"/>
|
||||
<com.vtosters.lite.ui.MaterialSectionDividerPreference/>
|
||||
android:defaultValue="false"
|
||||
android:key="isRoamingState"
|
||||
android:summary="@string/sett_roaming_state_submit"
|
||||
android:title="@string/sett_roaming_state" />
|
||||
<com.vtosters.lite.ui.MaterialSectionDividerPreference />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory
|
||||
android:key="multimedia"
|
||||
android:title="@string/sett_media">
|
||||
android:key="multimedia"
|
||||
android:title="@string/sett_media">
|
||||
<com.vtosters.lite.ui.MaterialSwitchPreference
|
||||
android:defaultValue="true"
|
||||
android:key="saveProcessedImage"
|
||||
android:title="@string/sett_save_processed_image"
|
||||
custom:singleLine="false"/>
|
||||
android:defaultValue="true"
|
||||
android:key="saveProcessedImage"
|
||||
android:title="@string/sett_save_processed_image"
|
||||
custom:singleLine="false" />
|
||||
<com.vtosters.lite.ui.MaterialSwitchPreference
|
||||
android:defaultValue="true"
|
||||
android:key="showMusicSuggestNotification"
|
||||
android:title="@string/sett_show_music_suggestion_notification"
|
||||
custom:singleLine="false"/>
|
||||
android:defaultValue="true"
|
||||
android:key="showMusicSuggestNotification"
|
||||
android:title="@string/sett_show_music_suggestion_notification"
|
||||
custom:singleLine="false" />
|
||||
<com.vtosters.lite.ui.MaterialSwitchPreference
|
||||
android:defaultValue="true"
|
||||
android:key="prefetchAudioMsg"
|
||||
android:title="@string/vkim_settings_prefetch_audiomsg"
|
||||
custom:singleLine="false"/>
|
||||
android:defaultValue="true"
|
||||
android:key="prefetchAudioMsg"
|
||||
android:title="@string/vkim_settings_prefetch_audiomsg"
|
||||
custom:singleLine="false" />
|
||||
<ListPreference
|
||||
android:defaultValue="always"
|
||||
android:entries="@array/sett_gif_autoplay_entries"
|
||||
android:entryValues="@array/sett_gif_autoplay_entry_values"
|
||||
android:key="gif_autoplay"
|
||||
android:summary="%s"
|
||||
android:title="@string/sett_gif_autoplay_title"/>
|
||||
android:defaultValue="always"
|
||||
android:entries="@array/sett_gif_autoplay_entries"
|
||||
android:entryValues="@array/sett_gif_autoplay_entry_values"
|
||||
android:key="gif_autoplay"
|
||||
android:summary="%s"
|
||||
android:title="@string/sett_gif_autoplay_title" />
|
||||
<ListPreference
|
||||
android:defaultValue="always"
|
||||
android:entries="@array/sett_gif_autoplay_entries"
|
||||
android:entryValues="@array/sett_gif_autoplay_entry_values"
|
||||
android:key="video_autoplay"
|
||||
android:summary="%s"
|
||||
android:title="@string/sett_video_autoplay_title"/>
|
||||
<com.vtosters.lite.ui.MaterialSectionDividerPreference/>
|
||||
android:defaultValue="always"
|
||||
android:entries="@array/sett_gif_autoplay_entries"
|
||||
android:entryValues="@array/sett_gif_autoplay_entry_values"
|
||||
android:key="video_autoplay"
|
||||
android:summary="%s"
|
||||
android:title="@string/sett_video_autoplay_title" />
|
||||
<com.vtosters.lite.ui.MaterialSectionDividerPreference />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory
|
||||
android:key="cache"
|
||||
android:title="@string/sett_cache">
|
||||
android:key="cache"
|
||||
android:title="@string/sett_cache">
|
||||
<com.vtosters.lite.ui.MaterialSwitchPreference
|
||||
android:defaultValue="true"
|
||||
android:key="enableAudioCache"
|
||||
android:title="@string/sett_enable_audio_cache"/>
|
||||
android:defaultValue="true"
|
||||
android:key="enableAudioCache"
|
||||
android:title="@string/sett_enable_audio_cache" />
|
||||
<com.vtosters.lite.ui.SummaryListPreference
|
||||
android:defaultValue=""
|
||||
android:dialogTitle="@string/sett_cache_location"
|
||||
android:key="audioCacheLocation"
|
||||
android:title="@string/sett_cache_location"/>
|
||||
android:defaultValue=""
|
||||
android:dialogTitle="@string/sett_cache_location"
|
||||
android:key="audioCacheLocation"
|
||||
android:title="@string/sett_cache_location" />
|
||||
<Preference
|
||||
android:key="downloadAudio"
|
||||
android:title="@string/cache_my_music"/>
|
||||
android:key="downloadAudio"
|
||||
android:title="@string/cache_my_music" />
|
||||
<Preference
|
||||
android:key="clearAudioCache"
|
||||
android:summary=""
|
||||
android:title="@string/sett_clear_audio_cache"/>
|
||||
android:key="clearAudioCache"
|
||||
android:summary=""
|
||||
android:title="@string/sett_clear_audio_cache" />
|
||||
<Preference
|
||||
android:enabled="false"
|
||||
android:summary="@string/where_is_cache_settings_summ"
|
||||
android:title="@string/where_is_cache_settings"/>
|
||||
<com.vtosters.lite.ui.MaterialSectionDividerPreference/>
|
||||
android:key="clearImageCache"
|
||||
android:summary=""
|
||||
android:title="@string/sett_clear_img_cache" />
|
||||
<Preference
|
||||
android:key="clearVideoCache"
|
||||
android:summary=""
|
||||
android:title="@string/sett_clear_video_cache" />
|
||||
<Preference
|
||||
android:key="clearMessagesCache"
|
||||
android:summary=""
|
||||
android:title="@string/sett_clear_messages_cache" />
|
||||
<com.vtosters.lite.ui.MaterialSectionDividerPreference />
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user