mirror of https://github.com/NekoX-Dev/NekoX.git
Refactor Updater
This commit is contained in:
parent
76ef6ac602
commit
d67c5c27b9
|
@ -1345,41 +1345,21 @@ public class SharedConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isAppUpdateAvailable() {
|
public static boolean isAppUpdateAvailable() {
|
||||||
if (pendingAppUpdate == null || pendingAppUpdate.document == null || !AndroidUtilities.isStandaloneApp()) {
|
if (pendingAppUpdate == null || pendingAppUpdate.document == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int currentVersion;
|
return pendingAppUpdateBuildVersion == BuildVars.BUILD_VERSION;
|
||||||
try {
|
|
||||||
PackageInfo pInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0);
|
|
||||||
currentVersion = pInfo.versionCode;
|
|
||||||
} catch (Exception e) {
|
|
||||||
FileLog.e(e);
|
|
||||||
currentVersion = BuildVars.BUILD_VERSION;
|
|
||||||
}
|
|
||||||
return pendingAppUpdateBuildVersion == currentVersion;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean setNewAppVersionAvailable(TLRPC.TL_help_appUpdate update) {
|
public static boolean setNewAppVersionAvailable(TLRPC.TL_help_appUpdate update) {
|
||||||
String updateVersionString = null;
|
if (update == null) {
|
||||||
int versionCode = 0;
|
pendingAppUpdate = null;
|
||||||
try {
|
pendingAppUpdateBuildVersion = 0;
|
||||||
PackageInfo packageInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0);
|
saveConfig();
|
||||||
versionCode = packageInfo.versionCode;
|
|
||||||
updateVersionString = packageInfo.versionName;
|
|
||||||
} catch (Exception e) {
|
|
||||||
FileLog.e(e);
|
|
||||||
}
|
|
||||||
if (versionCode == 0) {
|
|
||||||
versionCode = BuildVars.BUILD_VERSION;
|
|
||||||
}
|
|
||||||
if (updateVersionString == null) {
|
|
||||||
updateVersionString = BuildVars.BUILD_VERSION_STRING;
|
|
||||||
}
|
|
||||||
if (update.version == null || updateVersionString.compareTo(update.version) >= 0) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
pendingAppUpdate = update;
|
pendingAppUpdate = update;
|
||||||
pendingAppUpdateBuildVersion = versionCode;
|
pendingAppUpdateBuildVersion = BuildConfig.VERSION_CODE;
|
||||||
saveConfig();
|
saveConfig();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -233,7 +233,7 @@ public class BlockingUpdateView extends FrameLayout implements NotificationCente
|
||||||
public static boolean checkApkInstallPermissions(final Context context) {
|
public static boolean checkApkInstallPermissions(final Context context) {
|
||||||
if (Build.VERSION.SDK_INT >= 26 && !ApplicationLoader.applicationContext.getPackageManager().canRequestPackageInstalls()) {
|
if (Build.VERSION.SDK_INT >= 26 && !ApplicationLoader.applicationContext.getPackageManager().canRequestPackageInstalls()) {
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||||
builder.setTitle(LocaleController.getString("AppName", R.string.AppName));
|
builder.setTitle(LocaleController.getString("NekoX", R.string.NekoX));
|
||||||
builder.setMessage(LocaleController.getString("ApkRestricted", R.string.ApkRestricted));
|
builder.setMessage(LocaleController.getString("ApkRestricted", R.string.ApkRestricted));
|
||||||
builder.setPositiveButton(LocaleController.getString("PermissionOpenSettings", R.string.PermissionOpenSettings), (dialogInterface, i) -> {
|
builder.setPositiveButton(LocaleController.getString("PermissionOpenSettings", R.string.PermissionOpenSettings), (dialogInterface, i) -> {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -32,6 +32,7 @@ import org.telegram.messenger.SvgHelper;
|
||||||
import org.telegram.tgnet.TLRPC;
|
import org.telegram.tgnet.TLRPC;
|
||||||
import org.telegram.ui.ActionBar.BottomSheet;
|
import org.telegram.ui.ActionBar.BottomSheet;
|
||||||
import org.telegram.ui.ActionBar.Theme;
|
import org.telegram.ui.ActionBar.Theme;
|
||||||
|
import tw.nekomimi.nekogram.parts.DialogTransKt;
|
||||||
|
|
||||||
public class UpdateAppAlertDialog extends BottomSheet {
|
public class UpdateAppAlertDialog extends BottomSheet {
|
||||||
|
|
||||||
|
@ -252,7 +253,7 @@ public class UpdateAppAlertDialog extends BottomSheet {
|
||||||
textView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack));
|
textView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack));
|
||||||
textView.setSingleLine(true);
|
textView.setSingleLine(true);
|
||||||
textView.setEllipsize(TextUtils.TruncateAt.END);
|
textView.setEllipsize(TextUtils.TruncateAt.END);
|
||||||
textView.setText(LocaleController.getString("AppUpdate", R.string.AppUpdate));
|
textView.setText(LocaleController.getString("AppUpdateNekoX", R.string.AppUpdateNekoX));
|
||||||
linearLayout.addView(textView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 23, 16, 23, 0));
|
linearLayout.addView(textView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 23, 16, 23, 0));
|
||||||
|
|
||||||
TextView messageTextView = new TextView(getContext());
|
TextView messageTextView = new TextView(getContext());
|
||||||
|
@ -262,7 +263,16 @@ public class UpdateAppAlertDialog extends BottomSheet {
|
||||||
messageTextView.setLinkTextColor(Theme.getColor(Theme.key_dialogTextLink));
|
messageTextView.setLinkTextColor(Theme.getColor(Theme.key_dialogTextLink));
|
||||||
messageTextView.setText(LocaleController.formatString("AppUpdateVersionAndSize", R.string.AppUpdateVersionAndSize, appUpdate.version, AndroidUtilities.formatFileSize(appUpdate.document.size)));
|
messageTextView.setText(LocaleController.formatString("AppUpdateVersionAndSize", R.string.AppUpdateVersionAndSize, appUpdate.version, AndroidUtilities.formatFileSize(appUpdate.document.size)));
|
||||||
messageTextView.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.TOP);
|
messageTextView.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.TOP);
|
||||||
linearLayout.addView(messageTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 23, 0, 23, 5));
|
linearLayout.addView(messageTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 23, 5, 23, 5));
|
||||||
|
|
||||||
|
TextView translationHintTextView = new TextView(getContext());
|
||||||
|
translationHintTextView.setTextColor(Theme.getColor(Theme.key_dialogTextGray2));
|
||||||
|
translationHintTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
|
||||||
|
translationHintTextView.setMovementMethod(new AndroidUtilities.LinkMovementMethodMy());
|
||||||
|
translationHintTextView.setLinkTextColor(Theme.getColor(Theme.key_dialogTextLink));
|
||||||
|
translationHintTextView.setText(LocaleController.getString("NekoXUpdateTranslationHint", R.string.NekoXUpdateTranslationHint));
|
||||||
|
translationHintTextView.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.TOP);
|
||||||
|
linearLayout.addView(translationHintTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 23, 0, 23, 5));
|
||||||
|
|
||||||
TextView changelogTextView = new TextView(getContext());
|
TextView changelogTextView = new TextView(getContext());
|
||||||
changelogTextView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack));
|
changelogTextView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack));
|
||||||
|
@ -277,6 +287,11 @@ public class UpdateAppAlertDialog extends BottomSheet {
|
||||||
changelogTextView.setText(builder);
|
changelogTextView.setText(builder);
|
||||||
}
|
}
|
||||||
changelogTextView.setGravity(Gravity.LEFT | Gravity.TOP);
|
changelogTextView.setGravity(Gravity.LEFT | Gravity.TOP);
|
||||||
|
changelogTextView.setOnLongClickListener(v -> {
|
||||||
|
if (TextUtils.isEmpty(appUpdate.text)) return false;
|
||||||
|
DialogTransKt.startTrans(v.getContext(), appUpdate.text);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
linearLayout.addView(changelogTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 23, 15, 23, 0));
|
linearLayout.addView(changelogTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 23, 15, 23, 0));
|
||||||
|
|
||||||
FrameLayout.LayoutParams frameLayoutParams = new FrameLayout.LayoutParams(LayoutHelper.MATCH_PARENT, AndroidUtilities.getShadowHeight(), Gravity.BOTTOM | Gravity.LEFT);
|
FrameLayout.LayoutParams frameLayoutParams = new FrameLayout.LayoutParams(LayoutHelper.MATCH_PARENT, AndroidUtilities.getShadowHeight(), Gravity.BOTTOM | Gravity.LEFT);
|
||||||
|
|
|
@ -351,10 +351,10 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter.
|
||||||
private boolean showSetPasswordConfirm;
|
private boolean showSetPasswordConfirm;
|
||||||
private int otherwiseReloginDays;
|
private int otherwiseReloginDays;
|
||||||
|
|
||||||
private FrameLayout updateLayout;
|
// private FrameLayout updateLayout;
|
||||||
private AnimatorSet updateLayoutAnimator;
|
// private AnimatorSet updateLayoutAnimator;
|
||||||
private RadialProgress2 updateLayoutIcon;
|
// private RadialProgress2 updateLayoutIcon;
|
||||||
private TextView updateTextView;
|
// private TextView updateTextView;
|
||||||
|
|
||||||
private DialogsActivityDelegate delegate;
|
private DialogsActivityDelegate delegate;
|
||||||
|
|
||||||
|
@ -3415,77 +3415,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (searchString == null && initialDialogsType == 0) {
|
if (searchString == null && initialDialogsType == 0) {
|
||||||
updateLayout = new FrameLayout(context) {
|
// NekoX: Remove UPDATE NOW Bottom View in DialogsActivity
|
||||||
|
|
||||||
private Paint paint = new Paint();
|
|
||||||
private Matrix matrix = new Matrix();
|
|
||||||
private LinearGradient updateGradient;
|
|
||||||
private int lastGradientWidth;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onDraw(Canvas canvas) {
|
|
||||||
if (updateGradient == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
paint.setColor(0xffffffff);
|
|
||||||
paint.setShader(updateGradient);
|
|
||||||
updateGradient.setLocalMatrix(matrix);
|
|
||||||
canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), paint);
|
|
||||||
updateLayoutIcon.setBackgroundGradientDrawable(updateGradient);
|
|
||||||
updateLayoutIcon.draw(canvas);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
|
||||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
|
||||||
int width = MeasureSpec.getSize(widthMeasureSpec);
|
|
||||||
if (lastGradientWidth != width) {
|
|
||||||
updateGradient = new LinearGradient(0, 0, width, 0, new int[]{0xff69BF72, 0xff53B3AD}, new float[]{0.0f, 1.0f}, Shader.TileMode.CLAMP);
|
|
||||||
lastGradientWidth = width;
|
|
||||||
}
|
|
||||||
int x = (getMeasuredWidth() - updateTextView.getMeasuredWidth()) / 2;
|
|
||||||
updateLayoutIcon.setProgressRect(x, AndroidUtilities.dp(13), x + AndroidUtilities.dp(22), AndroidUtilities.dp(13 + 22));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setTranslationY(float translationY) {
|
|
||||||
super.setTranslationY(translationY);
|
|
||||||
additionalFloatingTranslation2 = AndroidUtilities.dp(48) - translationY;
|
|
||||||
if (additionalFloatingTranslation2 < 0) {
|
|
||||||
additionalFloatingTranslation2 = 0;
|
|
||||||
}
|
|
||||||
if (!floatingHidden) {
|
|
||||||
updateFloatingButtonOffset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
updateLayout.setWillNotDraw(false);
|
|
||||||
updateLayout.setVisibility(View.INVISIBLE);
|
|
||||||
updateLayout.setTranslationY(AndroidUtilities.dp(48));
|
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
|
||||||
updateLayout.setBackground(Theme.getSelectorDrawable(Theme.getColor(Theme.key_listSelector), null));
|
|
||||||
}
|
|
||||||
contentView.addView(updateLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM));
|
|
||||||
updateLayout.setOnClickListener(v -> {
|
|
||||||
if (!SharedConfig.isAppUpdateAvailable()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
AndroidUtilities.openForView(SharedConfig.pendingAppUpdate.document, true, getParentActivity());
|
|
||||||
});
|
|
||||||
|
|
||||||
updateLayoutIcon = new RadialProgress2(updateLayout);
|
|
||||||
updateLayoutIcon.setColors(0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
|
|
||||||
updateLayoutIcon.setCircleRadius(AndroidUtilities.dp(11));
|
|
||||||
updateLayoutIcon.setAsMini();
|
|
||||||
updateLayoutIcon.setIcon(MediaActionDrawable.ICON_UPDATE, true, false);
|
|
||||||
|
|
||||||
updateTextView = new TextView(context);
|
|
||||||
updateTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
|
|
||||||
updateTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
|
|
||||||
updateTextView.setText(LocaleController.getString("AppUpdateNow", R.string.AppUpdateNow).toUpperCase());
|
|
||||||
updateTextView.setTextColor(0xffffffff);
|
|
||||||
updateTextView.setPadding(AndroidUtilities.dp(30), 0, 0, 0);
|
|
||||||
updateLayout.addView(updateTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 0, 0, 0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int a = 0; a < 2; a++) {
|
for (int a = 0; a < 2; a++) {
|
||||||
|
@ -3615,8 +3545,6 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter.
|
||||||
PrivacyUtil.postCheckAll(getParentActivity(), currentAccount);
|
PrivacyUtil.postCheckAll(getParentActivity(), currentAccount);
|
||||||
if (new Random().nextInt(100) < 20)
|
if (new Random().nextInt(100) < 20)
|
||||||
UpdateUtil.postCheckFollowChannel(getParentActivity(), currentAccount);
|
UpdateUtil.postCheckFollowChannel(getParentActivity(), currentAccount);
|
||||||
if (!BuildVars.isFdroid && !BuildVars.isPlay && NekoXConfig.autoUpdateReleaseChannel != 0 && System.currentTimeMillis() / 1000 > NekoXConfig.nextUpdateCheck)
|
|
||||||
UIUtil.runOnIoDispatcher(() -> InternalUpdater.checkUpdate(getParentActivity(), true), 6000);
|
|
||||||
|
|
||||||
if (NekoXConfig.developerMode && !NekoXConfig.isDeveloper())
|
if (NekoXConfig.developerMode && !NekoXConfig.isDeveloper())
|
||||||
NekoXConfig.toggleDeveloperMode();
|
NekoXConfig.toggleDeveloperMode();
|
||||||
|
@ -3624,66 +3552,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter.
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateAppUpdateViews(boolean animated) {
|
private void updateAppUpdateViews(boolean animated) {
|
||||||
if (updateLayout == null) {
|
// NekoX: Remove UPDATE NOW Bottom View in DialogsActivity
|
||||||
return;
|
|
||||||
}
|
|
||||||
boolean show;
|
|
||||||
if (SharedConfig.isAppUpdateAvailable()) {
|
|
||||||
String fileName = FileLoader.getAttachFileName(SharedConfig.pendingAppUpdate.document);
|
|
||||||
File path = FileLoader.getPathToAttach(SharedConfig.pendingAppUpdate.document, true);
|
|
||||||
show = path.exists();
|
|
||||||
} else {
|
|
||||||
show = false;
|
|
||||||
}
|
|
||||||
if (show) {
|
|
||||||
if (updateLayout.getTag() != null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (updateLayoutAnimator != null) {
|
|
||||||
updateLayoutAnimator.cancel();
|
|
||||||
}
|
|
||||||
updateLayout.setVisibility(View.VISIBLE);
|
|
||||||
updateLayout.setTag(1);
|
|
||||||
if (animated) {
|
|
||||||
updateLayoutAnimator = new AnimatorSet();
|
|
||||||
updateLayoutAnimator.setDuration(180);
|
|
||||||
updateLayoutAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT);
|
|
||||||
updateLayoutAnimator.playTogether(ObjectAnimator.ofFloat(updateLayout, View.TRANSLATION_Y, 0));
|
|
||||||
updateLayoutAnimator.addListener(new AnimatorListenerAdapter() {
|
|
||||||
@Override
|
|
||||||
public void onAnimationEnd(Animator animation) {
|
|
||||||
updateLayoutAnimator = null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
updateLayoutAnimator.start();
|
|
||||||
} else {
|
|
||||||
updateLayout.setTranslationY(0);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (updateLayout.getTag() == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
updateLayout.setTag(null);
|
|
||||||
if (animated) {
|
|
||||||
updateLayoutAnimator = new AnimatorSet();
|
|
||||||
updateLayoutAnimator.setDuration(180);
|
|
||||||
updateLayoutAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT);
|
|
||||||
updateLayoutAnimator.playTogether(ObjectAnimator.ofFloat(updateLayout, View.TRANSLATION_Y, AndroidUtilities.dp(48)));
|
|
||||||
updateLayoutAnimator.addListener(new AnimatorListenerAdapter() {
|
|
||||||
@Override
|
|
||||||
public void onAnimationEnd(Animator animation) {
|
|
||||||
if (updateLayout.getTag() == null) {
|
|
||||||
updateLayout.setVisibility(View.INVISIBLE);
|
|
||||||
}
|
|
||||||
updateLayoutAnimator = null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
updateLayoutAnimator.start();
|
|
||||||
} else {
|
|
||||||
updateLayout.setTranslationY(AndroidUtilities.dp(48));
|
|
||||||
updateLayout.setVisibility(View.INVISIBLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateContextViewPosition() {
|
private void updateContextViewPosition() {
|
||||||
|
@ -6728,7 +6597,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter.
|
||||||
View databaseMigrationHint;
|
View databaseMigrationHint;
|
||||||
|
|
||||||
private void updateMenuButton(boolean animated) {
|
private void updateMenuButton(boolean animated) {
|
||||||
if (menuDrawable == null || updateLayout == null) {
|
if (menuDrawable == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int type;
|
int type;
|
||||||
|
|
|
@ -22,7 +22,11 @@ import android.content.res.Configuration;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.LinearGradient;
|
||||||
|
import android.graphics.Matrix;
|
||||||
|
import android.graphics.Paint;
|
||||||
import android.graphics.Point;
|
import android.graphics.Point;
|
||||||
|
import android.graphics.Shader;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.location.LocationManager;
|
import android.location.LocationManager;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
|
@ -36,7 +40,9 @@ import android.provider.ContactsContract;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Base64;
|
import android.util.Base64;
|
||||||
|
import android.util.TypedValue;
|
||||||
import android.view.ActionMode;
|
import android.view.ActionMode;
|
||||||
|
import android.view.Gravity;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
|
@ -113,11 +119,13 @@ import org.telegram.ui.Components.AudioPlayerAlert;
|
||||||
import org.telegram.ui.Components.BlockingUpdateView;
|
import org.telegram.ui.Components.BlockingUpdateView;
|
||||||
import org.telegram.ui.Components.Bulletin;
|
import org.telegram.ui.Components.Bulletin;
|
||||||
import org.telegram.ui.Components.BulletinFactory;
|
import org.telegram.ui.Components.BulletinFactory;
|
||||||
|
import org.telegram.ui.Components.CubicBezierInterpolator;
|
||||||
import org.telegram.ui.Components.Easings;
|
import org.telegram.ui.Components.Easings;
|
||||||
import org.telegram.ui.Components.EmbedBottomSheet;
|
import org.telegram.ui.Components.EmbedBottomSheet;
|
||||||
import org.telegram.ui.Components.GroupCallPip;
|
import org.telegram.ui.Components.GroupCallPip;
|
||||||
import org.telegram.ui.Components.JoinGroupAlert;
|
import org.telegram.ui.Components.JoinGroupAlert;
|
||||||
import org.telegram.ui.Components.LayoutHelper;
|
import org.telegram.ui.Components.LayoutHelper;
|
||||||
|
import org.telegram.ui.Components.MediaActionDrawable;
|
||||||
import org.telegram.ui.Components.PasscodeView;
|
import org.telegram.ui.Components.PasscodeView;
|
||||||
import org.telegram.ui.Components.PhonebookShareAlert;
|
import org.telegram.ui.Components.PhonebookShareAlert;
|
||||||
import org.telegram.ui.Components.PipRoundVideoView;
|
import org.telegram.ui.Components.PipRoundVideoView;
|
||||||
|
@ -133,6 +141,7 @@ import org.telegram.ui.Components.StickersAlert;
|
||||||
import org.telegram.ui.Components.TermsOfServiceView;
|
import org.telegram.ui.Components.TermsOfServiceView;
|
||||||
import org.telegram.ui.Components.ThemeEditorView;
|
import org.telegram.ui.Components.ThemeEditorView;
|
||||||
import org.telegram.ui.Components.UndoView;
|
import org.telegram.ui.Components.UndoView;
|
||||||
|
import org.telegram.ui.Components.UpdateAppAlertDialog;
|
||||||
import org.telegram.ui.Components.voip.VoIPHelper;
|
import org.telegram.ui.Components.voip.VoIPHelper;
|
||||||
import org.webrtc.voiceengine.WebRtcAudioTrack;
|
import org.webrtc.voiceengine.WebRtcAudioTrack;
|
||||||
|
|
||||||
|
@ -155,6 +164,7 @@ import java.util.regex.Pattern;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import kotlin.Unit;
|
import kotlin.Unit;
|
||||||
import kotlin.text.StringsKt;
|
import kotlin.text.StringsKt;
|
||||||
|
import tw.nekomimi.nekogram.InternalUpdater;
|
||||||
import tw.nekomimi.nekogram.ui.BottomBuilder;
|
import tw.nekomimi.nekogram.ui.BottomBuilder;
|
||||||
import tw.nekomimi.nekogram.ExternalGcm;
|
import tw.nekomimi.nekogram.ExternalGcm;
|
||||||
import tw.nekomimi.nekogram.NekoConfig;
|
import tw.nekomimi.nekogram.NekoConfig;
|
||||||
|
@ -2085,6 +2095,8 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
FileLog.e(e);
|
FileLog.e(e);
|
||||||
}
|
}
|
||||||
|
} else if (url.startsWith("tg:upgrade") || url.startsWith("tg://upgrade") || url.startsWith("tg:update") || url.startsWith("tg://update")) {
|
||||||
|
checkAppUpdate(true);
|
||||||
} else if ((url.startsWith("tg:search") || url.startsWith("tg://search"))) {
|
} else if ((url.startsWith("tg:search") || url.startsWith("tg://search"))) {
|
||||||
url = url.replace("tg:search", "tg://telegram.org").replace("tg://search", "tg://telegram.org");
|
url = url.replace("tg:search", "tg://telegram.org").replace("tg://search", "tg://telegram.org");
|
||||||
data = Uri.parse(url);
|
data = Uri.parse(url);
|
||||||
|
@ -3652,6 +3664,201 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
||||||
return foundContacts;
|
return foundContacts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void createUpdateUI() {
|
||||||
|
if (sideMenuContainer == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateLayout = new FrameLayout(this) {
|
||||||
|
|
||||||
|
private Paint paint = new Paint();
|
||||||
|
private Matrix matrix = new Matrix();
|
||||||
|
private LinearGradient updateGradient;
|
||||||
|
private int lastGradientWidth;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDraw(Canvas canvas) {
|
||||||
|
if (updateGradient == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
paint.setColor(0xffffffff);
|
||||||
|
paint.setShader(updateGradient);
|
||||||
|
updateGradient.setLocalMatrix(matrix);
|
||||||
|
canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), paint);
|
||||||
|
updateLayoutIcon.setBackgroundGradientDrawable(updateGradient);
|
||||||
|
updateLayoutIcon.draw(canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||||
|
int width = MeasureSpec.getSize(widthMeasureSpec);
|
||||||
|
if (lastGradientWidth != width) {
|
||||||
|
updateGradient = new LinearGradient(0, 0, width, 0, new int[]{0xff69BF72, 0xff53B3AD}, new float[]{0.0f, 1.0f}, Shader.TileMode.CLAMP);
|
||||||
|
lastGradientWidth = width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
updateLayout.setWillNotDraw(false);
|
||||||
|
updateLayout.setVisibility(View.INVISIBLE);
|
||||||
|
updateLayout.setTranslationY(AndroidUtilities.dp(44));
|
||||||
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
|
updateLayout.setBackground(Theme.getSelectorDrawable(Theme.getColor(Theme.key_listSelector), null));
|
||||||
|
}
|
||||||
|
sideMenuContainer.addView(updateLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 44, Gravity.LEFT | Gravity.BOTTOM));
|
||||||
|
updateLayout.setOnClickListener(v -> {
|
||||||
|
if (!SharedConfig.isAppUpdateAvailable()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (updateLayoutIcon.getIcon() == MediaActionDrawable.ICON_DOWNLOAD) {
|
||||||
|
FileLoader.getInstance(currentAccount).loadFile(SharedConfig.pendingAppUpdate.document, "update", 1, 1);
|
||||||
|
updateAppUpdateViews(true);
|
||||||
|
} else if (updateLayoutIcon.getIcon() == MediaActionDrawable.ICON_CANCEL) {
|
||||||
|
FileLoader.getInstance(currentAccount).cancelLoadFile(SharedConfig.pendingAppUpdate.document);
|
||||||
|
updateAppUpdateViews(true);
|
||||||
|
} else {
|
||||||
|
AndroidUtilities.openForView(SharedConfig.pendingAppUpdate.document, true, this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
updateLayoutIcon = new RadialProgress2(updateLayout);
|
||||||
|
updateLayoutIcon.setColors(0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||||
|
updateLayoutIcon.setProgressRect(AndroidUtilities.dp(22), AndroidUtilities.dp(11), AndroidUtilities.dp(22 + 22), AndroidUtilities.dp(11 + 22));
|
||||||
|
updateLayoutIcon.setCircleRadius(AndroidUtilities.dp(11));
|
||||||
|
updateLayoutIcon.setAsMini();
|
||||||
|
|
||||||
|
updateTextView = new SimpleTextView(this);
|
||||||
|
updateTextView.setTextSize(15);
|
||||||
|
updateTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
|
||||||
|
updateTextView.setText(LocaleController.getString("AppUpdate", R.string.AppUpdate));
|
||||||
|
updateTextView.setTextColor(0xffffffff);
|
||||||
|
updateTextView.setGravity(Gravity.LEFT);
|
||||||
|
updateLayout.addView(updateTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 74, 0, 0, 0));
|
||||||
|
|
||||||
|
updateSizeTextView = new TextView(this);
|
||||||
|
updateSizeTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
|
||||||
|
updateSizeTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
|
||||||
|
updateSizeTextView.setGravity(Gravity.RIGHT);
|
||||||
|
updateSizeTextView.setTextColor(0xffffffff);
|
||||||
|
updateLayout.addView(updateSizeTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | Gravity.RIGHT, 0, 0, 17, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateAppUpdateViews(boolean animated) {
|
||||||
|
if (sideMenuContainer == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (SharedConfig.isAppUpdateAvailable()) {
|
||||||
|
createUpdateUI();
|
||||||
|
updateSizeTextView.setText(AndroidUtilities.formatFileSize(SharedConfig.pendingAppUpdate.document.size));
|
||||||
|
String fileName = FileLoader.getAttachFileName(SharedConfig.pendingAppUpdate.document);
|
||||||
|
File path = FileLoader.getPathToAttach(SharedConfig.pendingAppUpdate.document, true);
|
||||||
|
boolean showSize;
|
||||||
|
if (path.exists()) {
|
||||||
|
updateLayoutIcon.setIcon(MediaActionDrawable.ICON_UPDATE, true, animated);
|
||||||
|
updateTextView.setText(LocaleController.getString("AppUpdateNow", R.string.AppUpdateNow));
|
||||||
|
showSize = false;
|
||||||
|
} else {
|
||||||
|
if (FileLoader.getInstance(currentAccount).isLoadingFile(fileName)) {
|
||||||
|
updateLayoutIcon.setIcon(MediaActionDrawable.ICON_CANCEL, true, animated);
|
||||||
|
Float p = ImageLoader.getInstance().getFileProgress(fileName);
|
||||||
|
updateTextView.setText(LocaleController.formatString("AppUpdateDownloading", R.string.AppUpdateDownloading, (int) ((p != null ? p : 0.0f) * 100)));
|
||||||
|
showSize = false;
|
||||||
|
} else {
|
||||||
|
updateLayoutIcon.setIcon(MediaActionDrawable.ICON_DOWNLOAD, true, animated);
|
||||||
|
updateTextView.setText(LocaleController.getString("AppUpdate", R.string.AppUpdate));
|
||||||
|
showSize = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (showSize) {
|
||||||
|
if (updateSizeTextView.getTag() != null) {
|
||||||
|
if (animated) {
|
||||||
|
updateSizeTextView.setTag(null);
|
||||||
|
updateSizeTextView.animate().alpha(1.0f).scaleX(1.0f).scaleY(1.0f).setDuration(180).start();
|
||||||
|
} else {
|
||||||
|
updateSizeTextView.setAlpha(1.0f);
|
||||||
|
updateSizeTextView.setScaleX(1.0f);
|
||||||
|
updateSizeTextView.setScaleY(1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (updateSizeTextView.getTag() == null) {
|
||||||
|
if (animated) {
|
||||||
|
updateSizeTextView.setTag(1);
|
||||||
|
updateSizeTextView.animate().alpha(0.0f).scaleX(0.0f).scaleY(0.0f).setDuration(180).start();
|
||||||
|
} else {
|
||||||
|
updateSizeTextView.setAlpha(0.0f);
|
||||||
|
updateSizeTextView.setScaleX(0.0f);
|
||||||
|
updateSizeTextView.setScaleY(0.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (updateLayout.getTag() != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateLayout.setVisibility(View.VISIBLE);
|
||||||
|
updateLayout.setTag(1);
|
||||||
|
if (animated) {
|
||||||
|
updateLayout.animate().translationY(0).setInterpolator(CubicBezierInterpolator.EASE_OUT).setListener(null).setDuration(180).start();
|
||||||
|
} else {
|
||||||
|
updateLayout.setTranslationY(0);
|
||||||
|
}
|
||||||
|
sideMenu.setPadding(0, 0, 0, AndroidUtilities.dp(44));
|
||||||
|
} else {
|
||||||
|
if (updateLayout == null || updateLayout.getTag() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateLayout.setTag(null);
|
||||||
|
if (animated) {
|
||||||
|
updateLayout.animate().translationY(AndroidUtilities.dp(44)).setInterpolator(CubicBezierInterpolator.EASE_OUT).setListener(new AnimatorListenerAdapter() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animation) {
|
||||||
|
if (updateLayout.getTag() == null) {
|
||||||
|
updateLayout.setVisibility(View.INVISIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).setDuration(180).start();
|
||||||
|
} else {
|
||||||
|
updateLayout.setTranslationY(AndroidUtilities.dp(44));
|
||||||
|
updateLayout.setVisibility(View.INVISIBLE);
|
||||||
|
}
|
||||||
|
sideMenu.setPadding(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkAppUpdate(boolean force) {
|
||||||
|
if (BuildVars.isFdroid || BuildVars.isPlay) return;
|
||||||
|
if (NekoXConfig.autoUpdateReleaseChannel == 0) return;
|
||||||
|
if (!force && System.currentTimeMillis() < SharedConfig.lastUpdateCheckTime + 1000L * 60 * 60) return;
|
||||||
|
SharedConfig.lastUpdateCheckTime = System.currentTimeMillis();
|
||||||
|
SharedConfig.saveConfig();
|
||||||
|
FileLog.d("checking update");
|
||||||
|
|
||||||
|
final int accountNum = currentAccount;
|
||||||
|
InternalUpdater.checkUpdate((res, error) -> AndroidUtilities.runOnUIThread(() -> {
|
||||||
|
if (res != null) {
|
||||||
|
SharedConfig.setNewAppVersionAvailable(res);
|
||||||
|
if (res.can_not_skip) {
|
||||||
|
showUpdateActivity(accountNum, res, false);
|
||||||
|
} else {
|
||||||
|
drawerLayoutAdapter.notifyDataSetChanged();
|
||||||
|
try {
|
||||||
|
(new UpdateAppAlertDialog(LaunchActivity.this, res, accountNum)).show();
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (force) {
|
||||||
|
if (error)
|
||||||
|
Toast.makeText(LaunchActivity.this, LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred), Toast.LENGTH_SHORT).show();
|
||||||
|
else
|
||||||
|
Toast.makeText(LaunchActivity.this, LocaleController.getString("VersionUpdateNoUpdate", R.string.VersionUpdateNoUpdate), Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
SharedConfig.setNewAppVersionAvailable(null);
|
||||||
|
drawerLayoutAdapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.appUpdateAvailable);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
public AlertDialog showAlertDialog(AlertDialog.Builder builder) {
|
public AlertDialog showAlertDialog(AlertDialog.Builder builder) {
|
||||||
try {
|
try {
|
||||||
if (visibleDialog != null) {
|
if (visibleDialog != null) {
|
||||||
|
@ -4282,6 +4489,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
||||||
} else if (SharedConfig.pendingAppUpdate != null && SharedConfig.pendingAppUpdate.can_not_skip) {
|
} else if (SharedConfig.pendingAppUpdate != null && SharedConfig.pendingAppUpdate.can_not_skip) {
|
||||||
showUpdateActivity(UserConfig.selectedAccount, SharedConfig.pendingAppUpdate, true);
|
showUpdateActivity(UserConfig.selectedAccount, SharedConfig.pendingAppUpdate, true);
|
||||||
}
|
}
|
||||||
|
checkAppUpdate(false);
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
ApplicationLoader.canDrawOverlays = Settings.canDrawOverlays(this);
|
ApplicationLoader.canDrawOverlays = Settings.canDrawOverlays(this);
|
||||||
|
@ -4597,6 +4805,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
||||||
if (SharedConfig.isAppUpdateAvailable()) {
|
if (SharedConfig.isAppUpdateAvailable()) {
|
||||||
String name = FileLoader.getAttachFileName(SharedConfig.pendingAppUpdate.document);
|
String name = FileLoader.getAttachFileName(SharedConfig.pendingAppUpdate.document);
|
||||||
if (name.equals(path)) {
|
if (name.equals(path)) {
|
||||||
|
updateAppUpdateViews(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (loadingThemeFileName != null) {
|
if (loadingThemeFileName != null) {
|
||||||
|
@ -4667,6 +4876,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
||||||
if (SharedConfig.isAppUpdateAvailable()) {
|
if (SharedConfig.isAppUpdateAvailable()) {
|
||||||
String name = FileLoader.getAttachFileName(SharedConfig.pendingAppUpdate.document);
|
String name = FileLoader.getAttachFileName(SharedConfig.pendingAppUpdate.document);
|
||||||
if (name.equals(path)) {
|
if (name.equals(path)) {
|
||||||
|
updateAppUpdateViews(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (id == NotificationCenter.screenStateChanged) {
|
} else if (id == NotificationCenter.screenStateChanged) {
|
||||||
|
@ -4741,6 +4951,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (id == NotificationCenter.appUpdateAvailable) {
|
} else if (id == NotificationCenter.appUpdateAvailable) {
|
||||||
|
updateAppUpdateViews(mainFragmentsStack.size() == 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3007,7 +3007,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter.
|
||||||
|
|
||||||
if (!BuildVars.isFdroid && !BuildVars.isPlay) {
|
if (!BuildVars.isFdroid && !BuildVars.isPlay) {
|
||||||
builder.addItem(LocaleController.getString("CheckUpdate", R.string.CheckUpdate), R.drawable.baseline_search_24, (it) -> {
|
builder.addItem(LocaleController.getString("CheckUpdate", R.string.CheckUpdate), R.drawable.baseline_search_24, (it) -> {
|
||||||
UIUtil.runOnIoDispatcher(() -> InternalUpdater.checkUpdate(getParentActivity(), false));
|
Browser.openUrl(context, "tg://update");
|
||||||
return Unit.INSTANCE;
|
return Unit.INSTANCE;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -3022,6 +3022,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter.
|
||||||
case 2:
|
case 2:
|
||||||
currentChannel += LocaleController.getString("AutoCheckUpdateRc", R.string.AutoCheckUpdateRc);
|
currentChannel += LocaleController.getString("AutoCheckUpdateRc", R.string.AutoCheckUpdateRc);
|
||||||
break;
|
break;
|
||||||
|
case 3:
|
||||||
|
currentChannel += LocaleController.getString("AutoCheckUpdatePreview", R.string.AutoCheckUpdatePreview);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.addItem(LocaleController.getString("AutoCheckUpdateSwitch", R.string.AutoCheckUpdateSwitch) + currentChannel, R.drawable.update_black_24, (it) -> {
|
builder.addItem(LocaleController.getString("AutoCheckUpdateSwitch", R.string.AutoCheckUpdateSwitch) + currentChannel, R.drawable.update_black_24, (it) -> {
|
||||||
|
@ -3042,6 +3045,11 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter.
|
||||||
switchBuilder.doRadioCheck(radioButtonCell);
|
switchBuilder.doRadioCheck(radioButtonCell);
|
||||||
return Unit.INSTANCE;
|
return Unit.INSTANCE;
|
||||||
});
|
});
|
||||||
|
switchBuilder.addRadioItem(LocaleController.getString("AutoCheckUpdatePreview", R.string.AutoCheckUpdatePreview), NekoXConfig.autoUpdateReleaseChannel == 3, (radioButtonCell) -> {
|
||||||
|
NekoXConfig.setAutoUpdateReleaseChannel(3);
|
||||||
|
switchBuilder.doRadioCheck(radioButtonCell);
|
||||||
|
return Unit.INSTANCE;
|
||||||
|
});
|
||||||
showDialog(switchBuilder.create());
|
showDialog(switchBuilder.create());
|
||||||
return Unit.INSTANCE;
|
return Unit.INSTANCE;
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,186 +1,216 @@
|
||||||
package tw.nekomimi.nekogram;
|
package tw.nekomimi.nekogram;
|
||||||
|
|
||||||
import static org.telegram.ui.Components.BlockingUpdateView.checkApkInstallPermissions;
|
import org.telegram.messenger.AccountInstance;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import androidx.core.content.FileProvider;
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
|
|
||||||
import org.telegram.messenger.AndroidUtilities;
|
|
||||||
import org.telegram.messenger.ApplicationLoader;
|
|
||||||
import org.telegram.messenger.BuildConfig;
|
import org.telegram.messenger.BuildConfig;
|
||||||
import org.telegram.messenger.BuildVars;
|
import org.telegram.messenger.BuildVars;
|
||||||
import org.telegram.messenger.FileLog;
|
import org.telegram.messenger.FileLog;
|
||||||
import org.telegram.messenger.LocaleController;
|
import org.telegram.messenger.UserConfig;
|
||||||
import org.telegram.messenger.R;
|
import org.telegram.tgnet.TLRPC;
|
||||||
import org.telegram.messenger.browser.Browser;
|
import org.webrtc.EglBase;
|
||||||
import org.telegram.ui.ActionBar.AlertDialog;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.util.ArrayList;
|
||||||
import java.text.SimpleDateFormat;
|
import java.util.Collections;
|
||||||
import java.util.Locale;
|
import java.util.List;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import cn.hutool.http.HttpRequest;
|
|
||||||
import tw.nekomimi.nekogram.utils.FileUtil;
|
import tw.nekomimi.nekogram.utils.FileUtil;
|
||||||
|
|
||||||
//TODO use UpdateAppAlertDialog / BlockingUpdateView?
|
//TODO use UpdateAppAlertDialog / BlockingUpdateView?
|
||||||
|
|
||||||
public class InternalUpdater {
|
public class InternalUpdater {
|
||||||
private static final String API_URL_RELEASE = "https://api.github.com/repos/NekoX-Dev/NekoX/releases?per_page=10";
|
|
||||||
|
|
||||||
private static class ReleaseMetadata {
|
static final int UPDATE_METADATA_START_FROM = 0;
|
||||||
String name;
|
static final int MAX_READ_COUNT = 20;
|
||||||
String body;
|
static final long CHANNEL_METADATA_ID = 1359638116;
|
||||||
String published_at;
|
static final String CHANNEL_METADATA_NAME = "nekox_update_metadata";
|
||||||
String html_url;
|
static final long CHANNEL_APKS_ID = 1137038259;
|
||||||
ApkMetadata[] assets;
|
static final String CHANNEL_APKS_NAME = "NekoXApks";
|
||||||
}
|
|
||||||
|
|
||||||
private static class ApkMetadata {
|
static void retrieveUpdateMetadata(retrieveUpdateMetadataCallback callback) {
|
||||||
String name;
|
final int localVersionCode = BuildVars.BUILD_VERSION;
|
||||||
String browser_download_url;
|
AccountInstance accountInstance = AccountInstance.getInstance(UserConfig.selectedAccount);
|
||||||
}
|
TLRPC.TL_messages_getHistory req = new TLRPC.TL_messages_getHistory();
|
||||||
|
req.peer = accountInstance.getMessagesController().getInputPeer(-CHANNEL_METADATA_ID);
|
||||||
private static class GithubApiContents {
|
req.offset_id = 0;
|
||||||
String content;
|
req.limit = MAX_READ_COUNT;
|
||||||
}
|
Runnable sendReq = () -> accountInstance.getConnectionsManager().sendRequest(req, (response, error) -> {
|
||||||
|
if (error != null) {
|
||||||
// as a base64 encoded json
|
FileLog.e("Error when retrieving update metadata from channel " + error);
|
||||||
private static class NekoXReleaseNote {
|
callback.apply(null, true);
|
||||||
NekoXAPK[] apks;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
private static class NekoXAPK {
|
|
||||||
String name;
|
|
||||||
String sha1;
|
|
||||||
String[] urls; // https://t.me/xxx or bdex://xxx, bdex removed
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ApkMetadata matchBuild(ApkMetadata[] apks) {
|
|
||||||
String target = BuildConfig.FLAVOR + "-" + FileUtil.getAbi() + "-" + BuildConfig.BUILD_TYPE + ".apk";
|
|
||||||
FileLog.e(target);
|
|
||||||
for (ApkMetadata apk : apks) {
|
|
||||||
if (apk.name.contains(target))
|
|
||||||
return apk;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void checkUpdate(Context ctx, boolean isAutoCheck) {
|
|
||||||
if (BuildVars.isFdroid)
|
|
||||||
return;
|
|
||||||
|
|
||||||
//cleanup
|
|
||||||
File f = new File(ApplicationLoader.getDataDirFixed(), "cache/new.apk");
|
|
||||||
if (f.exists()) f.delete();
|
|
||||||
|
|
||||||
try {
|
|
||||||
NekoXConfig.setNextUpdateCheck(System.currentTimeMillis() / 1000 + 24 * 3600);
|
|
||||||
|
|
||||||
//TODO update URL when api.github.com get banned.
|
|
||||||
String ret = HttpRequest.get(API_URL_RELEASE).header("accept", "application/vnd.github.v3+json").execute().body();
|
|
||||||
ReleaseMetadata[] releases = new Gson().fromJson(ret, ReleaseMetadata[].class);
|
|
||||||
ReleaseMetadata release = null;
|
|
||||||
|
|
||||||
// Not now.
|
|
||||||
String releaseChannel = "stable";
|
|
||||||
switch (NekoXConfig.autoUpdateReleaseChannel) {
|
|
||||||
case 2:
|
|
||||||
releaseChannel = "rc";
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
releaseChannel = "preview";
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
TLRPC.messages_Messages res = (TLRPC.messages_Messages) response;
|
||||||
for (ReleaseMetadata rel : releases) {
|
List<UpdateMetadata> metas = new ArrayList<>();
|
||||||
if (rel.name.equals("v" + BuildConfig.VERSION_NAME))
|
for (TLRPC.Message message : res.messages) {
|
||||||
break;
|
if (!(message instanceof TLRPC.TL_message)) continue;
|
||||||
if (rel.name.contains("rc") && NekoXConfig.autoUpdateReleaseChannel < 2 || rel.name.contains("preview") && NekoXConfig.autoUpdateReleaseChannel < 3)
|
if (!message.message.startsWith("v")) continue;
|
||||||
|
String[] split = message.message.split(",");
|
||||||
|
if (split.length < 4) continue;
|
||||||
|
UpdateMetadata metaData = new UpdateMetadata(message.id, split);
|
||||||
|
metas.add(metaData);
|
||||||
|
}
|
||||||
|
Collections.sort(metas, (o1, o2) -> o2.versionCode - o1.versionCode); // versionCode Desc
|
||||||
|
UpdateMetadata found = null;
|
||||||
|
for (UpdateMetadata metaData : metas) {
|
||||||
|
if (metaData.versionCode <= localVersionCode) break;
|
||||||
|
if (NekoXConfig.autoUpdateReleaseChannel < 3 && metaData.versionName.contains("preview"))
|
||||||
continue;
|
continue;
|
||||||
release = rel;
|
if (NekoXConfig.autoUpdateReleaseChannel < 2 && metaData.versionName.contains("rc"))
|
||||||
|
continue;
|
||||||
|
found = metaData;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (release == null) {
|
if (found != null) {
|
||||||
FileLog.d("no update");
|
for (TLRPC.Message message : res.messages) {
|
||||||
if (!isAutoCheck)
|
if (!(message instanceof TLRPC.TL_message)) continue;
|
||||||
AndroidUtilities.runOnUIThread(() -> Toast.makeText(ctx, LocaleController.getString("VersionUpdateNoUpdate", R.string.VersionUpdateNoUpdate), Toast.LENGTH_SHORT).show());
|
if (message.id == found.UpdateLogMessageID) {
|
||||||
return;
|
found.updateLog = message.message;
|
||||||
} else if (release.name.equals(NekoXConfig.ignoredUpdateTag) && isAutoCheck) {
|
found.updateLogEntities = message.entities;
|
||||||
FileLog.d("ignored tag " + release.name);
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found == null) {
|
||||||
|
FileLog.d("Cannot find Update Metadata");
|
||||||
|
callback.apply(null, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
FileLog.w("Found Update Metadata " + found.versionName + " " + found.versionCode);
|
||||||
// match release apk urls
|
callback.apply(found, false);
|
||||||
final ApkMetadata apk = matchBuild(release.assets);
|
});
|
||||||
|
if (req.peer.access_hash != 0) sendReq.run();
|
||||||
// match apk urls. these can be empty.
|
else {
|
||||||
|
TLRPC.TL_contacts_resolveUsername resolve = new TLRPC.TL_contacts_resolveUsername();
|
||||||
ReleaseMetadata finalRelease = release;
|
resolve.username = CHANNEL_METADATA_NAME;
|
||||||
|
accountInstance.getConnectionsManager().sendRequest(resolve, (response1, error1) -> {
|
||||||
AndroidUtilities.runOnUIThread(() -> {
|
if (error1 != null) {
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
|
FileLog.e("Error when checking update, unable to resolve metadata channel " + error1.text);
|
||||||
builder.setTitle(LocaleController.getString("VersionUpdateTitle", R.string.VersionUpdateTitle));
|
callback.apply(null, true);
|
||||||
|
return;
|
||||||
String message = null;
|
|
||||||
try {
|
|
||||||
message = finalRelease.name + " " + LocaleController.formatDateChat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US).parse(finalRelease.published_at).getTime() / 1000) + "\n\n";
|
|
||||||
} catch (Exception e) {
|
|
||||||
FileLog.e(e);
|
|
||||||
}
|
}
|
||||||
if (apk == null)
|
if (!(response1 instanceof TLRPC.TL_contacts_resolvedPeer)) {
|
||||||
message += LocaleController.getString("VersionUpdateVariantNotMatch", R.string.VersionUpdateVariantNotMatch);
|
FileLog.e("Error when checking update, unable to resolve metadata channel, unexpected responseType " + response1.getClass().getName());
|
||||||
else
|
callback.apply(null, true);
|
||||||
message += apk.name.replace(".apk", "");
|
return;
|
||||||
builder.setMessage(message);
|
}
|
||||||
|
TLRPC.TL_contacts_resolvedPeer resolvedPeer = (TLRPC.TL_contacts_resolvedPeer) response1;
|
||||||
builder.setPositiveButton(LocaleController.getString("VersionUpdateConfirm", R.string.VersionUpdateConfirm), (dialog, which) -> {
|
accountInstance.getMessagesController().putUsers(resolvedPeer.users, false);
|
||||||
Browser.openUrl(ctx, apk.browser_download_url);
|
accountInstance.getMessagesController().putChats(resolvedPeer.chats, false);
|
||||||
});
|
accountInstance.getMessagesStorage().putUsersAndChats(resolvedPeer.users, resolvedPeer.chats, false, true);
|
||||||
builder.setNeutralButton(LocaleController.getString("VersionUpdateIgnore", R.string.VersionUpdateIgnore), (dialog, which) -> NekoXConfig.setIgnoredUpdateTag(finalRelease.name));
|
if ((resolvedPeer.chats == null || resolvedPeer.chats.size() == 0)) {
|
||||||
builder.setNegativeButton(LocaleController.getString("VersionUpdateNotNow", R.string.VersionUpdateNotNow), (dialog, which) -> NekoXConfig.setNextUpdateCheck(System.currentTimeMillis() / 1000 + 3 * 24 * 3600));
|
FileLog.e("Error when checking update, unable to resolve metadata channel, unexpected resolvedChat ");
|
||||||
builder.show();
|
callback.apply(null, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
req.peer = new TLRPC.TL_inputPeerChannel();
|
||||||
|
req.peer.channel_id = resolvedPeer.chats.get(0).id;
|
||||||
|
req.peer.access_hash = resolvedPeer.chats.get(0).access_hash;
|
||||||
|
sendReq.run();
|
||||||
});
|
});
|
||||||
} catch (Exception e) {
|
|
||||||
FileLog.e(e);
|
|
||||||
if (!isAutoCheck)
|
|
||||||
AndroidUtilities.runOnUIThread(() -> Toast.makeText(ctx, "An exception occurred during checking updates.", Toast.LENGTH_SHORT).show());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean openApkInstall(Activity activity, File f) {
|
public static void checkUpdate(checkUpdateCallback callback) {
|
||||||
if (!checkApkInstallPermissions(activity)) {
|
AccountInstance accountInstance = AccountInstance.getInstance(UserConfig.selectedAccount);
|
||||||
return false;
|
retrieveUpdateMetadata((metadata, err) -> {
|
||||||
}
|
if (metadata == null) {
|
||||||
|
callback.apply(null, err);
|
||||||
boolean exists = false;
|
return;
|
||||||
try {
|
|
||||||
if (exists = f.exists()) {
|
|
||||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
|
||||||
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= 24) {
|
|
||||||
intent.setDataAndType(FileProvider.getUriForFile(activity, BuildConfig.APPLICATION_ID + ".provider", f), "application/vnd.android.package-archive");
|
|
||||||
} else {
|
|
||||||
intent.setDataAndType(Uri.fromFile(f), "application/vnd.android.package-archive");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
activity.startActivityForResult(intent, 500);
|
|
||||||
} catch (Exception e) {
|
|
||||||
FileLog.e(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
TLRPC.TL_messages_getHistory req = new TLRPC.TL_messages_getHistory();
|
||||||
FileLog.e(e);
|
req.peer = accountInstance.getMessagesController().getInputPeer(-CHANNEL_APKS_ID);
|
||||||
|
req.offset_id = metadata.apkChannelMessageID;
|
||||||
|
req.limit = MAX_READ_COUNT;
|
||||||
|
|
||||||
|
Runnable sendReq = () -> accountInstance.getConnectionsManager().sendRequest(req, (response, error) -> {
|
||||||
|
if (error != null) {
|
||||||
|
FileLog.e("Error when getting update document " + error.text);
|
||||||
|
callback.apply(null, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TLRPC.messages_Messages res = (TLRPC.messages_Messages) response;
|
||||||
|
FileLog.d("Retrieve update messages, size:" + res.messages.size());
|
||||||
|
final String target = BuildConfig.FLAVOR + "-" + FileUtil.getAbi() + "-" + ("debug".equals(BuildConfig.BUILD_TYPE) ? "release" : BuildConfig.BUILD_TYPE) + ".apk";
|
||||||
|
for (int i = 0; i < res.messages.size(); i++) {
|
||||||
|
if (res.messages.get(i).media == null) continue;
|
||||||
|
|
||||||
|
TLRPC.Document apkDocument = res.messages.get(i).media.document;
|
||||||
|
String fileName = apkDocument.attributes.size() == 0 ? "" : apkDocument.attributes.get(0).file_name;
|
||||||
|
if (!(fileName.contains(target) && fileName.contains(metadata.versionName) ))
|
||||||
|
continue;
|
||||||
|
TLRPC.TL_help_appUpdate update = new TLRPC.TL_help_appUpdate();
|
||||||
|
update.version = metadata.versionName;
|
||||||
|
update.document = apkDocument;
|
||||||
|
update.can_not_skip = false;
|
||||||
|
update.flags |= 2;
|
||||||
|
if (metadata.updateLog != null) {
|
||||||
|
update.text = metadata.updateLog;
|
||||||
|
update.entities = metadata.updateLogEntities;
|
||||||
|
}
|
||||||
|
callback.apply(update, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
callback.apply(null, false);
|
||||||
|
});
|
||||||
|
if (req.peer.access_hash != 0) sendReq.run();
|
||||||
|
else {
|
||||||
|
TLRPC.TL_contacts_resolveUsername resolve = new TLRPC.TL_contacts_resolveUsername();
|
||||||
|
resolve.username = CHANNEL_APKS_NAME;
|
||||||
|
accountInstance.getConnectionsManager().sendRequest(resolve, (response1, error1) -> {
|
||||||
|
if (error1 != null) {
|
||||||
|
FileLog.e("Error when checking update, unable to resolve metadata channel " + error1);
|
||||||
|
callback.apply(null, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!(response1 instanceof TLRPC.TL_contacts_resolvedPeer)) {
|
||||||
|
FileLog.e("Error when checking update, unable to resolve metadata channel, unexpected responseType " + response1.getClass().getName());
|
||||||
|
callback.apply(null, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TLRPC.TL_contacts_resolvedPeer resolvedPeer = (TLRPC.TL_contacts_resolvedPeer) response1;
|
||||||
|
accountInstance.getMessagesController().putUsers(resolvedPeer.users, false);
|
||||||
|
accountInstance.getMessagesController().putChats(resolvedPeer.chats, false);
|
||||||
|
accountInstance.getMessagesStorage().putUsersAndChats(resolvedPeer.users, resolvedPeer.chats, false, true);
|
||||||
|
if ((resolvedPeer.chats == null || resolvedPeer.chats.size() == 0)) {
|
||||||
|
FileLog.e("Error when checking update, unable to resolve metadata channel, unexpected resolvedChat ");
|
||||||
|
callback.apply(null, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
req.peer = new TLRPC.TL_inputPeerChannel();
|
||||||
|
req.peer.channel_id = resolvedPeer.chats.get(0).id;
|
||||||
|
req.peer.access_hash = resolvedPeer.chats.get(0).access_hash;
|
||||||
|
sendReq.run();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface retrieveUpdateMetadataCallback {
|
||||||
|
void apply(UpdateMetadata metadata, boolean error);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface checkUpdateCallback {
|
||||||
|
void apply(TLRPC.TL_help_appUpdate resp, boolean error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class UpdateMetadata {
|
||||||
|
int messageID;
|
||||||
|
String versionName;
|
||||||
|
int versionCode;
|
||||||
|
int apkChannelMessageID;
|
||||||
|
int UpdateLogMessageID;
|
||||||
|
String updateLog = null;
|
||||||
|
ArrayList<TLRPC.MessageEntity> updateLogEntities = null;
|
||||||
|
|
||||||
|
UpdateMetadata(int messageID, String[] split) {
|
||||||
|
this.messageID = messageID;
|
||||||
|
versionName = split[0];
|
||||||
|
versionCode = Integer.parseInt(split[1]);
|
||||||
|
apkChannelMessageID = Integer.parseInt(split[2]);
|
||||||
|
UpdateLogMessageID = Integer.parseInt(split[3]);
|
||||||
}
|
}
|
||||||
return exists;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -82,7 +82,7 @@ public class NekoXConfig {
|
||||||
|
|
||||||
public static int autoUpdateReleaseChannel = preferences.getInt("autoUpdateReleaseChannel", 2);
|
public static int autoUpdateReleaseChannel = preferences.getInt("autoUpdateReleaseChannel", 2);
|
||||||
public static String ignoredUpdateTag = preferences.getString("ignoredUpdateTag", "");
|
public static String ignoredUpdateTag = preferences.getString("ignoredUpdateTag", "");
|
||||||
public static long nextUpdateCheck = preferences.getLong("nextUpdateCheckTimestamp", 0);
|
// public static long nextUpdateCheck = preferences.getLong("nextUpdateCheckTimestamp", 0);
|
||||||
|
|
||||||
// public static int customApi = preferences.getInt("custom_api", 0);
|
// public static int customApi = preferences.getInt("custom_api", 0);
|
||||||
// public static int customAppId = preferences.getInt("custom_app_id", 0);
|
// public static int customAppId = preferences.getInt("custom_app_id", 0);
|
||||||
|
@ -135,9 +135,9 @@ public class NekoXConfig {
|
||||||
return BuildConfig.APP_HASH;
|
return BuildConfig.APP_HASH;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setNextUpdateCheck(long timestamp) {
|
// public static void setNextUpdateCheck(long timestamp) {
|
||||||
preferences.edit().putLong("nextUpdateCheckTimestamp", nextUpdateCheck = timestamp).apply();
|
// preferences.edit().putLong("nextUpdateCheckTimestamp", nextUpdateCheck = timestamp).apply();
|
||||||
}
|
// }
|
||||||
|
|
||||||
public static boolean isDeveloper() {
|
public static boolean isDeveloper() {
|
||||||
if (hasDeveloper != null)
|
if (hasDeveloper != null)
|
||||||
|
|
|
@ -247,6 +247,7 @@
|
||||||
<string name="AutoCheckUpdateSwitch">Automatic Update</string>
|
<string name="AutoCheckUpdateSwitch">Automatic Update</string>
|
||||||
<string name="AutoCheckUpdateStable">Stable</string>
|
<string name="AutoCheckUpdateStable">Stable</string>
|
||||||
<string name="AutoCheckUpdateRc">Release Candidate</string>
|
<string name="AutoCheckUpdateRc">Release Candidate</string>
|
||||||
|
<string name="AutoCheckUpdatePreview">Preview (Unstable)</string>
|
||||||
<string name="unreadBadgeOnBackButton">Unread badge on back button</string>
|
<string name="unreadBadgeOnBackButton">Unread badge on back button</string>
|
||||||
<string name="customPublicProxyIP">Set IP of public proxy</string>
|
<string name="customPublicProxyIP">Set IP of public proxy</string>
|
||||||
<string name="customPublicProxyIPNotice">In some areas, specifying the IP of public proxy CDN(eg. Cloudflare) can speed up access.</string>
|
<string name="customPublicProxyIPNotice">In some areas, specifying the IP of public proxy CDN(eg. Cloudflare) can speed up access.</string>
|
||||||
|
@ -263,4 +264,6 @@
|
||||||
<string name="rememberAllBackMessages">Remember all clicked replies</string>
|
<string name="rememberAllBackMessages">Remember all clicked replies</string>
|
||||||
<string name="DisableInstantCamera">Disable instant camera</string>
|
<string name="DisableInstantCamera">Disable instant camera</string>
|
||||||
<string name="showSeconds">Show timestamp in seconds</string>
|
<string name="showSeconds">Show timestamp in seconds</string>
|
||||||
|
<string name="AppUpdateNekoX">Update Nekogram X</string>
|
||||||
|
<string name="NekoXUpdateTranslationHint">Press to translate the change log</string>
|
||||||
</resources>
|
</resources>
|
Loading…
Reference in New Issue