Add sponsor badge next to own name on profile
- SponsorHelper queries FoxCloud /mobile/me by Telegram ID (X-Tg-Id) and caches is_sponsor per account - Self profile shows a sponsor badge next to the name when is_sponsor is true - Reactive refresh via new NotificationCenter.sponsorStatusUpdated global event Verified: TMessagesProj compileReleaseJavaWithJavac succeeds.
This commit is contained in:
parent
d200a290f8
commit
51bde550b9
5 changed files with 185 additions and 0 deletions
|
|
@ -279,6 +279,7 @@ public class NotificationCenter {
|
||||||
public static final int updatedChatRanks = totalEvents++;
|
public static final int updatedChatRanks = totalEvents++;
|
||||||
public static final int joinedGroup = totalEvents++;
|
public static final int joinedGroup = totalEvents++;
|
||||||
public static final int loadedAiComposeTones = totalEvents++;
|
public static final int loadedAiComposeTones = totalEvents++;
|
||||||
|
public static final int sponsorStatusUpdated = totalEvents++;
|
||||||
|
|
||||||
//global
|
//global
|
||||||
public static final int pushMessagesUpdated = totalEvents++;
|
public static final int pushMessagesUpdated = totalEvents++;
|
||||||
|
|
|
||||||
|
|
@ -341,6 +341,7 @@ import tw.nekomimi.nekogram.BackButtonMenuRecent;
|
||||||
import tw.nekomimi.nekogram.NekoConfig;
|
import tw.nekomimi.nekogram.NekoConfig;
|
||||||
import tw.nekomimi.nekogram.SimpleTextViewSwitcher;
|
import tw.nekomimi.nekogram.SimpleTextViewSwitcher;
|
||||||
import tw.nekomimi.nekogram.helpers.PopupHelper;
|
import tw.nekomimi.nekogram.helpers.PopupHelper;
|
||||||
|
import tw.nekomimi.nekogram.helpers.SponsorHelper;
|
||||||
import tw.nekomimi.nekogram.helpers.remote.ConfigHelper;
|
import tw.nekomimi.nekogram.helpers.remote.ConfigHelper;
|
||||||
import tw.nekomimi.nekogram.settings.NekoSettingsActivity;
|
import tw.nekomimi.nekogram.settings.NekoSettingsActivity;
|
||||||
import tw.nekomimi.nekogram.translator.Translator;
|
import tw.nekomimi.nekogram.translator.Translator;
|
||||||
|
|
@ -375,6 +376,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter.
|
||||||
private final Drawable[] verifiedCheckDrawable = new Drawable[2];
|
private final Drawable[] verifiedCheckDrawable = new Drawable[2];
|
||||||
private final CrossfadeDrawable[] verifiedCrossfadeDrawable = new CrossfadeDrawable[2];
|
private final CrossfadeDrawable[] verifiedCrossfadeDrawable = new CrossfadeDrawable[2];
|
||||||
private final CrossfadeDrawable[] premiumCrossfadeDrawable = new CrossfadeDrawable[2];
|
private final CrossfadeDrawable[] premiumCrossfadeDrawable = new CrossfadeDrawable[2];
|
||||||
|
private final Drawable[] foxSponsorDrawable = new Drawable[2];
|
||||||
private ScamDrawable scamDrawable;
|
private ScamDrawable scamDrawable;
|
||||||
private UndoView undoView;
|
private UndoView undoView;
|
||||||
private OverlaysView overlaysView;
|
private OverlaysView overlaysView;
|
||||||
|
|
@ -2261,6 +2263,10 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter.
|
||||||
getNotificationCenter().addObserver(this, NotificationCenter.profileMusicUpdated);
|
getNotificationCenter().addObserver(this, NotificationCenter.profileMusicUpdated);
|
||||||
getNotificationCenter().addObserver(this, NotificationCenter.updatedChatRanks);
|
getNotificationCenter().addObserver(this, NotificationCenter.updatedChatRanks);
|
||||||
NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.emojiLoaded);
|
NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.emojiLoaded);
|
||||||
|
NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.sponsorStatusUpdated);
|
||||||
|
if (userId == getUserConfig().getClientUserId() || myProfile) {
|
||||||
|
SponsorHelper.refresh(false);
|
||||||
|
}
|
||||||
updateRowsIds();
|
updateRowsIds();
|
||||||
if (listAdapter != null) {
|
if (listAdapter != null) {
|
||||||
listAdapter.notifyDataSetChanged();
|
listAdapter.notifyDataSetChanged();
|
||||||
|
|
@ -2402,6 +2408,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter.
|
||||||
getNotificationCenter().removeObserver(this, NotificationCenter.profileMusicUpdated);
|
getNotificationCenter().removeObserver(this, NotificationCenter.profileMusicUpdated);
|
||||||
getNotificationCenter().removeObserver(this, NotificationCenter.updatedChatRanks);
|
getNotificationCenter().removeObserver(this, NotificationCenter.updatedChatRanks);
|
||||||
NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.emojiLoaded);
|
NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.emojiLoaded);
|
||||||
|
NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.sponsorStatusUpdated);
|
||||||
if (avatarsViewPager != null) {
|
if (avatarsViewPager != null) {
|
||||||
avatarsViewPager.onDestroy();
|
avatarsViewPager.onDestroy();
|
||||||
}
|
}
|
||||||
|
|
@ -9185,6 +9192,10 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter.
|
||||||
public void didReceivedNotification(int id, int account, final Object... args) {
|
public void didReceivedNotification(int id, int account, final Object... args) {
|
||||||
if (id == NotificationCenter.uploadStoryEnd || id == NotificationCenter.chatWasBoostedByUser) {
|
if (id == NotificationCenter.uploadStoryEnd || id == NotificationCenter.chatWasBoostedByUser) {
|
||||||
checkCanSendStoryForPosting();
|
checkCanSendStoryForPosting();
|
||||||
|
} else if (id == NotificationCenter.sponsorStatusUpdated) {
|
||||||
|
if (userId != 0) {
|
||||||
|
updateProfileData(false);
|
||||||
|
}
|
||||||
} else if (id == NotificationCenter.updateInterfaces) {
|
} else if (id == NotificationCenter.updateInterfaces) {
|
||||||
int mask = (Integer) args[0];
|
int mask = (Integer) args[0];
|
||||||
boolean infoChanged = (mask & MessagesController.UPDATE_MASK_AVATAR) != 0 || (mask & MessagesController.UPDATE_MASK_NAME) != 0 || (mask & MessagesController.UPDATE_MASK_STATUS) != 0 || (mask & MessagesController.UPDATE_MASK_EMOJI_STATUS) != 0;
|
boolean infoChanged = (mask & MessagesController.UPDATE_MASK_AVATAR) != 0 || (mask & MessagesController.UPDATE_MASK_NAME) != 0 || (mask & MessagesController.UPDATE_MASK_STATUS) != 0 || (mask & MessagesController.UPDATE_MASK_EMOJI_STATUS) != 0;
|
||||||
|
|
@ -11167,6 +11178,19 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter.
|
||||||
return verifiedCrossfadeDrawable[a];
|
return verifiedCrossfadeDrawable[a];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Drawable getFoxSponsorDrawable(int a) {
|
||||||
|
if (foxSponsorDrawable[a] == null) {
|
||||||
|
Drawable d = ContextCompat.getDrawable(getParentActivity(), R.drawable.foxsponsor_badge).mutate();
|
||||||
|
int color = getThemedColor(Theme.key_profile_verifiedBackground);
|
||||||
|
if (a == 1) {
|
||||||
|
color = dontApplyPeerColor(color);
|
||||||
|
}
|
||||||
|
d.setColorFilter(color, PorterDuff.Mode.SRC_IN);
|
||||||
|
foxSponsorDrawable[a] = d;
|
||||||
|
}
|
||||||
|
return foxSponsorDrawable[a];
|
||||||
|
}
|
||||||
|
|
||||||
private Drawable getPremiumCrossfadeDrawable(int a) {
|
private Drawable getPremiumCrossfadeDrawable(int a) {
|
||||||
if (premiumCrossfadeDrawable[a] == null) {
|
if (premiumCrossfadeDrawable[a] == null) {
|
||||||
premiumStarDrawable[a] = ContextCompat.getDrawable(getParentActivity(), R.drawable.msg_premium_liststar).mutate();
|
premiumStarDrawable[a] = ContextCompat.getDrawable(getParentActivity(), R.drawable.msg_premium_liststar).mutate();
|
||||||
|
|
@ -11538,6 +11562,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter.
|
||||||
} else if (getMessagesController().isDialogMuted(dialogId != 0 ? dialogId : userId, topicId)) {
|
} else if (getMessagesController().isDialogMuted(dialogId != 0 ? dialogId : userId, topicId)) {
|
||||||
nameTextView[a].setRightDrawable2(getThemedDrawable(Theme.key_drawable_muteIconDrawable));
|
nameTextView[a].setRightDrawable2(getThemedDrawable(Theme.key_drawable_muteIconDrawable));
|
||||||
nameTextViewRightDrawable2ContentDescription = LocaleController.getString(R.string.NotificationsMuted);
|
nameTextViewRightDrawable2ContentDescription = LocaleController.getString(R.string.NotificationsMuted);
|
||||||
|
} else if (user.self && SponsorHelper.isSponsor(user.id)) {
|
||||||
|
nameTextView[a].setRightDrawable2(getFoxSponsorDrawable(a));
|
||||||
|
nameTextViewRightDrawable2ContentDescription = LocaleController.getString(R.string.FoxSponsorBadge);
|
||||||
} else {
|
} else {
|
||||||
nameTextView[a].setRightDrawable2(null);
|
nameTextView[a].setRightDrawable2(null);
|
||||||
nameTextViewRightDrawable2ContentDescription = null;
|
nameTextViewRightDrawable2ContentDescription = null;
|
||||||
|
|
@ -11561,6 +11588,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter.
|
||||||
nameTextView[a].setRightDrawable2(getScamDrawable(user.scam ? 0 : 1));
|
nameTextView[a].setRightDrawable2(getScamDrawable(user.scam ? 0 : 1));
|
||||||
} else if (user.verified) {
|
} else if (user.verified) {
|
||||||
nameTextView[a].setRightDrawable2(getVerifiedCrossfadeDrawable(a));
|
nameTextView[a].setRightDrawable2(getVerifiedCrossfadeDrawable(a));
|
||||||
|
} else if (user.self && SponsorHelper.isSponsor(user.id)) {
|
||||||
|
nameTextView[a].setRightDrawable2(getFoxSponsorDrawable(a));
|
||||||
} else {
|
} else {
|
||||||
nameTextView[a].setRightDrawable2(null);
|
nameTextView[a].setRightDrawable2(null);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,145 @@
|
||||||
|
package tw.nekomimi.nekogram.helpers;
|
||||||
|
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import org.telegram.messenger.AndroidUtilities;
|
||||||
|
import org.telegram.messenger.ApplicationLoader;
|
||||||
|
import org.telegram.messenger.FileLog;
|
||||||
|
import org.telegram.messenger.NotificationCenter;
|
||||||
|
import org.telegram.messenger.UserConfig;
|
||||||
|
import org.telegram.messenger.Utilities;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves the "sponsor" status of the current Telegram user against the
|
||||||
|
* FoxCloud backend and caches it locally.
|
||||||
|
*
|
||||||
|
* Identification is done purely by Telegram ID: the backend endpoint
|
||||||
|
* {@code GET /mobile/me} accepts an {@code X-Tg-Id} header and looks the user
|
||||||
|
* up by the Telegram account that was linked on the website / bot. No
|
||||||
|
* subscription URL or manual input is required.
|
||||||
|
*
|
||||||
|
* The result is cached per-account in shared preferences so the badge can be
|
||||||
|
* drawn synchronously while a fresh check runs in the background. When the
|
||||||
|
* cached value changes, {@link NotificationCenter#sponsorStatusUpdated} is
|
||||||
|
* posted on the global instance.
|
||||||
|
*/
|
||||||
|
public final class SponsorHelper {
|
||||||
|
|
||||||
|
private SponsorHelper() {}
|
||||||
|
|
||||||
|
private static final String TAG = "SponsorHelper";
|
||||||
|
private static final String BASE_URL = "https://vpnghost.space";
|
||||||
|
private static final String PREFS = "foxsponsor";
|
||||||
|
// Re-check at most once per hour while the value is fresh.
|
||||||
|
private static final long TTL_MS = 60 * 60 * 1000L;
|
||||||
|
|
||||||
|
private static volatile boolean checking = false;
|
||||||
|
|
||||||
|
private static SharedPreferences prefs() {
|
||||||
|
return ApplicationLoader.applicationContext.getSharedPreferences(PREFS, android.content.Context.MODE_PRIVATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Cached sponsor flag for the given Telegram user id. Defaults to false. */
|
||||||
|
public static boolean isSponsor(long telegramId) {
|
||||||
|
if (telegramId == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return prefs().getBoolean("sponsor_" + telegramId, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convenience: sponsor flag for the currently selected account. */
|
||||||
|
public static boolean isCurrentUserSponsor() {
|
||||||
|
var user = UserConfig.getInstance(UserConfig.selectedAccount).getCurrentUser();
|
||||||
|
return user != null && isSponsor(user.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kick off a background refresh of the sponsor status for the current
|
||||||
|
* account. Safe to call repeatedly: it self-throttles via {@link #TTL_MS}
|
||||||
|
* unless {@code force} is set.
|
||||||
|
*/
|
||||||
|
public static void refresh(boolean force) {
|
||||||
|
var user = UserConfig.getInstance(UserConfig.selectedAccount).getCurrentUser();
|
||||||
|
if (user == null || user.id == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final long telegramId = user.id;
|
||||||
|
if (checking) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!force) {
|
||||||
|
long last = prefs().getLong("checked_" + telegramId, 0);
|
||||||
|
if (Math.abs(System.currentTimeMillis() - last) < TTL_MS) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checking = true;
|
||||||
|
Utilities.globalQueue.postRunnable(() -> {
|
||||||
|
try {
|
||||||
|
doCheck(telegramId);
|
||||||
|
} finally {
|
||||||
|
checking = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// @WorkerThread
|
||||||
|
private static void doCheck(long telegramId) {
|
||||||
|
HttpURLConnection connection = null;
|
||||||
|
try {
|
||||||
|
URL url = new URL(BASE_URL + "/mobile/me");
|
||||||
|
connection = (HttpURLConnection) url.openConnection();
|
||||||
|
connection.setInstanceFollowRedirects(true);
|
||||||
|
connection.setConnectTimeout(15000);
|
||||||
|
connection.setReadTimeout(15000);
|
||||||
|
connection.setRequestProperty("X-Tg-Id", String.valueOf(telegramId));
|
||||||
|
connection.setRequestProperty("Accept", "application/json");
|
||||||
|
|
||||||
|
int code = connection.getResponseCode();
|
||||||
|
if (code != HttpURLConnection.HTTP_OK) {
|
||||||
|
FileLog.d(TAG + ": /mobile/me returned HTTP " + code);
|
||||||
|
// Don't clobber a previously known value on transient errors.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
try (InputStream in = connection.getInputStream()) {
|
||||||
|
byte[] buffer = new byte[4096];
|
||||||
|
int read;
|
||||||
|
while ((read = in.read(buffer)) >= 0) {
|
||||||
|
sb.append(new String(buffer, 0, read, "UTF-8"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject json = new JSONObject(sb.toString());
|
||||||
|
if (!json.optBoolean("success", false)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
boolean sponsor = json.optBoolean("is_sponsor", false);
|
||||||
|
store(telegramId, sponsor);
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e(e);
|
||||||
|
} finally {
|
||||||
|
if (connection != null) {
|
||||||
|
connection.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void store(long telegramId, boolean sponsor) {
|
||||||
|
boolean previous = prefs().getBoolean("sponsor_" + telegramId, false);
|
||||||
|
prefs().edit()
|
||||||
|
.putBoolean("sponsor_" + telegramId, sponsor)
|
||||||
|
.putLong("checked_" + telegramId, System.currentTimeMillis())
|
||||||
|
.apply();
|
||||||
|
if (previous != sponsor) {
|
||||||
|
AndroidUtilities.runOnUIThread(() ->
|
||||||
|
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.sponsorStatusUpdated));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
9
TMessagesProj/src/main/res/drawable/foxsponsor_badge.xml
Normal file
9
TMessagesProj/src/main/res/drawable/foxsponsor_badge.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M12,2L14.6,7.27L20.42,8.12L16.21,12.22L17.2,18.02L12,15.28L6.8,18.02L7.79,12.22L3.58,8.12L9.4,7.27L12,2Z" />
|
||||||
|
</vector>
|
||||||
|
|
@ -149,6 +149,7 @@
|
||||||
<string name="ShareNekogram">Share FoxiGram...</string>
|
<string name="ShareNekogram">Share FoxiGram...</string>
|
||||||
<string name="NekogramVersion">FoxiGram %1$s\nBased on Telegram %2$s\nDesigned by %3$s</string>
|
<string name="NekogramVersion">FoxiGram %1$s\nBased on Telegram %2$s\nDesigned by %3$s</string>
|
||||||
<string name="UpdateInstalling">Installing update...</string>
|
<string name="UpdateInstalling">Installing update...</string>
|
||||||
|
<string name="FoxSponsorBadge">Sponsor</string>
|
||||||
<string name="UpdateDownloading">Downloading update...</string>
|
<string name="UpdateDownloading">Downloading update...</string>
|
||||||
<string name="UpdateInstallingNotification">A notification will be shown when the update completes.</string>
|
<string name="UpdateInstallingNotification">A notification will be shown when the update completes.</string>
|
||||||
<string name="UpdateInstallingRelaunch">The app will relaunch when the update completes.</string>
|
<string name="UpdateInstallingRelaunch">The app will relaunch when the update completes.</string>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue