From eecfb85a954e2a15183f1f1e636e83dd20facd2b Mon Sep 17 00:00:00 2001 From: AbdulKus <73951988+AbdulKus@users.noreply.github.com> Date: Tue, 11 Aug 2026 14:50:29 +0300 Subject: [PATCH 1/2] Add personal video calls --- app/jni/tgvoip/tgvoip.cpp | 97 +- app/src/main/AndroidManifest.xml | 6 +- .../messenger/voip/VideoCameraCapturer.java | 212 ++ .../thunderdog/challegram/MainActivity.java | 19 + .../java/org/thunderdog/challegram/U.java | 7 + .../challegram/service/TGCallService.java | 110 +- .../challegram/telegram/CallManager.java | 80 +- .../challegram/ui/CallController.java | 283 +- .../challegram/ui/ProfileController.java | 228 +- .../challegram/voip/CallConfiguration.java | 3 + .../challegram/voip/TgCallsController.java | 50 + .../org/thunderdog/challegram/voip/VoIP.java | 7 + .../challegram/voip/VoIPInstance.java | 21 + .../main/res/values-ru/frogram_strings.xml | 7 + app/src/main/res/values/ids.xml | 3 + app/src/main/res/values/local_strings.xml | 10 +- app/src/main/res/values/strings.xml | 2483 +---------------- 17 files changed, 899 insertions(+), 2727 deletions(-) create mode 100644 app/src/main/java/org/telegram/messenger/voip/VideoCameraCapturer.java diff --git a/app/jni/tgvoip/tgvoip.cpp b/app/jni/tgvoip/tgvoip.cpp index afdde5731b..33342cf88c 100644 --- a/app/jni/tgvoip/tgvoip.cpp +++ b/app/jni/tgvoip/tgvoip.cpp @@ -34,6 +34,7 @@ #include #include +#include #include #include @@ -405,6 +406,11 @@ class JniWrapper { struct TgCallsContext { std::unique_ptr tgcalls; std::shared_ptr javaController; + std::shared_ptr videoCapture; + std::shared_ptr> localVideoSink; + std::shared_ptr> remoteVideoSink; + bool videoEnabled = false; + bool frontCamera = true; }; jbyteArray toJavaByteArray (JNIEnv *env, const std::vector &data) { @@ -464,6 +470,7 @@ JNI_OBJECT_FUNC(jlong, voip_TgCallsController, newInstance, env->ReleaseByteArrayElements(jEncryptionKey, (jbyte *) jEncryptionKeyData, JNI_ABORT); bool isOutgoingCall = configuration.getBoolean("isOutgoing") == JNI_TRUE; + bool isVideoCall = configuration.getBoolean("isVideo") == JNI_TRUE; // tgcalls::Endpoint @@ -579,6 +586,16 @@ JNI_OBJECT_FUNC(jlong, voip_TgCallsController, newInstance, std::shared_ptr javaController = std::make_shared(env, thiz, tgcalls::javaTgCallsController); + auto videoPlatformContext = std::make_shared(env); + std::shared_ptr videoCapture = + tgcalls::VideoCaptureInterface::Create( + tgcalls::StaticThreads::getThreads(), + "front", + false, + videoPlatformContext + ); + videoCapture->setState(isVideoCall ? tgcalls::VideoState::Active : tgcalls::VideoState::Inactive); + tgcalls::Descriptor descriptor = { .version = version, .config = tgcalls::Config { @@ -612,7 +629,7 @@ JNI_OBJECT_FUNC(jlong, voip_TgCallsController, newInstance, std::move(encryptionKey), isOutgoingCall ), - .videoCapture = nullptr, + .videoCapture = isVideoCall ? videoCapture : nullptr, .stateUpdated = [javaController](tgcalls::State state) { javaController->runSafely([javaController, state](JNIEnv *env) { jint javaState = toJavaCallState(env, state); @@ -667,6 +684,8 @@ JNI_OBJECT_FUNC(jlong, voip_TgCallsController, newInstance, auto *context = new TgCallsContext; context->javaController = javaController; + context->videoCapture = videoCapture; + context->videoEnabled = isVideoCall; context->tgcalls = tgcalls::Meta::Create(version, std::move(descriptor)); context->tgcalls->setNetworkType(networkType); context->tgcalls->setAudioOutputGainControlEnabled(audioOutputGainControlEnabled); @@ -749,6 +768,80 @@ JNI_OBJECT_FUNC(void, voip_TgCallsController, updateAudioOutputGainControlEnable } } +JNI_OBJECT_FUNC(jboolean, voip_TgCallsController, nativeSupportsVideo, jlong ptr) { + auto context = jni::jlong_to_ptr(ptr); + return context != nullptr && context->tgcalls != nullptr && context->tgcalls->supportsVideo() + ? JNI_TRUE + : JNI_FALSE; +} + +JNI_OBJECT_FUNC(void, voip_TgCallsController, nativeSetVideoEnabled, jlong ptr, jboolean jEnabled) { + auto context = jni::jlong_to_ptr(ptr); + if (context == nullptr || context->tgcalls == nullptr || context->videoCapture == nullptr) { + return; + } + bool enabled = jEnabled == JNI_TRUE; + if (context->videoEnabled == enabled) { + return; + } + context->videoEnabled = enabled; + if (enabled) { + context->videoCapture->setState(tgcalls::VideoState::Active); + context->tgcalls->setVideoCapture(context->videoCapture); + } else { + context->tgcalls->setVideoCapture(nullptr); + context->videoCapture->setState(tgcalls::VideoState::Inactive); + } +} + +JNI_OBJECT_FUNC(void, voip_TgCallsController, nativeSetVideoPaused, jlong ptr, jboolean jPaused) { + auto context = jni::jlong_to_ptr(ptr); + if (context == nullptr || context->videoCapture == nullptr || !context->videoEnabled) { + return; + } + context->videoCapture->setState( + jPaused == JNI_TRUE ? tgcalls::VideoState::Paused : tgcalls::VideoState::Active + ); +} + +JNI_OBJECT_FUNC(void, voip_TgCallsController, nativeSwitchCamera, jlong ptr) { + auto context = jni::jlong_to_ptr(ptr); + if (context == nullptr || context->videoCapture == nullptr) { + return; + } + context->frontCamera = !context->frontCamera; + context->videoCapture->switchToDevice(context->frontCamera ? "front" : "back", false); + context->videoCapture->setState( + context->videoEnabled ? tgcalls::VideoState::Active : tgcalls::VideoState::Inactive + ); +} + +JNI_OBJECT_FUNC(void, voip_TgCallsController, nativeSetLocalVideoOutput, jlong ptr, jobject jSink) { + auto context = jni::jlong_to_ptr(ptr); + if (context == nullptr || context->videoCapture == nullptr) { + return; + } + context->localVideoSink = jSink != nullptr + ? std::shared_ptr>( + webrtc::JavaToNativeVideoSink(env, jSink) + ) + : nullptr; + context->videoCapture->setOutput(context->localVideoSink); +} + +JNI_OBJECT_FUNC(void, voip_TgCallsController, nativeSetRemoteVideoOutput, jlong ptr, jobject jSink) { + auto context = jni::jlong_to_ptr(ptr); + if (context == nullptr || context->tgcalls == nullptr) { + return; + } + context->remoteVideoSink = jSink != nullptr + ? std::shared_ptr>( + webrtc::JavaToNativeVideoSink(env, jSink) + ) + : nullptr; + context->tgcalls->setIncomingVideoOutput(context->remoteVideoSink); +} + JNI_OBJECT_FUNC(void, voip_TgCallsController, fetchNetworkStats, jlong ptr, jobject jOutStats) { auto context = jni::jlong_to_ptr(ptr); if (context != nullptr && context->tgcalls != nullptr) { @@ -868,4 +961,4 @@ jint JNI_OnLoad (JavaVM *vm, void *reserved) { return JNI_VERSION_1_6; } -} \ No newline at end of file +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index fab8a54671..77225beecf 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -67,6 +67,7 @@ + + android:foregroundServiceType="phoneCall|microphone|camera|mediaPlayback" /> @@ -352,6 +353,7 @@ android:name=".MainActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout|locale|layoutDirection|uiMode" android:launchMode="singleTask" + android:supportsPictureInPicture="true" android:windowSoftInputMode="stateHidden|adjustPan" android:exported="true"> @@ -457,4 +459,4 @@ android:name="com.google.android.gms.car.application" android:resource="@xml/automotive_app_desc"/> - \ No newline at end of file + diff --git a/app/src/main/java/org/telegram/messenger/voip/VideoCameraCapturer.java b/app/src/main/java/org/telegram/messenger/voip/VideoCameraCapturer.java new file mode 100644 index 0000000000..0c1bfbb929 --- /dev/null +++ b/app/src/main/java/org/telegram/messenger/voip/VideoCameraCapturer.java @@ -0,0 +1,212 @@ +/* + * This file is a part of Frogram X. + * + * It bridges Telegram's tgcalls Android video source to the WebRTC camera + * implementation bundled with the application. + */ +package org.telegram.messenger.voip; + +import android.content.Context; + +import androidx.annotation.Keep; + +import org.thunderdog.challegram.Log; +import org.webrtc.Camera1Enumerator; +import org.webrtc.Camera2Enumerator; +import org.webrtc.CameraEnumerator; +import org.webrtc.CameraVideoCapturer; +import org.webrtc.CapturerObserver; +import org.webrtc.ContextUtils; +import org.webrtc.SurfaceTextureHelper; + +@Keep +public final class VideoCameraCapturer { + private static final int VIDEO_STATE_INACTIVE = 0; + private static final int VIDEO_STATE_PAUSED = 1; + private static final int VIDEO_STATE_ACTIVE = 2; + + private static final int CAPTURE_WIDTH = 1280; + private static final int CAPTURE_HEIGHT = 720; + private static final int CAPTURE_FPS = 30; + + private long nativePtr; + private boolean useFrontCamera = true; + private boolean started; + private boolean destroyed; + private int requestedState = VIDEO_STATE_INACTIVE; + + private CameraVideoCapturer capturer; + private SurfaceTextureHelper surfaceTextureHelper; + + @Keep + public VideoCameraCapturer () { } + + @Keep + private synchronized void init (long nativePtr, boolean useFrontCamera) { + if (destroyed) { + return; + } + stopAndDisposeCapturer(); + this.nativePtr = nativePtr; + this.useFrontCamera = useFrontCamera; + + Context context = ContextUtils.getApplicationContext(); + if (context == null) { + Log.e(Log.TAG_VOIP, "Video camera initialization failed: application context is unavailable"); + return; + } + + CameraEnumerator enumerator = Camera2Enumerator.isSupported(context) + ? new Camera2Enumerator(context) + : new Camera1Enumerator(false); + String deviceName = findCamera(enumerator, useFrontCamera); + if (deviceName == null) { + Log.e(Log.TAG_VOIP, "Video camera initialization failed: no camera found"); + return; + } + + capturer = enumerator.createCapturer(deviceName, new CameraVideoCapturer.CameraEventsHandler() { + @Override + public void onCameraError (String errorDescription) { + Log.e(Log.TAG_VOIP, "Video camera error: %s", errorDescription); + } + + @Override + public void onCameraDisconnected () { + Log.w(Log.TAG_VOIP, "Video camera disconnected"); + } + + @Override + public void onCameraFreezed (String errorDescription) { + Log.e(Log.TAG_VOIP, "Video camera frozen: %s", errorDescription); + } + + @Override + public void onCameraOpening (String cameraName) { + Log.v(Log.TAG_VOIP, "Opening video camera: %s", cameraName); + } + + @Override + public void onFirstFrameAvailable () { + Log.v(Log.TAG_VOIP, "First local video frame is available"); + } + + @Override + public void onCameraClosed () { + Log.v(Log.TAG_VOIP, "Video camera closed"); + } + }); + if (capturer == null) { + Log.e(Log.TAG_VOIP, "Video camera initialization failed: capturer is unavailable"); + return; + } + + surfaceTextureHelper = SurfaceTextureHelper.create("FrogramVideoCamera", null); + if (surfaceTextureHelper == null) { + Log.e(Log.TAG_VOIP, "Video camera initialization failed: EGL surface is unavailable"); + capturer.dispose(); + capturer = null; + return; + } + + CapturerObserver observer = nativeGetJavaVideoCapturerObserver(nativePtr); + capturer.initialize(surfaceTextureHelper, context, observer); + if (requestedState == VIDEO_STATE_ACTIVE) { + startCapture(); + } + } + + @Keep + private synchronized void onStateChanged (long nativePtr, int state) { + if (destroyed || this.nativePtr != nativePtr) { + return; + } + requestedState = state; + if (state == VIDEO_STATE_ACTIVE) { + startCapture(); + } else if (state == VIDEO_STATE_PAUSED || state == VIDEO_STATE_INACTIVE) { + stopCapture(); + } + } + + @Keep + private synchronized void onAspectRatioRequested (float aspectRatio) { + if (capturer == null || !started || aspectRatio <= 0f) { + return; + } + if (aspectRatio < 1f) { + capturer.changeCaptureFormat(CAPTURE_HEIGHT, CAPTURE_WIDTH, CAPTURE_FPS); + } else { + capturer.changeCaptureFormat(CAPTURE_WIDTH, CAPTURE_HEIGHT, CAPTURE_FPS); + } + } + + @Keep + private synchronized void onDestroy () { + destroyed = true; + requestedState = VIDEO_STATE_INACTIVE; + stopAndDisposeCapturer(); + nativePtr = 0; + } + + private void startCapture () { + if (capturer == null || started) { + return; + } + try { + capturer.startCapture(CAPTURE_WIDTH, CAPTURE_HEIGHT, CAPTURE_FPS); + started = true; + } catch (Throwable t) { + Log.e(Log.TAG_VOIP, "Unable to start video capture", t); + } + } + + private void stopCapture () { + if (capturer == null || !started) { + return; + } + try { + capturer.stopCapture(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } catch (Throwable t) { + Log.e(Log.TAG_VOIP, "Unable to stop video capture", t); + } + started = false; + } + + private void stopAndDisposeCapturer () { + stopCapture(); + if (capturer != null) { + try { + capturer.dispose(); + } catch (Throwable t) { + Log.e(Log.TAG_VOIP, "Unable to dispose video capturer", t); + } + capturer = null; + } + if (surfaceTextureHelper != null) { + try { + surfaceTextureHelper.dispose(); + } catch (Throwable t) { + Log.e(Log.TAG_VOIP, "Unable to dispose video surface", t); + } + surfaceTextureHelper = null; + } + } + + private static String findCamera (CameraEnumerator enumerator, boolean front) { + String fallback = null; + for (String deviceName : enumerator.getDeviceNames()) { + if (fallback == null) { + fallback = deviceName; + } + if ((front && enumerator.isFrontFacing(deviceName)) || (!front && enumerator.isBackFacing(deviceName))) { + return deviceName; + } + } + return fallback; + } + + private static native CapturerObserver nativeGetJavaVideoCapturerObserver (long nativePtr); +} diff --git a/app/src/main/java/org/thunderdog/challegram/MainActivity.java b/app/src/main/java/org/thunderdog/challegram/MainActivity.java index 8341c56598..461979b199 100644 --- a/app/src/main/java/org/thunderdog/challegram/MainActivity.java +++ b/app/src/main/java/org/thunderdog/challegram/MainActivity.java @@ -15,6 +15,7 @@ package org.thunderdog.challegram; import android.content.Intent; +import android.content.res.Configuration; import android.net.Uri; import android.os.Bundle; import android.os.Handler; @@ -1531,6 +1532,24 @@ public void onPause () { }*/ } + @Override + protected void onUserLeaveHint () { + ViewController current = navigation != null ? navigation.getCurrentStackItem() : null; + if (current instanceof CallController && ((CallController) current).enterPictureInPictureIfPossible()) { + return; + } + super.onUserLeaveHint(); + } + + @Override + public void onPictureInPictureModeChanged (boolean isInPictureInPictureMode, Configuration newConfig) { + super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig); + ViewController current = navigation != null ? navigation.getCurrentStackItem() : null; + if (current instanceof CallController) { + ((CallController) current).onPictureInPictureModeChanged(isInPictureInPictureMode); + } + } + @Override public void onResume () { super.onResume(); diff --git a/app/src/main/java/org/thunderdog/challegram/U.java b/app/src/main/java/org/thunderdog/challegram/U.java index 441b910019..b9865d5937 100644 --- a/app/src/main/java/org/thunderdog/challegram/U.java +++ b/app/src/main/java/org/thunderdog/challegram/U.java @@ -457,6 +457,10 @@ public static String toHexString (String str) { } public static void startForeground (Service service, int notificationId, Notification notification) { + startForeground(service, notificationId, notification, false); + } + + public static void startForeground (Service service, int notificationId, Notification notification, boolean useCamera) { if (notification == null) throw new IllegalArgumentException(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { @@ -471,6 +475,9 @@ public static void startForeground (Service service, int notificationId, Notific if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { knownType |= android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE; } + if (useCamera) { + knownType |= android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA; + } knownType |= android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK; service.startForeground(notificationId, notification, knownType); return; diff --git a/app/src/main/java/org/thunderdog/challegram/service/TGCallService.java b/app/src/main/java/org/thunderdog/challegram/service/TGCallService.java index cf337e9272..f3079c7345 100644 --- a/app/src/main/java/org/thunderdog/challegram/service/TGCallService.java +++ b/app/src/main/java/org/thunderdog/challegram/service/TGCallService.java @@ -78,10 +78,13 @@ import org.thunderdog.challegram.voip.Socks5Proxy; import org.thunderdog.challegram.voip.VoIP; import org.thunderdog.challegram.voip.VoIPInstance; +import org.thunderdog.challegram.voip.annotation.AudioState; import org.thunderdog.challegram.voip.annotation.CallNetworkType; import org.thunderdog.challegram.voip.annotation.CallState; +import org.thunderdog.challegram.voip.annotation.VideoState; import org.thunderdog.challegram.voip.gui.CallSettings; import org.thunderdog.challegram.voip.gui.VoIPFeedbackActivity; +import org.webrtc.VideoSink; import java.lang.ref.WeakReference; import java.lang.reflect.Field; @@ -98,6 +101,10 @@ public class TGCallService extends Service implements TdlibCache.CallStateChangeListener, AudioManager.OnAudioFocusChangeListener, SensorEventListener, UI.StateListener { + public interface VideoStateListener { + void onVideoStateChanged (boolean supported, boolean localVideoEnabled, @VideoState int remoteVideoState, boolean frontCamera); + } + @Override public IBinder onBind (Intent intent) { return null; @@ -179,6 +186,8 @@ private void setCallId (Tdlib tdlib, int callId) { private SoundPoolMap soundPoolMap; private @Nullable VoIPInstance tgcalls; private @Nullable PrivateCallListener callListener; + private @Nullable VideoStateListener videoStateListener; + private @VideoState int remoteVideoState = VideoState.INACTIVE; private PowerManager.WakeLock cpuWakelock; private BluetoothAdapter btAdapter; @@ -271,6 +280,77 @@ public void updateOutputGainControlState () { } } + public void setVideoStateListener (@Nullable VideoStateListener listener) { + videoStateListener = listener; + dispatchVideoState(); + } + + private void dispatchVideoState () { + VideoStateListener listener = videoStateListener; + if (listener != null) { + listener.onVideoStateChanged( + tgcalls != null && tgcalls.supportsVideo(), + tgcalls != null && tgcalls.isVideoEnabled(), + remoteVideoState, + tgcalls == null || tgcalls.isFrontCamera() + ); + } + } + + public boolean supportsVideo () { + return tgcalls != null && tgcalls.supportsVideo(); + } + + public boolean isLocalVideoEnabled () { + return tgcalls != null && tgcalls.isVideoEnabled(); + } + + public boolean isFrontCamera () { + return tgcalls == null || tgcalls.isFrontCamera(); + } + + public @VideoState int getRemoteVideoState () { + return remoteVideoState; + } + + public boolean hasActiveVideo () { + return isLocalVideoEnabled() || remoteVideoState == VideoState.ACTIVE || remoteVideoState == VideoState.PAUSED; + } + + public void setVideoEnabled (boolean enabled) { + if (tgcalls == null || !tgcalls.supportsVideo()) { + return; + } + tgcalls.setVideoEnabled(enabled); + if (enabled) { + CallSettings settings = getCallSettings(); + if (settings != null && !settings.isSpeakerModeEnabled()) { + settings.setSpeakerMode(CallSettings.SPEAKER_MODE_SPEAKER); + } + } + updateVideoForegroundType(); + dispatchVideoState(); + } + + public void setVideoPaused (boolean paused) { + if (tgcalls != null && tgcalls.isVideoEnabled()) { + tgcalls.setVideoPaused(paused); + } + } + + public void switchCamera () { + if (tgcalls != null && tgcalls.isVideoEnabled()) { + tgcalls.switchCamera(); + dispatchVideoState(); + } + } + + public void setVideoSinks (@Nullable VideoSink localSink, @Nullable VideoSink remoteSink) { + if (tgcalls != null && tgcalls.supportsVideo()) { + tgcalls.setVideoSinks(localSink, remoteSink); + } + } + public boolean compareCall (Tdlib tdlib, int callId) { return call != null && callTdlib() == tdlib.id() && callId == call.id; } @@ -777,6 +857,17 @@ public void onAccuracyChanged (Sensor sensor, int accuracy) { private Notification ongoingCallNotification; + private void updateVideoForegroundType () { + if (ongoingCallNotification != null) { + U.startForeground( + this, + TdlibNotificationManager.ID_ONGOING_CALL_NOTIFICATION, + ongoingCallNotification, + isLocalVideoEnabled() + ); + } + } + private static final @DrawableRes int CALL_ICON_RES = R.drawable.baseline_phone_24_white; private void showNotification () { @@ -848,7 +939,7 @@ private void showNotification () { } else { ongoingCallNotification = builder.getNotification(); } - U.startForeground(this, TdlibNotificationManager.ID_ONGOING_CALL_NOTIFICATION, ongoingCallNotification); + U.startForeground(this, TdlibNotificationManager.ID_ONGOING_CALL_NOTIFICATION, ongoingCallNotification, isLocalVideoEnabled()); } // Sound @@ -1322,8 +1413,11 @@ private void releaseTgCalls (@Nullable Tdlib tdlib, @Nullable TdApi.Call call) { tdlib = tgcalls.tdlib(); } lastDebugLog = tgcalls.collectDebugLog(); + tgcalls.setVideoSinks(null, null); tgcalls.performDestroy(); tgcalls = null; + remoteVideoState = VideoState.INACTIVE; + dispatchVideoState(); } if (callListener != null && tdlib != null && call != null) { tdlib.listeners().unsubscribeFromCallUpdates(call.id, callListener); @@ -1389,6 +1483,12 @@ public void onSignalBarCountChanged (int newCount) { public void onSignallingDataEmitted (byte[] data) { tdlib.client().send(new TdApi.SendCallSignalingData(call.id, data), tdlib.silentHandler()); } + + @Override + public void onRemoteMediaStateChanged (VoIPInstance context, @AudioState int audioState, @VideoState int videoState) { + remoteVideoState = videoState; + UI.post(TGCallService.this::dispatchVideoState); + } }; VoIPInstance tgcallsTemp; @@ -1419,6 +1519,14 @@ public void onNewCallSignalingDataArrived (int callId, byte[] data) { }; tdlib.listeners().subscribeToCallUpdates(call.id, callListener); this.tgcalls = tgcalls; + if (tgcalls.isVideoEnabled()) { + CallSettings settings = getCallSettings(); + if (settings != null && !settings.isSpeakerModeEnabled()) { + settings.setSpeakerMode(CallSettings.SPEAKER_MODE_SPEAKER); + } + } + updateVideoForegroundType(); + UI.post(this::dispatchVideoState); } else { hangUp(); } diff --git a/app/src/main/java/org/thunderdog/challegram/telegram/CallManager.java b/app/src/main/java/org/thunderdog/challegram/telegram/CallManager.java index b6185ba609..bada4f232b 100644 --- a/app/src/main/java/org/thunderdog/challegram/telegram/CallManager.java +++ b/app/src/main/java/org/thunderdog/challegram/telegram/CallManager.java @@ -316,7 +316,11 @@ public boolean checkRecordPermissions (final Context context, final Tdlib tdlib, } public void makeCallDelayed (final ViewController context, final long userId, @Nullable final TdApi.UserFullInfo userFull, final boolean needPrompt) { - UI.post(() -> makeCall(context, userId, userFull, needPrompt), 180l); + makeCallDelayed(context, userId, userFull, needPrompt, false); + } + + private void makeCallDelayed (final ViewController context, final long userId, @Nullable final TdApi.UserFullInfo userFull, final boolean needPrompt, final boolean isVideo) { + UI.post(() -> makeCall(context, userId, userFull, needPrompt, isVideo), 180l); } public boolean hasActiveCall () { @@ -339,16 +343,24 @@ public boolean promptActiveCall () { } public void makeCall (final ViewController context,final long userId, @Nullable TdApi.UserFullInfo userFull) { - makeCall(context, userId, userFull, Settings.instance().needOutboundCallsPrompt()); + makeCall(context, userId, userFull, Settings.instance().needOutboundCallsPrompt(), false); } public void makeCall (final ViewController context, final long userId, @Nullable TdApi.UserFullInfo userFull, final boolean needPrompt) { + makeCall(context, userId, userFull, needPrompt, false); + } + + public void makeVideoCall (final ViewController context, final long userId, @Nullable TdApi.UserFullInfo userFull) { + makeCall(context, userId, userFull, false, true); + } + + private void makeCall (final ViewController context, final long userId, @Nullable TdApi.UserFullInfo userFull, final boolean needPrompt, final boolean isVideo) { if (userId == 0) { return; } if (Looper.myLooper() != Looper.getMainLooper()) { final TdApi.UserFullInfo userFullFinal = userFull; - UI.post(() -> makeCall(context, userId, userFullFinal, needPrompt)); + UI.post(() -> makeCall(context, userId, userFullFinal, needPrompt, isVideo)); return; } if (userFull == null) { @@ -382,7 +394,7 @@ public void makeCall (final ViewController context, final long userId, @Nulla hangUp(pendingCallTdlib, pendingCall.id, () -> { if (!signal[0]) { signal[0] = true; - makeCall(context, userId, userFullFinal, false); + makeCall(context, userId, userFullFinal, false, isVideo); } }); UI.post(() -> { @@ -426,27 +438,55 @@ public void makeCall (final ViewController context, final long userId, @Nulla if (error != null) { UI.showError(error); } else { - makeCall(context, userId, remoteUserFull, needPrompt); + makeCall(context, userId, remoteUserFull, needPrompt, isVideo); } }); return; } if (needPrompt) { final TdApi.UserFullInfo userFullFinal = userFull; - context.showOptions(Lang.getStringBold(R.string.CallX, context.tdlib().cache().userName(userId)), new int[]{R.id.btn_phone_call, R.id.btn_cancel}, new String[]{Lang.getString(R.string.Call), Lang.getString(R.string.Cancel)}, null, new int[]{R.drawable.baseline_call_24, R.drawable.baseline_cancel_24}, (itemView, id) -> { + final boolean canVideoCall = userFull.supportsVideoCalls; + context.showOptions( + Lang.getStringBold(R.string.CallX, context.tdlib().cache().userName(userId)), + canVideoCall ? new int[]{R.id.btn_phone_call, R.id.btn_video_call, R.id.btn_cancel} : new int[]{R.id.btn_phone_call, R.id.btn_cancel}, + canVideoCall ? new String[]{Lang.getString(R.string.AudioCall), Lang.getString(R.string.VideoCall), Lang.getString(R.string.Cancel)} : new String[]{Lang.getString(R.string.Call), Lang.getString(R.string.Cancel)}, + null, + canVideoCall ? new int[]{R.drawable.baseline_call_24, R.drawable.baseline_videocam_24, R.drawable.baseline_cancel_24} : new int[]{R.drawable.baseline_call_24, R.drawable.baseline_cancel_24}, + (itemView, id) -> { if (id == R.id.btn_phone_call) { - makeCallDelayed(context, userId, userFullFinal, false); + makeCallDelayed(context, userId, userFullFinal, false, false); + } else if (id == R.id.btn_video_call) { + makeCallDelayed(context, userId, userFullFinal, false, true); } return true; }); // UI.getCurrentStackItem(context); return; } + if (isVideo && !userFull.supportsVideoCalls) { + UI.showToast(R.string.VideoCallUnavailable, Toast.LENGTH_SHORT); + return; + } + if (isVideo) { + final TdApi.UserFullInfo resolvedUserFull = userFull; + BaseActivity activity = UI.getUiContext(); + if (activity != null && activity.permissions().requestRecordVideoPermissions(granted -> { + if (granted) { + makeCall(context, userId, resolvedUserFull, false, true); + } else if (activity.checkSelfPermission(Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { + showNeedMicAlert(false); + } else { + context.openMissingCameraPermissionAlert(); + } + })) { + return; + } + } if (!checkRecordPermissions(context.context(), context.tdlib(), null, userId, null)) { return; } context.context().closeAllMedia(false); - context.tdlib().send(new TdApi.CreateCall(userId, VoIP.getProtocol(), false), (callId, error) -> { + context.tdlib().send(new TdApi.CreateCall(userId, VoIP.getProtocol(), isVideo), (callId, error) -> { if (error != null) { Log.e(Log.TAG_VOIP, "Failed to create call: %s", TD.toErrorString(error)); UI.showError(error); @@ -487,14 +527,30 @@ private boolean checkConnection (final Context context, final Tdlib tdlib) { public void acceptCall (Context context, Tdlib tdlib, final int callId) { if (checkConnection(context, tdlib)) { - if (!checkRecordPermissions(context, tdlib, tdlib.cache().getCall(callId), 0, null)) { + TdApi.Call pendingCall = tdlib.cache().getCall(callId); + if (!checkRecordPermissions(context, tdlib, pendingCall, 0, null)) { return; } - Log.v(Log.TAG_VOIP, "#%d: AcceptCall requested", callId); - tdlib.client().send(new TdApi.AcceptCall(callId, VoIP.getProtocol()), object -> Log.v(Log.TAG_VOIP, "#%d: AcceptCall completed: %s", callId, object)); + BaseActivity activity = UI.getUiContext(); + if (pendingCall != null && pendingCall.isVideo && activity != null && + activity.permissions().requestAccessCameraPermission(granted -> { + if (granted) { + acceptCall(context, tdlib, callId); + } else { + sendAcceptCall(tdlib, callId); + } + })) { + return; + } + sendAcceptCall(tdlib, callId); } } + private void sendAcceptCall (Tdlib tdlib, int callId) { + Log.v(Log.TAG_VOIP, "#%d: AcceptCall requested", callId); + tdlib.client().send(new TdApi.AcceptCall(callId, VoIP.getProtocol()), object -> Log.v(Log.TAG_VOIP, "#%d: AcceptCall completed: %s", callId, object)); + } + public void hangUpCurrentCall () { int currentCall = getCurrentCallId(); if (currentCall != 0) { @@ -529,7 +585,7 @@ public void hangUp (final Tdlib tdlib, final int callId, final boolean isDisconn } int duration = getCallDuration(tdlib, callId); Log.v(Log.TAG_VOIP, "#%d: DiscardCall, isDisconnect: %b, connectionId: %d, duration: %d", callId, isDisconnect, connectionId, duration); - tdlib.client().send(new TdApi.DiscardCall(callId, isDisconnect, null, Math.max(0, duration), false, connectionId), object -> { + tdlib.client().send(new TdApi.DiscardCall(callId, isDisconnect, null, Math.max(0, duration), call.isVideo, connectionId), object -> { Log.v(Log.TAG_VOIP, "#%d: DiscardCall completed: %s", callId, object); }); } diff --git a/app/src/main/java/org/thunderdog/challegram/ui/CallController.java b/app/src/main/java/org/thunderdog/challegram/ui/CallController.java index a83b221b03..a481963e46 100644 --- a/app/src/main/java/org/thunderdog/challegram/ui/CallController.java +++ b/app/src/main/java/org/thunderdog/challegram/ui/CallController.java @@ -14,18 +14,22 @@ */ package org.thunderdog.challegram.ui; +import android.app.PictureInPictureParams; import android.content.Context; import android.content.pm.ActivityInfo; import android.graphics.Canvas; import android.graphics.RectF; import android.graphics.Typeface; import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; +import android.os.Build; import android.os.SystemClock; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextPaint; import android.text.TextUtils; import android.util.TypedValue; +import android.util.Rational; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; @@ -66,10 +70,13 @@ import org.thunderdog.challegram.util.text.TextColorSetOverride; import org.thunderdog.challegram.util.text.TextColorSets; import org.thunderdog.challegram.voip.gui.CallSettings; +import org.thunderdog.challegram.voip.annotation.VideoState; import org.thunderdog.challegram.widget.AvatarView; import org.thunderdog.challegram.widget.EmojiTextView; import org.thunderdog.challegram.widget.TextView; import org.thunderdog.challegram.widget.voip.CallControlsLayout; +import org.webrtc.RendererCommon; +import org.webrtc.SurfaceViewRenderer; import me.vkryl.android.AnimatorUtils; import me.vkryl.android.ScrimUtil; @@ -82,7 +89,7 @@ import me.vkryl.core.MathUtils; import me.vkryl.core.StringUtils; -public class CallController extends ViewController implements TdlibCache.UserDataChangeListener, TdlibCache.CallStateChangeListener, View.OnClickListener, FactorAnimator.Target, Runnable, CallControlsLayout.CallControlCallback, Screen.StatusBarHeightChangeListener { +public class CallController extends ViewController implements TdlibCache.UserDataChangeListener, TdlibCache.CallStateChangeListener, View.OnClickListener, FactorAnimator.Target, Runnable, CallControlsLayout.CallControlCallback, Screen.StatusBarHeightChangeListener, TGCallService.VideoStateListener { private static final boolean DEBUG_FADE_BRANDING = true; private static class ButtonView extends View implements FactorAnimator.Target { @@ -212,6 +219,10 @@ public int getId () { } private AvatarView avatarView; + private FrameLayoutFix contentView; + private SurfaceViewRenderer remoteVideoView, localVideoView; + private FrameLayoutFix localVideoWrap; + private TextView remoteVideoStatusView; private TextView nameView, stateView; private EmojiStatusHelper emojiStatusHelper; private float nameTextWidth; @@ -272,7 +283,13 @@ protected void onDraw (Canvas c) { private CallControlsLayout callControlsLayout; private FrameLayoutFix buttonWrap; - private ButtonView muteButtonView, speakerButtonView; + private ButtonView muteButtonView, speakerButtonView, videoButtonView, switchCameraButtonView; + private @Nullable TGCallService boundVideoService; + private boolean videoSupported; + private boolean localVideoEnabled; + private boolean frontCamera = true; + private @VideoState int remoteVideoState = VideoState.INACTIVE; + private boolean inPictureInPicture; private float lastHeaderFactor; @@ -336,7 +353,7 @@ public void onStatusBarHeightChanged (int newHeight) { @Override protected View onCreateView (final Context context) { - final FrameLayoutFix contentView = new FrameLayoutFix(context) { + this.contentView = new FrameLayoutFix(context) { @Override protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); @@ -349,6 +366,7 @@ protected void onLayout (boolean changed, int left, int top, int right, int bott updateEmojiPosition(); } }; + final FrameLayoutFix contentView = this.contentView; ViewSupport.setThemedBackground(contentView, ColorId.headerBackground, this); avatarView = new AvatarView(context) { @@ -394,6 +412,49 @@ protected void onDraw(Canvas c){ avatarView.setLayoutParams(FrameLayoutFix.newParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); contentView.addView(avatarView); + remoteVideoView = new SurfaceViewRenderer(context); + remoteVideoView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL); + remoteVideoView.setEnableHardwareScaler(true); + remoteVideoView.init(null, null); + remoteVideoView.setVisibility(View.GONE); + remoteVideoView.setLayoutParams(FrameLayoutFix.newParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + contentView.addView(remoteVideoView); + + remoteVideoStatusView = new TextView(context); + remoteVideoStatusView.setText(Lang.getString(R.string.RemoteCameraOff)); + remoteVideoStatusView.setTextColor(0xffffffff); + remoteVideoStatusView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14f); + remoteVideoStatusView.setGravity(Gravity.CENTER); + remoteVideoStatusView.setPadding(Screen.dp(16f), Screen.dp(9f), Screen.dp(16f), Screen.dp(9f)); + GradientDrawable remoteVideoStatusBackground = new GradientDrawable(); + remoteVideoStatusBackground.setColor(0x99000000); + remoteVideoStatusBackground.setCornerRadius(Screen.dp(20f)); + ViewUtils.setBackground(remoteVideoStatusView, remoteVideoStatusBackground); + remoteVideoStatusView.setVisibility(View.GONE); + remoteVideoStatusView.setLayoutParams(FrameLayoutFix.newParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER)); + contentView.addView(remoteVideoStatusView); + + localVideoWrap = new FrameLayoutFix(context); + GradientDrawable localVideoBackground = new GradientDrawable(); + localVideoBackground.setColor(0xff101715); + localVideoBackground.setCornerRadius(Screen.dp(14f)); + ViewUtils.setBackground(localVideoWrap, localVideoBackground); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + localVideoWrap.setClipToOutline(true); + localVideoWrap.setElevation(Screen.dp(8f)); + } + localVideoWrap.setVisibility(View.GONE); + + localVideoView = new SurfaceViewRenderer(context); + localVideoView.setZOrderMediaOverlay(true); + localVideoView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL); + localVideoView.setEnableHardwareScaler(true); + localVideoView.init(null, null); + localVideoView.setMirror(true); + localVideoView.setLayoutParams(FrameLayoutFix.newParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + localVideoWrap.addView(localVideoView); + contentView.addView(localVideoWrap); + FrameLayoutFix.LayoutParams params = FrameLayoutFix.newParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); // Top-left corner @@ -607,24 +668,47 @@ public boolean onTouchEvent (MotionEvent event) { muteButtonView.setOnClickListener(this); muteButtonView.setIcon(R.drawable.baseline_mic_24); muteButtonView.setNeedCross(true); - muteButtonView.setLayoutParams(FrameLayoutFix.newParams(Screen.dp(72f), Screen.dp(72f), Gravity.LEFT | Gravity.BOTTOM)); + muteButtonView.setLayoutParams(FrameLayoutFix.newParams(Screen.dp(64f), Screen.dp(72f), Gravity.LEFT | Gravity.BOTTOM)); + + FrameLayoutFix.LayoutParams videoButtonParams = FrameLayoutFix.newParams(Screen.dp(64f), Screen.dp(72f), Gravity.LEFT | Gravity.BOTTOM); + videoButtonParams.leftMargin = Screen.dp(64f); + videoButtonView = new ButtonView(context); + videoButtonView.setId(R.id.btn_call_video); + videoButtonView.setOnClickListener(this); + videoButtonView.setIcon(R.drawable.baseline_videocam_24); + videoButtonView.setNeedCross(true); + videoButtonView.setContentDescription(Lang.getString(R.string.TurnCameraOn)); + videoButtonView.setVisibility(View.GONE); + videoButtonView.setLayoutParams(videoButtonParams); ButtonView messageButtonView = new ButtonView(context); messageButtonView.setId(R.id.btn_openChat); messageButtonView.setOnClickListener(this); messageButtonView.setIcon(R.drawable.baseline_chat_bubble_24); - messageButtonView.setLayoutParams(FrameLayoutFix.newParams(Screen.dp(72f), Screen.dp(72f), Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM)); + messageButtonView.setLayoutParams(FrameLayoutFix.newParams(Screen.dp(64f), Screen.dp(72f), Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM)); + + FrameLayoutFix.LayoutParams switchCameraParams = FrameLayoutFix.newParams(Screen.dp(64f), Screen.dp(72f), Gravity.RIGHT | Gravity.BOTTOM); + switchCameraParams.rightMargin = Screen.dp(64f); + switchCameraButtonView = new ButtonView(context); + switchCameraButtonView.setId(R.id.btn_call_switch_camera); + switchCameraButtonView.setOnClickListener(this); + switchCameraButtonView.setIcon(R.drawable.baseline_camera_front_24); + switchCameraButtonView.setContentDescription(Lang.getString(R.string.SwitchCamera)); + switchCameraButtonView.setVisibility(View.GONE); + switchCameraButtonView.setLayoutParams(switchCameraParams); speakerButtonView = new ButtonView(context); speakerButtonView.setId(R.id.btn_speaker); speakerButtonView.setOnClickListener(this); speakerButtonView.setIcon(R.drawable.baseline_volume_up_24); - speakerButtonView.setLayoutParams(FrameLayoutFix.newParams(Screen.dp(72f), Screen.dp(72f), Gravity.RIGHT | Gravity.BOTTOM)); + speakerButtonView.setLayoutParams(FrameLayoutFix.newParams(Screen.dp(64f), Screen.dp(72f), Gravity.RIGHT | Gravity.BOTTOM)); buttonWrap = new FrameLayoutFix(context); buttonWrap.setLayoutParams(FrameLayoutFix.newParams(ViewGroup.LayoutParams.MATCH_PARENT, Screen.dp(76f), Gravity.BOTTOM)); buttonWrap.addView(muteButtonView); + buttonWrap.addView(videoButtonView); buttonWrap.addView(messageButtonView); + buttonWrap.addView(switchCameraButtonView); buttonWrap.addView(speakerButtonView); Views.setPaddingBottom(buttonWrap, extraBottomInset); Drawable drawable = ScrimUtil.makeCubicGradientScrimDrawable(0xff000000, 2, Gravity.BOTTOM, false); @@ -656,6 +740,8 @@ public boolean onTouchEvent (MotionEvent event) { speakerButtonView.setIsActive(callSettings.isSpeakerModeEnabled(), false); } + bindVideoService(); + return contentView; } @@ -678,6 +764,145 @@ public long mediaTextComplexColor () { this.emojiViewHint.setText(Lang.getString(R.string.CallEmojiHint, TD.getUserSingleName(call.userId, user))); } + private void bindVideoService () { + TGCallService service = TGCallService.currentInstance(); + if (service != null && !service.compareCall(tdlib, call.id)) { + service = null; + } + if (boundVideoService != service) { + if (boundVideoService != null) { + boundVideoService.setVideoStateListener(null); + boundVideoService.setVideoSinks(null, null); + } + boundVideoService = service; + if (service != null) { + service.setVideoStateListener(this); + } + } + if (service != null && localVideoView != null && remoteVideoView != null) { + service.setVideoSinks(localVideoView, remoteVideoView); + onVideoStateChanged(service.supportsVideo(), service.isLocalVideoEnabled(), service.getRemoteVideoState(), service.isFrontCamera()); + } else { + updateVideoUi(); + } + } + + @Override + public void onVideoStateChanged (boolean supported, boolean localVideoEnabled, @VideoState int remoteVideoState, boolean frontCamera) { + tdlib.ui().post(() -> { + if (isDestroyed()) { + return; + } + this.videoSupported = supported; + this.localVideoEnabled = localVideoEnabled; + this.remoteVideoState = remoteVideoState; + this.frontCamera = frontCamera; + updateVideoUi(); + }); + } + + private void updateVideoUi () { + if (remoteVideoView == null || localVideoWrap == null || videoButtonView == null) { + return; + } + boolean remoteVideoVisible = remoteVideoState != VideoState.INACTIVE; + boolean anyVideoVisible = remoteVideoVisible || localVideoEnabled; + + remoteVideoView.setVisibility(remoteVideoVisible ? View.VISIBLE : View.GONE); + remoteVideoStatusView.setVisibility(remoteVideoState == VideoState.PAUSED ? View.VISIBLE : View.GONE); + localVideoWrap.setVisibility(localVideoEnabled ? View.VISIBLE : View.GONE); + avatarView.setVisibility(anyVideoVisible ? View.GONE : View.VISIBLE); + localVideoView.setMirror(frontCamera); + + if (localVideoEnabled) { + FrameLayoutFix.LayoutParams localParams; + if (remoteVideoVisible) { + localParams = FrameLayoutFix.newParams(Screen.dp(112f), Screen.dp(168f), Gravity.RIGHT | Gravity.TOP); + localParams.topMargin = Math.max(Screen.getStatusBarHeight() + Screen.dp(12f), Screen.dp(36f)); + localParams.rightMargin = Screen.dp(12f); + } else { + localParams = FrameLayoutFix.newParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + } + localVideoWrap.setLayoutParams(localParams); + } + + boolean showVideoControls = videoSupported || call.isVideo; + videoButtonView.setVisibility(showVideoControls && !inPictureInPicture ? View.VISIBLE : View.GONE); + videoButtonView.setIsActive(!localVideoEnabled, isFocused()); + videoButtonView.setContentDescription(Lang.getString(localVideoEnabled ? R.string.TurnCameraOff : R.string.TurnCameraOn)); + switchCameraButtonView.setVisibility(localVideoEnabled && !inPictureInPicture ? View.VISIBLE : View.GONE); + applyPictureInPictureUi(); + } + + private void applyPictureInPictureUi () { + if (buttonWrap == null) { + return; + } + int visibility = inPictureInPicture ? View.GONE : View.VISIBLE; + buttonWrap.setVisibility(visibility); + callControlsLayout.setVisibility(visibility); + nameView.setVisibility(visibility); + stateView.setVisibility(visibility); + brandWrap.setVisibility(visibility); + emojiViewSmall.setVisibility(visibility); + emojiViewBig.setVisibility(visibility); + emojiViewHint.setVisibility(visibility); + if (!inPictureInPicture) { + updateControlsAlpha(); + } + } + + public boolean enterPictureInPictureIfPossible () { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { + return false; + } + bindVideoService(); + if (boundVideoService == null || !boundVideoService.hasActiveVideo() || context().isInPictureInPictureMode()) { + return false; + } + try { + PictureInPictureParams params = new PictureInPictureParams.Builder() + .setAspectRatio(new Rational(9, 16)) + .build(); + return context().enterPictureInPictureMode(params); + } catch (Throwable t) { + Log.w(Log.TAG_VOIP, "Unable to enter picture-in-picture mode", t); + return false; + } + } + + public void onPictureInPictureModeChanged (boolean inPictureInPicture) { + this.inPictureInPicture = inPictureInPicture; + if (boundVideoService != null) { + boundVideoService.setVideoPaused(false); + } + updateVideoUi(); + } + + private void setVideoEnabledWithPermission () { + bindVideoService(); + if (boundVideoService == null) { + return; + } + if (boundVideoService.isLocalVideoEnabled()) { + boundVideoService.setVideoEnabled(false); + return; + } + boolean requested = context().permissions().requestAccessCameraPermission(granted -> { + if (granted) { + bindVideoService(); + if (boundVideoService != null) { + boundVideoService.setVideoEnabled(true); + } + } else { + openMissingCameraPermissionAlert(); + } + }); + if (!requested) { + boundVideoService.setVideoEnabled(true); + } + } + @Override public void onCallAccept (TdApi.Call call) { tdlib.context().calls().acceptCall(context(), tdlib, call.id); @@ -690,7 +915,11 @@ public void onCallDecline (TdApi.Call call, boolean isHangUp) { @Override public void onCallRestart (TdApi.Call call) { - tdlib.context().calls().makeCall(this, call.userId, null); + if (call.isVideo) { + tdlib.context().calls().makeVideoCall(this, call.userId, null); + } else { + tdlib.context().calls().makeCall(this, call.userId, null); + } } public boolean compareUserId (long userId) { @@ -705,6 +934,10 @@ public void onCallClose (TdApi.Call call) { @Override public void onPrepareToShow () { super.onPrepareToShow(); + bindVideoService(); + if (boundVideoService != null) { + boundVideoService.setVideoPaused(false); + } if (!UI.isTablet()) { context().setOrientation(BaseActivity.getAndroidOrientationPortrait()); } @@ -713,6 +946,9 @@ public void onPrepareToShow () { @Override public void onCleanAfterHide () { super.onCleanAfterHide(); + if (boundVideoService != null && !inPictureInPicture) { + boundVideoService.setVideoPaused(true); + } if (!UI.isTablet()) { context().setOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); } @@ -738,6 +974,7 @@ private void setIsLooping (boolean isLooping) { @Override public void run () { if (!isDestroyed()) { + bindVideoService(); updateCallState(); if (isLooping) { UI.post(this, tdlib.context().calls().getTimeTillNextCallDurationUpdate(tdlib, call.id)); @@ -828,6 +1065,17 @@ public void onClick (View v) { } } else if (viewId == R.id.btn_openChat) { tdlib.ui().openPrivateChat(this, call.userId, null); + } else if (viewId == R.id.btn_call_video) { + if (!TD.isFinished(call)) { + setVideoEnabledWithPermission(); + } + } else if (viewId == R.id.btn_call_switch_camera) { + if (!TD.isFinished(call)) { + bindVideoService(); + if (boundVideoService != null) { + boundVideoService.switchCamera(); + } + } } else if (viewId == R.id.btn_speaker) { if (!TD.isFinished(call)) { if (callSettings == null) { @@ -949,6 +1197,7 @@ private void setFlashing (boolean isFlashing) { private long callDuration; private void updateCallState () { + bindVideoService(); updateLoop(); String str; callDuration = tdlib.context().calls().getCallDuration(tdlib, call.id); @@ -979,6 +1228,10 @@ private void updateFlashing () { @Override protected void onFocusStateChanged () { + bindVideoService(); + if (boundVideoService != null) { + boundVideoService.setVideoPaused(!isFocused() && !inPictureInPicture); + } updateFlashing(); } @@ -1141,6 +1394,10 @@ private void updateEmojiPosition () { @Override public void onFocus () { super.onFocus(); + bindVideoService(); + if (boundVideoService != null) { + boundVideoService.setVideoPaused(false); + } if (!oneShot) { destroyStackItemByIdExcludingLast(R.id.controller_call); ViewController c = previousStackItem(); @@ -1169,11 +1426,23 @@ public void replaceCall (TdApi.Call call) { updateCall(call); tdlib.cache().subscribeToCallUpdates(call.id, this); tdlib.context().calls().acknowledgeCurrentCall(call.id); + bindVideoService(); updateCallState(); } @Override public void destroy () { + if (boundVideoService != null) { + boundVideoService.setVideoStateListener(null); + boundVideoService.setVideoSinks(null, null); + boundVideoService = null; + } + if (localVideoView != null) { + localVideoView.release(); + } + if (remoteVideoView != null) { + remoteVideoView.release(); + } super.destroy(); Screen.removeStatusBarHeightListener(this); tdlib.cache().unsubscribeFromCallUpdates(call.id, this); diff --git a/app/src/main/java/org/thunderdog/challegram/ui/ProfileController.java b/app/src/main/java/org/thunderdog/challegram/ui/ProfileController.java index 2d18fa1d9c..76dd489fed 100644 --- a/app/src/main/java/org/thunderdog/challegram/ui/ProfileController.java +++ b/app/src/main/java/org/thunderdog/challegram/ui/ProfileController.java @@ -1,3 +1,6 @@ +Warning: truncated output (original token count: 62774) +Total output lines: 6816 + /* * This file is a part of Telegram X * Copyright © 2014 (tgx-android@pm.me) @@ -486,7 +489,7 @@ public void onMenuItemPressed (int id, View view) { manageChat(); } else if (id == R.id.menu_btn_call) { if (userFull != null) { - tdlib.context().calls().makeCall(this, user.id, userFull); + tdlib.context().calls().makeCall(this, user.id, userFull, true); } /*case R.id.menu_btn_edit: { if (supergroupFull != null) { @@ -3386,228 +3389,7 @@ else if (groupFull != null) showSettings( new SettingsWrapBuilder(R.id.btn_prehistoryMode) .setRawItems(new ListItem[]{ - new ListItem(ListItem.TYPE_RADIO_OPTION, R.id.btn_visible, 0, R.string.ChatHistoryVisible, R.id.btn_prehistoryMode, currentValue), - new ListItem(ListItem.TYPE_RADIO_OPTION, R.id.btn_hidden, 0, R.string.ChatHistoryHidden, R.id.btn_prehistoryMode, !currentValue) - }) - .setHeaderItem(headerItem) - .setOnSettingItemClick((view, settingsId, item, doneButton, settingsAdapter, window) -> { - boolean visible = settingsAdapter.getCheckIntResults().get(R.id.btn_prehistoryMode) == R.id.btn_visible; - if (groupFull != null && !visible) { - headerItem.setString(Lang.plural(R.string.ChatHistoryPartiallyHiddenInfo, 100)); - } else if (!visible && supergroupFull != null && supergroupFull.linkedChatId != 0) { - headerItem.setString(new SpannableStringBuilder(Lang.getString(R.string.ChatHistoryHiddenInfo)) - .append("\n\n") - .append(Lang.getStringBold(R.string.ChatHistoryWarnLinkedChannel, tdlib.chatTitle(supergroupFull.linkedChatId)))); - } else { - headerItem.setString(visible ? R.string.ChatHistoryVisibleInfo : R.string.ChatHistoryHiddenInfo); - } - settingsAdapter.updateValuedSettingByPosition(settingsAdapter.indexOfView(headerItem)); - }) - .setIntDelegate((id, result) -> { - boolean visible = result.get(R.id.btn_prehistoryMode) == R.id.btn_visible; - if (currentValue != visible) { - if (groupFull != null) { - showConfirm(Lang.getMarkdownString(this, R.string.UpgradeChatPrompt), Lang.getString(R.string.Proceed), () -> - tdlib.upgradeToSupergroup(chat.id, (oldChatId, newChatId, error) -> { - if (newChatId != 0) { - tdlib.send(new TdApi.ToggleSupergroupIsAllHistoryAvailable(ChatId.toSupergroupId(newChatId), visible), tdlib.typedOkHandler()); - } - }) - ); - } else { - if (supergroupFull != null && supergroupFull.linkedChatId != 0) { - tdlib.client().send(new TdApi.SetChatDiscussionGroup(0, chat.id), ignored -> tdlib.client().send(new TdApi.ToggleSupergroupIsAllHistoryAvailable(supergroup.id, visible), tdlib.okHandler())); - } else { - tdlib.send(new TdApi.ToggleSupergroupIsAllHistoryAvailable(supergroup.id, visible), tdlib.typedOkHandler()); - } - baseAdapter.updateValuedSettingById(R.id.btn_prehistoryMode); - } - } - }) - ); - } - - private void openEnabledReactions () { - EditEnabledReactionsController c = new EditEnabledReactionsController(context, tdlib); - c.setArguments(new EditEnabledReactionsController.Args(chat, EditEnabledReactionsController.TYPE_ENABLED_REACTIONS)); - navigateTo(c); - } - - private void openChatPermissions () { - EditRightsController c = new EditRightsController(context, tdlib); - c.setArguments(new EditRightsController.Args(chat.id)); - navigateTo(c); - } - - private void openRecentActions () { - MessagesController c = new MessagesController(context, tdlib); - c.setArguments(new MessagesController.Arguments(MessagesController.PREVIEW_MODE_EVENT_LOG, null, chat)); - navigateTo(c); - } - - private void openStats () { - ChatStatisticsController c = new ChatStatisticsController(context, tdlib); - c.setArguments(new ChatStatisticsController.Args(chat.id)); - navigateTo(c); - } - - private void editUsername () { - EditUsernameController c = new EditUsernameController(context, tdlib); - c.setArguments(new EditUsernameController.Args(chat.id)); - navigateTo(c); - } - - private void editLinkedChat () { - TdApi.Chat linkedChat = supergroupFull != null && supergroupFull.linkedChatId != 0 ? tdlib.chat(supergroupFull.linkedChatId) : null; - Lang.SpanCreator linkedChatCreator = (target, argStart, argEnd, argIndex, needFakeBold) -> - new ClickableSpan() { - @Override - public void onClick (@NonNull View widget) { - tdlib.ui().openChat(ProfileController.this, linkedChat, new TdlibUi.ChatOpenParameters().keepStack().removeDuplicates()); - } - }; - switch (mode) { - case Mode.EDIT_CHANNEL: { - int size = linkedChat != null ? 3 : 2; - IntList ids = new IntList(size); - StringList strings = new StringList(size); - IntList icons = new IntList(size); - - CharSequence info; - if (linkedChat != null) { - ids.append(R.id.btn_delete); - strings.append(R.string.ChannelGroupRemove); - icons.append(R.drawable.baseline_remove_circle_24); - info = Lang.getString(R.string.ChannelGroupInfo2, linkedChatCreator, - tdlib.chatTitle(linkedChat) - ); - } else { - info = Lang.getString(R.string.ChannelGroupInfo); - } - - ids.append(R.id.btn_search); - icons.append(R.drawable.baseline_search_24); - strings.append(R.string.ChannelGroupExisting); - - ids.append(R.id.btn_new); - icons.append(R.drawable.baseline_group_add_24); - strings.append(R.string.ChannelGroupNew); - - showOptions(info, ids.get(), strings.get(), size == 3 ? new int[]{OptionColor.RED, OptionColor.NORMAL, OptionColor.NORMAL} : null, icons.get(), (v, id) -> { - if (id == R.id.btn_delete) { - if (linkedChat != null) { - showConfirm(Lang.getString(R.string.UnlinkGroupConfirm, linkedChatCreator, tdlib.chatTitle(linkedChat)), Lang.getString(R.string.UnlinkGroupDone), R.drawable.baseline_remove_circle_24, OptionColor.RED, () -> - tdlib.client().send(new TdApi.SetChatDiscussionGroup(chat.id, 0), tdlib.okHandler()) - ); - } - } else if (id == R.id.btn_search) { - PeopleController c = new PeopleController(context, tdlib); - c.setArguments(new PeopleController.Args(PeopleController.MODE_DISCUSSION_GROUPS).setGroupSelectListener((context, group) -> { - linkGroup(context, group.getChatId(), true); - return true; - })); - navigateTo(c); - } else if (id == R.id.btn_new) { - CreateGroupController.Callback callback = new CreateGroupController.Callback() { - @Override - public boolean onGroupCreated (CreateGroupController context, TdApi.Chat chat) { - linkGroup(context, chat.id, false); - return true; - } - - @Override - public boolean forceSupergroupChat () { - return true; - } - }; - /*ContactsController c = new ContactsController(context, tdlib); - c.initWithMode(ContactsController.MODE_NEW_GROUP); - c.setGroupCreationCallback();*/ - ArrayList users = new ArrayList<>(); - users.add(new TGUser(tdlib, tdlib.myUser())); - CreateGroupController c = new CreateGroupController(context, tdlib); - c.setGroupCreationCallback(callback); - c.setMembers(users); - navigateTo(c); - } - return true; - }, null); - break; - } - case Mode.EDIT_SUPERGROUP: { - if (linkedChat == null) - return; - CharSequence info = Lang.getString(R.string.GroupChannelInfo, linkedChatCreator, tdlib.chatTitle(linkedChat)); - showOptions(info, new int[]{R.id.btn_delete, R.id.btn_cancel}, new String[]{Lang.getString(R.string.GroupChannelUnlink), Lang.getString(R.string.Cancel)}, new int[]{OptionColor.RED, OptionColor.NORMAL}, new int[]{R.drawable.baseline_remove_circle_24, R.drawable.baseline_cancel_24}, (v, id) -> { - if (id == R.id.btn_delete) { - showConfirm(Lang.getString(R.string.UnlinkChannelConfirm, linkedChatCreator, tdlib.chatTitle(linkedChat)), Lang.getString(R.string.UnlinkChannelDone), R.drawable.baseline_remove_circle_24, OptionColor.RED, () -> - tdlib.client().send(new TdApi.SetChatDiscussionGroup(0, chat.id), tdlib.okHandler()) - ); - } - return true; - }, null); - break; - } - } - } - - private void linkGroup (ViewController context, long selectedChatId, boolean needPrompt) { - boolean isPublic = tdlib.chatPublic(chat.id); - boolean isLinkedPublic = tdlib.chatPublic(selectedChatId); - - tdlib.cache().supergroupFull(ChatId.toSupergroupId(selectedChatId), selectedFullInfo -> { - Runnable doneAct = () -> { - RunnableLong act = chatId -> { - tdlib.client().send(new TdApi.ToggleSupergroupIsAllHistoryAvailable(ChatId.toSupergroupId(chatId), true), ignored -> - tdlib.client().send(new TdApi.SetChatDiscussionGroup(chat.id, chatId), tdlib.okHandler()) - ); - context.navigateBack(); - }; - if (ChatId.isBasicGroup(selectedChatId)) { - tdlib.client().send(new TdApi.UpgradeBasicGroupChatToSupergroupChat(selectedChatId), result -> { - switch (result.getConstructor()) { - case TdApi.Chat.CONSTRUCTOR: - tdlib.ui().post(() -> act.runWithLong(((TdApi.Chat) result).id)); - break; - case TdApi.Error.CONSTRUCTOR: - UI.showError(result); - break; - } - }); - } else if (selectedFullInfo != null) { - long currentChatId = selectedFullInfo.linkedChatId; - tdlib.ui().post(() -> { - if (currentChatId != 0) { - showConfirm(Lang.getString(R.string.LinkGroupConfirmOverride, (target, argStart, argEnd, argIndex, needFakeBold) -> new ClickableSpan() { - @Override - public void onClick (@NonNull View widget) { - tdlib.ui().openChat(ProfileController.this, argIndex == 0 ? selectedChatId : currentChatId, new TdlibUi.ChatOpenParameters().keepStack().removeDuplicates()); - } - }, tdlib.chatTitle(selectedChatId), tdlib.chatTitle(currentChatId)), Lang.getString(R.string.LinkGroupConfirmOverrideDone), R.drawable.baseline_remove_circle_24, OptionColor.RED, () -> { - act.runWithLong(selectedChatId); - }); - } else { - act.runWithLong(selectedChatId); - } - }); - } - }; - if (!needPrompt) { - doneAct.run(); - return; - } - CharSequence prompt = Lang.getString(R.string.LinkGroupConfirm, (target, argStart, argEnd, argIndex, needFakeBold) -> new ClickableSpan() { - @Override - public void onClick (@NonNull View widget) { - if (argIndex == 0) { - tdlib.ui().openChat(ProfileController.this, selectedChatId, new TdlibUi.ChatOpenParameters().keepStack().removeDuplicates()); - } else { - tdlib.ui().openChat(ProfileController.this, chat.id, new TdlibUi.ChatOpenParameters().keepStack().removeDuplicates()); - } - } - }, tdlib.chatTitle(selectedChatId), tdlib.chatTitle(chat.id)); - SpannableStringBuilder b = prompt instanceof SpannableStringBuilder ? (SpannableStringBuilder) prompt : new SpannableStringBuilder(prompt); - if (!isPublic || !isLinkedPublic) { + new ListItem(ListItem.TYPE_RADIO_OPTION, R.id.btn_visible,…2774 tokens truncated…kedPublic) { if (isPublic) { b.append("\n\n").append(Lang.getMarkdownString(this, R.string.LinkGroupConfirmWarnPrivateGroup)); } else { diff --git a/app/src/main/java/org/thunderdog/challegram/voip/CallConfiguration.java b/app/src/main/java/org/thunderdog/challegram/voip/CallConfiguration.java index a163ac108f..e7f301341a 100644 --- a/app/src/main/java/org/thunderdog/challegram/voip/CallConfiguration.java +++ b/app/src/main/java/org/thunderdog/challegram/voip/CallConfiguration.java @@ -25,6 +25,7 @@ public class CallConfiguration { public final TdApi.CallStateReady state; public final boolean isOutgoing; + public final boolean isVideo; public final @NonNull String persistentStateFilePath; public final @Nullable String logFilePath; @@ -48,6 +49,7 @@ public class CallConfiguration { public CallConfiguration ( @NonNull TdApi.CallStateReady state, boolean isOutgoing, + boolean isVideo, @NonNull File persistentStateFile, @Nullable File logFile, @Nullable File statsLogFile, @@ -78,6 +80,7 @@ public CallConfiguration ( this.state = state; } this.isOutgoing = isOutgoing; + this.isVideo = isVideo; this.persistentStateFilePath = persistentStateFile.getAbsolutePath(); this.logFilePath = logFile != null ? logFile.getAbsolutePath() : null; diff --git a/app/src/main/java/org/thunderdog/challegram/voip/TgCallsController.java b/app/src/main/java/org/thunderdog/challegram/voip/TgCallsController.java index f762a00d51..56af64a785 100644 --- a/app/src/main/java/org/thunderdog/challegram/voip/TgCallsController.java +++ b/app/src/main/java/org/thunderdog/challegram/voip/TgCallsController.java @@ -23,16 +23,20 @@ import org.thunderdog.challegram.voip.annotation.AudioState; import org.thunderdog.challegram.voip.annotation.CallNetworkType; import org.thunderdog.challegram.voip.annotation.VideoState; +import org.webrtc.VideoSink; @SuppressWarnings("JavaJniMissingFunction") public class TgCallsController extends VoIPInstance { private final String version; private long nativePtr; + private boolean videoEnabled; + private boolean frontCamera = true; public TgCallsController (@NonNull Tdlib tdlib, @NonNull TdApi.Call call, @NonNull CallConfiguration configuration, @NonNull CallOptions options, @NonNull ConnectionStateListener stateListener, String version) { super(tdlib, call, configuration, options, stateListener); if (configuration.state.encryptionKey.length != 256) throw new IllegalArgumentException(Integer.toString(configuration.state.encryptionKey.length)); this.version = version; + this.videoEnabled = configuration.isVideo; this.nativePtr = newInstance(version, configuration, options); } @@ -60,6 +64,12 @@ private native long newInstance ( private native void updateMicrophoneDisabled (long ptr, boolean isDisabled); private native void updateEchoCancellationStrength (long ptr, int strength); private native void updateAudioOutputGainControlEnabled (long ptr, boolean isEnabled); + private native boolean nativeSupportsVideo (long ptr); + private native void nativeSetVideoEnabled (long ptr, boolean enabled); + private native void nativeSetVideoPaused (long ptr, boolean paused); + private native void nativeSwitchCamera (long ptr); + private native void nativeSetLocalVideoOutput (long ptr, @Nullable VideoSink sink); + private native void nativeSetRemoteVideoOutput (long ptr, @Nullable VideoSink sink); private native void destroyInstance (long ptr); @Override @@ -97,6 +107,46 @@ protected void handleNetworkTypeChange (@CallNetworkType int type) { updateNetworkType(nativePtr(), type); } + @Override + public boolean supportsVideo () { + return nativePtr != 0 && nativeSupportsVideo(nativePtr()); + } + + @Override + public boolean isVideoEnabled () { + return videoEnabled; + } + + @Override + public boolean isFrontCamera () { + return frontCamera; + } + + @Override + public void setVideoEnabled (boolean enabled) { + if (videoEnabled != enabled) { + videoEnabled = enabled; + nativeSetVideoEnabled(nativePtr(), enabled); + } + } + + @Override + public void setVideoPaused (boolean paused) { + nativeSetVideoPaused(nativePtr(), paused); + } + + @Override + public void switchCamera () { + frontCamera = !frontCamera; + nativeSwitchCamera(nativePtr()); + } + + @Override + public void setVideoSinks (@Nullable VideoSink localSink, @Nullable VideoSink remoteSink) { + nativeSetLocalVideoOutput(nativePtr(), localSink); + nativeSetRemoteVideoOutput(nativePtr(), remoteSink); + } + @Override public long getConnectionId () { return preferredConnectionId(nativePtr()); diff --git a/app/src/main/java/org/thunderdog/challegram/voip/VoIP.java b/app/src/main/java/org/thunderdog/challegram/voip/VoIP.java index e84224274f..014e8cca1f 100644 --- a/app/src/main/java/org/thunderdog/challegram/voip/VoIP.java +++ b/app/src/main/java/org/thunderdog/challegram/voip/VoIP.java @@ -14,7 +14,9 @@ */ package org.thunderdog.challegram.voip; +import android.Manifest; import android.content.Context; +import android.content.pm.PackageManager; import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioTrack; @@ -382,9 +384,14 @@ public static VoIPInstance instantiateAndConnect ( final boolean preferSystemNoiseSuppressor = VoIPServerConfig.getBoolean("use_system_ns", true); // These do not change during the call + final boolean startWithVideo = call.isVideo && ( + Build.VERSION.SDK_INT < Build.VERSION_CODES.M || + ContextUtils.getApplicationContext().checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED + ); final CallConfiguration configuration = new CallConfiguration( stateReady, call.isOutgoing, + startWithVideo, persistentStateFile, logFiles != null ? logFiles.logFile : null, diff --git a/app/src/main/java/org/thunderdog/challegram/voip/VoIPInstance.java b/app/src/main/java/org/thunderdog/challegram/voip/VoIPInstance.java index a7102ce937..42a1dae457 100644 --- a/app/src/main/java/org/thunderdog/challegram/voip/VoIPInstance.java +++ b/app/src/main/java/org/thunderdog/challegram/voip/VoIPInstance.java @@ -23,6 +23,7 @@ import org.thunderdog.challegram.telegram.Tdlib; import org.thunderdog.challegram.voip.annotation.CallNetworkType; import org.thunderdog.challegram.voip.annotation.CallState; +import org.webrtc.VideoSink; import me.vkryl.core.lambda.Destroyable; @@ -110,6 +111,26 @@ public void setNetworkType (@CallNetworkType int type) { protected abstract void handleNetworkTypeChange (@CallNetworkType int type); + public boolean supportsVideo () { + return false; + } + + public boolean isVideoEnabled () { + return false; + } + + public boolean isFrontCamera () { + return true; + } + + public void setVideoEnabled (boolean enabled) { } + + public void setVideoPaused (boolean paused) { } + + public void switchCamera () { } + + public void setVideoSinks (VideoSink localSink, VideoSink remoteSink) { } + // Getters public abstract CharSequence collectDebugLog (); diff --git a/app/src/main/res/values-ru/frogram_strings.xml b/app/src/main/res/values-ru/frogram_strings.xml index f41861f7f9..1fb24554a1 100644 --- a/app/src/main/res/values-ru/frogram_strings.xml +++ b/app/src/main/res/values-ru/frogram_strings.xml @@ -43,4 +43,11 @@ Открыть публикацию полностью Реакция по двойному нажатию Дважды нажмите на сообщение, чтобы поставить первую выбранную ниже реакцию. Если выбрана одна реакция, реакции по свайпу отключаются. В некоторых группах и каналах отдельные реакции могут быть недоступны. + Аудиозвонок + Видеозвонок + Видеозвонки недоступны для этого пользователя или устройства + Включить камеру + Выключить камеру + Переключить камеру + Камера выключена diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml index 193e449468..9787fd7a2e 100644 --- a/app/src/main/res/values/ids.xml +++ b/app/src/main/res/values/ids.xml @@ -1191,6 +1191,7 @@ + @@ -1361,6 +1362,8 @@ --> + + diff --git a/app/src/main/res/values/local_strings.xml b/app/src/main/res/values/local_strings.xml index a61dd082e0..02c68544a0 100644 --- a/app/src/main/res/values/local_strings.xml +++ b/app/src/main/res/values/local_strings.xml @@ -11,4 +11,12 @@ False-positive emulator detection warning on %1$s \`%2$s\` Hello. I use **Frogram X** on a real device, but it says I am running on an emulator.\n\n**My real device details:**\n\nName: %1$s \`%2$s\`\nProduct: \`%3$s\`\nDevice: \`%4$s\`\nHardware: \`%5$s\`\n\n**The app version I am using:**\n\n%6$s\n\n**Emulator detection result:** `%7$s`\n\nPlease take a look if this warning can be resolved for my device.\nThank you! - \ No newline at end of file + + Audio call + Video call + Video calls aren\'t supported by this user or device + Turn camera on + Turn camera off + Switch camera + Camera is off + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 63c65d129e..06d851c8fa 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,6 @@ +Warning: truncated output (original token count: 106077) +Total output lines: 5908 + Continue in English @@ -1728,2485 +1731,7 @@ You revoked the primary invite link %1$s %1$s revoked %2$s\'s invite link %3$s You revoked %1$s\'s invite link %2$s - %1$s revoked %2$s\'s temporary invite link %3$s - You revoked %1$s\'s temporary invite link %2$s - %1$s deleted the primary invite link %2$s - You deleted the primary invite link %1$s - %1$s deleted %2$s\'s invite link %3$s - You deleted %1$s\'s invite link %2$s - %1$s deleted %2$s\'s temporary invite link %3$s - You deleted %1$s\'s temporary invite link %2$s - %1$s created the group - You created the group - %1$s of %2$s - %1$s of ~%2$s - Reading line %1$s… - %1$s, %2$s - %1$s member joined the group - %1$s members joined the group - %1$s member joined the channel - %1$s members joined the channel - Add %1$s to the group? - Add %1$s to the group and assign as an admin? - Add %1$s to the channel? - Voice Calls - Choose exactly who can and can\'t call you. - Ringtone - Disabled - Calls - Allow - Contact added - %1$s is not on Telegram yet. Would you like to invite them via SMS? - %2$s is not on Telegram yet. Would you like to invite them via SMS? They may have up to %1$s contact on Telegram. - %2$s is not on Telegram yet. Would you like to invite them via SMS? They may have up to %1$s contacts on Telegram. - Outgoing Call - Incoming Call - Missed Call - Canceled Call - Declined Call - Declined - Decline - Answer - Outgoing Call (Busy) - Missed - Canceled - Outgoing - Incoming - Call Again - Call Back - Share Call Diagnostics - Busy - Message Font Size - Enable Size Scaling - Disable Size Scaling - Reset to Default - You haven\'t called anybody yet. - Airplane Mode - You have airplane mode enabled. Please turn it off or connect to Wi-Fi to make calls. - Offline - You\'re currently offline. Please connect to the Internet in order to make calls. - Sorry, you cannot call %1$s because of their privacy settings. You can ask them to modify their setting or to call you instead. - Connecting - Ringing - Waiting - Failed to connect - Exchanging encryption keys - Exchanging keys - Connecting… - Call ended - Call canceled - Call canceled - Call missed - Call missed - Call answered - Line Busy - Disconnected - Telegram Call - Incoming Telegram Call - On Mobile Network - While Roaming - Always - Permission required - Microphone access required in order to make calls. - If the emoji on %1$s\'s screen are the same, this call is 100%% secure. - Show call - Another call in progress - You currently have an ongoing call with %1$s. Would you like to hang up on that call and start a new one with %2$s? - Less Data for Calls - Using less data may improve your experience on bad networks, but will slightly decrease audio quality. - End call - Hang up - Swipe actions - Loop Animated Stickers - Animated Emoji - Duration - Please rate the quality of your Telegram call - Add an optional comment - Earpiece - Speaker - Bluetooth - Night Mode - Proxy - Connection - Disabled - Tap to set up - Credentials - Credentials (optional) - SOCKS5 Proxy - MTPROTO Proxy - SOCKS5 %1$s - MTPROTO %1$s - Add SOCKS5 Proxy - Add MTPROTO Proxy - Add HTTP Proxy - HTTP Proxy - Transparent TCP connection - Enable if server supports transparent TCP connections via HTTP CONNECT method.\n\nWhen supported, it may improve connection speed dramatically. Try changing this option if this proxy doesn\'t work. - HTTP %1$s - Tor Network %1$s - Username - Password - Secret - Proxy servers may be helpful in accessing Telegram if there is no connection in a specific region. - Error (%1$s) - Error - Problems detected - Checking… - Available (%1$s) - Without Proxy - Connections - Connected (%1$s) - Add proxy - Other settings - Server - Port - Proxy settings - Switch automatically - Automatically try different connections when the app takes too long to connect. This may increase the time needed to establish connection on weak networks. - Are you sure you want to enable this proxy? - You can change your proxy server later in Settings > Data and Storage. - This proxy may display a sponsored channel in your chat list. This doesn\'t reveal any of your Telegram traffic. - Enable - Save Proxy - Username - Password - Save to Downloads - Save %1$s file to Downloads - Save %1$s files to Downloads - Save to Music - Save %1$s file to Music - Save %1$s files to Music - Successfully downloaded: %1$s - Successfully downloaded %1$s file:\n%2$s - Successfully downloaded %1$s files:\n%2$s - Saved %1$s file - Saved %1$s files - This call is no longer active - %1$s joined Telegram! - Delete Entry - Sticker - Animated Sticker - Video message - Microphone is required in order to make calls. It seems to be not present on your device. - People - Groups - Remove %1$s from suggestions? - Remove %1$s from recently found chats? - Send to - Send as - Send as… - Your account - Select Chats - Add a comment… - Send sticker - View Pack - Bio - Birthday - Description - Intro - Public Link - Bot Link - Any details such as age, occupation or city.\nExample: 23 y.o. designer from San Francisco. - Expired photo - Expired video - Paid content - Expired voice message - Expired video message - Send with Enter - Hide keyboard on chat scroll - Hashtag has been copied to the clipboard - Cashtag has been copied to the clipboard - Invite Friends - Hey, let\'s switch to %1$s:\n%2$s - View Profile - View Channel - View Group - View Channel - View Post - Open App - Open Website - Open Bot - View Bot - Send as copy - Remove captions in copies - GIF saved to Gallery - %1$s GIF saved to Gallery - %1$s GIFs saved to Gallery - Error - Username %1$s not found - Chat with specified username not found - Regular - Urgent - Low - Urgent notifications will appear even in Do Not Disturb mode. Low priority will appear only in the system tray. - Priority - Select messages in between - Processing… - Processing files. Please wait… - Do you want to permanently delete this chat? - Sorry, you were restricted by chat admins from performing this action. - Remove this hashtag from suggestions? - Are you sure you want to report %1$s for spam? - Report - Report %1$s - Report %1$s? - Report - Description - Description (required) - Report %1$s\'s photo? - Spam - Fake - Violence - Child Abuse - Pornography - Report sent - Select messages to include in your report. - Messages have been copied to the clipboard - Forwarded from %1$s - In reply to %1$s - Copy username - Posted by %1$s - Clear from cache - Send message to %1$s - Note: you will be able to download this file any time later. - Note: you will be able to download these files any time later. - Freed %1$s of disk space - Link Preview - Are you sure you want to clear history for this channel? This action cannot be undone. - **No, seriously.**\n\nThis will delete **all messages** for **all subscribers**. There will be no way to restore them. - Are you sure you want to clear history for this chat for all users? This action cannot be undone. - Are you sure you want to clear history for this chat? This action cannot be undone. - Are you sure you want to clear all **Saved Messages**? This action cannot be undone. - **No, seriously.**\n\nThis will delete **all Saved Messages**. There will be no way to restore them. - Channel - Cyan - Pink - Orange - White-black - Green - Video messages - No Video messages - Delete %1$s from contacts? - Bot is not responding. Please try again later. - %1$s is not responding. Please try again later. - In-app Browser - Share Link - Failed to copy text. Most likely, the text you tried to copy is too big. - Auto Night Mode - Disable Auto Night Mode? - Changing current theme will disable Auto Night Mode.\n\nYou may enable it any time later in Settings > Themes and Chats. - Use proxy for calls - Proxy servers may degrade the quality of your calls. - Chat Previews - Block user - Block sender - If you set a timer, the photo will self-destruct after it was viewed. - If you set a timer, the video will self-destruct after it is viewed. - No members to show - No results to show - Try changing your search query.\nFound members will be shown here. - Try changing your search query. - Manage Channel - Manage Group - Edit Bot - **Warning**: this will update the default bot information shown on the profile page for **all users**. - **Warning**: this will update the default bot intro shown on the chat page for **all users**. - chat owner - not a member - banned member - channel - group - joined just now - joined %1$s sec ago - joined %1$s secs ago - joined %1$s min ago - joined %1$s mins ago - joined %1$s hr ago - joined %1$s hrs ago - joined at %1$s - joined yesterday at %1$s - joined %1$s day ago - joined %1$s days ago - joined %1$s week ago - joined %1$s weeks ago - joined %1$s month ago - joined %1$s months ago - joined %1$s year ago - joined %1$s years ago - Restricted - Promoted by %1$s - Promoted by %1$s %2$s - Banned by %1$s - Banned by %1$s %2$s - Invited by %1$s %2$s - Invited by %1$s - Restricted by %1$s - Restricted by %1$s %2$s - Edit Group - Group Info - Service actions in the group in the last 48 hours. - Service actions in the channel in the last 48 hours. - Banned - All members - Only admins - Only admins with privilege - Edit Admin - Admin Rights - - Reactions - Reactions disabled - **All** reactions enabled - %1$s reaction enabled - %1$s reactions enabled - - Enabled - Disabled - %1$s allowed - %1$s allowed - - Enable Quick Reaction - Some groups and channels may not allow specific reactions. - Reaction on double tap - Double-tap a message to apply the first reaction selected below. When only one reaction is selected, swipe reactions are disabled. Some groups and channels may not allow specific reactions. - - Allow members to react to group messages - %1$s reaction - %1$s reactions - Maximum number of reactions - Limit the number of different reactions that can be added to a post, including already published ones. - Maximum number of reactions - Limit the number of different reactions that can be added to a message, including already sent ones. - Available reactions - Premium reactions - Subscribe to **Telegram Premium** to be able to use reactions below. - Reached the limit of quick reactions - Quick Reaction - Disabled - Big reactions are interactive buttons under messages presenting each reaction - When limited, avatars display only in scenarios when you are likely to recognise the user. - Big Reactions - Chats - Channels - None - Reactions in channels are anonymous - - User Permissions - Group Permissions - Channel Permissions - Promote to Admin - What can this admin do? - What can this user do? - Read Messages - Send Messages - Send Media - Send Music - Send Files - Send Photos - Send Videos - Send Voice Messages - Send Video Messages - Send Stickers & GIFs - Send Polls - Embed Links - React to Messages - Change Group Info - Change Channel Info - Delete Messages - Ban Users - Add Users - Pin Messages - Add New Admins - Edit Messages - Manage video chats - Manage live streams - Manage direct messages - Edit Member Tags - Edit Own Tags - Manage topics - Create topics - Topics - Open this topic by default - Open chat normally by default - No topics found - Mark all as read - Pin topic - Unpin topic - Create topic - Edit topic - Topic name - Topic icon - Close topic - Reopen topic - Delete topic - Delete topic “%1$s” and all its messages? This can’t be undone. - Stories - Messages - Post Stories - Edit Stories of Others - Delete Stories of Others - Remain anonymous - No groups to show - Groups in common will be shown here - Edit Admin Rights - Edit Admin Tag - Edit Owner Tag - Edit Member Tag - Make Anonymous - Disclose Admin - Make Anonymous - Disclose Owner - View Admin Rights - Edit User Restrictions - Edit Group Restrictions - Edit Channel Restrictions - Restrict user - Ban group - Ban channel - Granular control over permissions is not available when restricting groups. - Granular control over permissions is not available when restricting channels. - View Restrictions - Post Messages - Banned members will be shown here - Restricted members will be shown here - Unban user - Unban channel - Unban group - Unban bot - Block for - Restrict for - Restrict until - Block until - Custom date - Remove restrictions - Uploading photo, please wait… - Deleting profile photo, please wait… - Chat name can\'t be empty - Anyone who has Telegram installed will be able to join your channel by following this link. - Channel Link - Group Link - Apply - Enter description here - Allow Screen Capture - If enabled, you can take screenshots of the app, but the system will display your chats in the task switcher even when the passcode is on.\n\nYou may need to restart the app for this to take effect. - Remove - Remove - Remove - Call %1$s? - Prompt before calling - Show confirmation dialog each time you call anyone. - Custom Vibrations - This action cannot be done while call is active. - Follow - Unselect - Sorry, this public link is already taken. - Sorry, this public link is invalid. - Public links must have at least 5 characters. - Public link must not exceed 32 characters. - Sorry, a link can\'t start with a number. - You can set a public link on **Telegram**. If you do, other people will be able to find and join your group by this link.\n\nYou can use **a–z**, **0–9** and underscores.\nMinimum length is **5** characters. - You can set a public link on **Telegram**. If you do, other people will be able to find and follow your channel by this link.\n\nYou can use **a–z**, **0–9** and underscores.\nMinimum length is **5** characters. - Checking link availability… - t.me/%1$s is your current public link. - Loading actions… - Join Chat - Join %1$s chat - Join %1$s chats - Request to Join Channel - Request to Join Group - %1$s will be able to return to the group. - %1$s will not be able to return to the group unless added back by admin. - %1$s will be able to return to the channel. - %1$s will not be able to return to the channel unless added back by admin. - Unban - Ban Member - Remove from group - Remove from channel - Invite back to group - Invite back to channel - %1$s will not be able to return to the group unless added by another member or given an invite link. - %1$s will be able to add new admins with the same (or more limited) permissions. - %1$s will not be able to add new admins. - Share my contact - %1$s will be banned and removed from the channel. - %1$s will be removed and banned from the group. - %1$s will not be removed from the channel. - %1$s will not be removed from the group. - You do not have enough admin rights to ban %1$s in this chat. - You do not have enough admin rights to promote %1$s in this chat. - Recent Actions - All actions - Selected actions - All admins - Please specify at least one filter - **No recent actions**\n\nNo notable actions taken by the members and admins of this group in the last 48 hours. - **No recent actions**\n\nNo notable actions taken\nby the admins of this channel\nin the last 48 hours. - **No actions found**\n\nNo recent actions that match your query\nwere found. - No recent actions that contain \'%1$s\' have been found. - What are Recent Actions? - This is a list of all notable actions by group members and admins in the last 48 hours. - This is a list of all notable actions by channel admins in the last 48 hours. - banned %1$s - unbanned %1$s - banned %1$s\n\nDuration: %2$s - %1$s edited this message: - %1$s edited caption: - %1$s removed caption: - Original message - Original caption - Empty - %1$s pinned this message: - %1$s stopped the poll: - %1$s stopped the quiz: - %1$s unpinned message - %1$s deleted this message: - %1$s changed the group link: - %1$s changed the channel link: - %1$s removed group link: - %1$s removed channel link - Previous link - %1$s edited the group description: - %1$s edited the channel description: - %1$s removed the channel description - %1$s removed the group description - Previous description - %1$s enabled group invites - %1$s disabled group invites - %1$s enabled sender visibility - %1$s disabled sender visibility - %1$s enabled signatures - %1$s disabled signatures - %1$s enabled content protection - %1$s disabled content protection - Edited invite link %1$s\n\nUsage limit: %2$s → %3$s\nExpires: %4$s - never - today at %1$s - tomorrow at %1$s - %1$s at %2$s - Changed invite link %1$s usage limit: %2$s —> %3$s - Set invite link %1$s to never expire - Set invite link %1$s to expire today at %2$s - Set invite link %1$s to expire tomorrow at %2$s - Set invite link %1$s to expire %2$s at %3$s - no limit - changed default permissions - Send messages - Send media - Send photos - Send videos - Send music - Send files - Send voice messages - Send video messages - restricted %1$s\n\nDuration: %2$s - changed restrictions for %1$s\n\nDuration: %2$s - removed restrictions from %1$s - Send stickers & GIFs - Send stickers & GIFs - Send polls - Send polls - Change info - Edit own tag - Change info - Edit own tag - Create topics - Create topics - Pin messages - Pin messages - Add users - Add users - Send media - Send music - Send files - Send photos - Send videos - Send voice messages - Send video messages - Send messages - Embed links - React to messages - Embed links - React to messages - Read messages - promoted %1$s - changed privileges of %1$s - removed admin privileges of %1$s - Change channel info - Change group info - Manage channel - Manage group - Post messages - Edit messages - Delete messages - Post stories - Edit stories of others - Delete stories of others - Add admins - Manage topics - Remain anonymous - Manage video chats - Manage live streams - Manage direct messages - Title: %1$s - Title: %1$s → %2$s - Ban users - Add users - Pin messages - Edit member tags - All actions - New restrictions - Admin rights - New members - Invite links - Group info - Group settings - Channel settings - Channel info - Deleted messages - Edited messages - Pinned messages - Members leaving - Video chats - Live streams - %1$s set the slow mode timer to %2$s - %1$s disabled the slow mode - You set the slow mode timer to %1$s - %1$s disabled the slow mode - %1$s linked this group to %2$s - %1$s unlinked this group from %2$s - This group was linked to %1$s - This group was unlinked from %1$s - %1$s made %2$s the discussion group for this channel - %1$s removed the discussion group %2$s - %1$s set group location to %2$s - - %1$s enabled aggressive anti-spam - %1$s disabled aggressive anti-spam - You enabled aggressive anti-spam - You disabled aggressive anti-spam - - %1$s changed active usernames from %2$s to %3$s - You changed active usernames from %1$s to %2$s - %1$s changed usernames order from %2$s to %3$s - You changed usernames order from %1$s to %2$s - %1$s activated %2$s username - %1$s deactivated %2$s username - You activated %1$s username - You deactivated %1$s username - %2$s activated %1$s username: %3$s - %2$s activated %1$s usernames: %3$s - %2$s deactivated %1$s username: %3$s - %2$s deactivated %1$s usernames: %3$s - You activated %1$s username: %2$s - You activated %1$s usernames: %2$s - You deactivated %1$s username: %2$s - You deactivated %1$s usernames: %2$s - - You removed tag for %2$s "%1$s" - You set tag for %2$s "%1$s" - %2$s removed your tag "%1$s" - %2$s removed tag for %3$s "%1$s" - %2$s set your tag "%1$s" - %2$s set tag for %3$s "%1$s" - - %1$s enabled auto-translation - %1$s disabled auto-translation - You enabled auto-translation - You disabled auto-translation - - %1$s enabled topics - %1$s disabled topics - You enabled topics - You disabled topics - %1$s pinned topic %2$s - You pinned topic %1$s - %1$s created topic %2$s - You created topic %1$s - %1$s deleted topic %2$s - You deleted topic %1$s - %1$s changed topic name from %2$s to %3$s - You changed topic name from %1$s to %2$s - %1$s closed topic %2$s - You closed topic %1$s - %1$s reopened the topic %2$s - You reopened the topic %1$s - %1$s made topic %2$s hidden - You made topic %1$s hidden - %1$s made topic %2$s visible - You made topic %1$s visible - - %1$s muted new video chat participants - %1$s allowed new video chat participants to speak - You muted new video chat participants - You allowed new video chat participants to speak - %1$s muted %2$s in the video chat - %1$s allowed %2$s to speak in the video chat - You muted %1$s in the video chat - You allowed %1$s to speak in the video chat - - %1$s muted new live stream participants - %1$s allowed new live stream participants to speak - You muted new live stream participants - You allowed new live stream participants to speak - %1$s muted %2$s in the live stream - %1$s allowed %2$s to speak in the live stream - You muted %1$s in the live stream - You allowed %1$s to speak in the live stream - - %1$s changed %2$s\'s volume to %3$s - You changed %1$s\'s volume to %2$s - %1$s changed your volume to %2$s - %1$s changed group location to %2$s - %1$s removed group location - transferred ownership to %1$s - is no longer an owner - - Enabled reactions: - Disabled all reactions - Changed available reactions: - Enabled all reactions - Limited available reactions to: - + Added: - – Removed: - - %1$s changed accent color from %2$s to %3$s - You changed accent color from %1$s to %2$s - - %1$s changed emoji status from %2$s to %3$s - You changed emoji status from %1$s to %2$s - %1$s changed emoji status from none to %2$s - You changed emoji status from none to %1$s - %1$s changed emoji status from %2$s to none - You changed emoji status from %1$s to none - - %1$s changed emoji from %2$s to %3$s - You changed emoji from %1$s to %2$s - %1$s changed emoji from none to %2$s - You changed emoji from none to %1$s - %1$s changed emoji from %2$s to none - You changed emoji from %1$s to none - - %1$s changed profile emoji from %2$s to %3$s - You changed profile emoji from %1$s to %2$s - %1$s changed profile emoji from none to %2$s - You changed profile emoji from none to %1$s - %1$s changed profile emoji from %2$s to none - You changed profile emoji from %1$s to none - - %1$s changed profile color from %2$s to %3$s - You changed profile color from %1$s to %2$s - %1$s changed profile color from none to %2$s - You changed profile color from none to %1$s - %1$s changed profile color from %2$s to none - You changed profile color from %1$s to none - - %1$s changed profile color and icon from %2$s to %3$s - You changed profile color and icon from %1$s to %2$s - %1$s changed profile color and icon from none to %2$s - You changed profile color and icon from none to %1$s - %1$s changed profile color and icon from %2$s to none - You changed profile color and icon from %1$s to none - - %1$s changed the channel background - You changed the channel background - %1$s unset the channel background - You unset the channel background - - %1$s changed the chat background - You changed the chat background - %1$s unset the chat background - You unset the chat background - - Until %1$s - Network Usage - Recently Used - Trending statuses - Add to Favorites - Remove from Favorites - Hold to record audio. Tap to switch to video. - Hold to record video. Tap to switch to audio. - Sending animated emoji requires **Telegram Premium** - %1$s accepts new chats only from contacts and **Telegram Premium** users. - Message %2$s for %1$s **star** per message - Message %2$s for %1$s **stars** per message - %1$s\'s Telegram client doesn\'t support this feature. They need to install an update first. - Record HQ Round Videos - Discard Video Message - Are you sure you want to discard your video message? - Discard Audio Message - Are you sure you want to discard your audio message? - Discard - Feature is not available for this type of media - %1$s made group history hidden for new members - %1$s made group history visible for new members - %1$s changed group sticker set - %1$s removed group sticker set - %1$s changed group emoji set - %1$s removed group emoji set - Chat History for New Members - New members will see messages that were sent before they joined. - New members won\'t see earlier messages. - Hidden - New members won\'t see more than %1$s earlier message. - New members won\'t see more than %1$s earlier messages. - Visible - Discard current changes? - Free - Original - Start with rear-facing camera - Email - Beginning - You successfully transferred %1$s to %2$s for %3$s - You successfully transferred %1$s to %2$s - %1$s refunded %2$s - You received %1$s star for %2$s - You received %1$s stars for %2$s - %3$s received %1$s star for %2$s - %3$s received %1$s stars for %2$s - View Message - Saved Messages - Saved - Direct messages were enabled in this channel - %1$s now accepts direct messages - %2$s now accepts direct messages for %1$s star each - %2$s now accepts direct messages for %1$s stars each - %1$s disabled direct messages - Channel "%1$s" created - Linked chat not found - %1$s joined the channel - You joined the channel - %1$s left the channel - You left the channel - Installed - as separate messages - as one message - as %1$s message - as %1$s messages - " video" - " videos" - " photo" - " photos" - " media" - " media" - Pinned message: %1$s - Pinned message changed - Edit Markdown - Force built-in media decoding - Disable HLS video playback - Compress audio in videos - Edit text in messages using shortcuts: `**`**bold**`**`, `__`__italic__`__`, `~~`~~strikethrough~~`~~`, ````monospace````, `||`||spoiler||`||`, `[`text`](`url`)` - Message not found - This message is from a private chat - - Sync contacts with Telegram? - Sync - Privacy Policy - Contacts on your device will be seamlessly uploaded to Telegram servers so you could find them in **Contacts** section of **%1$s**.\n\nWhen you delete a contact on your device while sync is on, it will also be deleted from your contacts list on **Telegram** servers.\n\nYou can always turn sync off or clear data on Telegram servers via **Settings > Privacy and Security > Delete Synced Contacts**.\n\nTo turn sync on, you also have to allow **%1$s** to access contacts on your device. - To turn contacts sync on and seamlessly upload them to Telegram, allow access to your contacts.\n\nTap **Settings** > **Permissions**, and turn **Contacts** on. - Tap Settings > Permissions, and turn Contacts on to allow **%1$s** access to your contacts to find them on Telegram. - - Continue - **No chats to show**\n\nInvite your friends and family to join Telegram - Start a chat - %1$s is using Telegram - %1$s and %2$s are using Telegram - %2$s and %1$s more of your contacts are using Telegram - %2$s and %1$s more of your contacts are using Telegram - Search People - 1000+ contacts on Telegram - Hey, I\'m using Telegram to chat – and so is %1$s of our other contacts. Join us! Download it here: %2$s - Hey, I\'m using Telegram to chat – and so are %1$s of our other contacts. Join us! Download it here: %2$s - Hey, I\'m using Telegram to chat – and so are 1000+ of our other contacts. Join us! Download it here: %1$s - Invite Contacts - Specify at least one restriction rule - Specify at least one admin rule - Member tag is too long - Member tag must not include emoji - Would you like to enable extended link previews in Secret Chats? Note that link previews are generated on Telegram servers. - Please note that inline bots are provided by third-party developers. For the bot to work, the symbols you type after the bot\'s username are sent to the respective developer. - Clear Recent Emoji - Clear Recent Reactions - Doodle - Arrow - Rectangle - Fill color - Text exceeds the limit by %1$s character. - Text exceeds the limit by %1$s characters. - Caption exceeds the limit by %1$s character. - Caption exceeds the limit by %1$s characters. - Cannot access this chat - You were banned in this group - You were banned in this channel - This group is private - This channel is private - You can\'t add members to this chat - We\'ve sent a 6-digit recovery code to %1$s. Please check your email and enter it here. - The verification code has been resent to your email. - We\'ve sent you a 6-digit recovery code. Please check your email and enter it here. - Having trouble accessing your email? - Telegram Call - Phone Call - Set as current - Archive sticker set %1$s? You can restore it later in Settings > Stickers > Archived. - Archive emoji pack %1$s? You can restore it later in Settings > Emoji > Archived. - Archive - Archive pack - Clear drawing - Failed to play video message, see logs for details. - Failed to play video, see logs for details. - Error log - Video format is not supported. - Failed to play GIF, see logs for details. - GIF format is not supported. - See logs - Failed to play audio, see logs for details. - Audio format is not supported. - Download %1$s - Resume Download - Pause Download - Highlight in List - Reverse Order - Play Next - Add to Playlist - Play Next - Remove %1$s from current playlist? - Remove - Next - Previous - Play - Pause - Resume - Stop - Default notification settings for all private chats and mentions. - Default notification settings for all group chats. - Default notification settings for all channels. - Custom notification settings for the Secret Chat with %1$s. - Custom notification settings for messages and mentions from %1$s. - Custom notification settings for the Group "%1$s". - Custom notification settings for the Group "%1$s" (%2$s). - Custom notification settings for the Channel "%1$s". - Custom notification settings for the Channel "%1$s" (%2$s). - Custom: %1$s - Music Player - Incoming Call - Outgoing Call - More settings - Custom - Incognito Keyboard - Request keyboard to not update any personalized data such as typing history and personalized language model based on what you type in Secret Chats.\n\nBe aware that this setting is not a guarantee, and some IMEs may not respect it. - This message could not be displayed because of an error. We are very sorry for that.\n\nPlease copy the scary error details below and submit them to @tgandroidtests so we can investigate the issue. Thank you! - Peer-to-Peer in Calls - Disabling peer-to-peer will relay all calls through Telegram servers to avoid revealing your IP address, but may decrease audio quality. - Disabled - System Default - System - Automatic - Scheduled - Detect current sunset & sunrise time - Determining location… - There is currently no sunrise or sunset at your current location. - From - To - Switch to night theme based on ambient lighting or your time preference. - Switch to night theme when ambient lighting falls below %1$d%%.\n\nSmall dot indicates current level of ambient lighting measured by your device. - Switch to night theme based on your time preference. - Switch to night theme based on your system settings. - Switch to night theme based on the value provided by system. - Bots - Logged In with Telegram - **No active logins**\n\nYou can log in on websites that support signing in with Telegram. - Disconnect All Websites - You can log in on websites that support signing in with Telegram. - Connected Websites - Disconnect %1$s? - Disconnect - Disconnect Website - Are you sure you want to disconnect all websites? - Block %1$s - Tap to disconnect from your Telegram account. - Light - Disabled - Default - Blue - Orange - Yellow - Green - Cyan - Red - Purple - Pink - White - Error updating photo: %1$s - Bot %1$s not found - Add Account - Answering as %1$s - Go to source chat - Directions… - Foursquare - Live Location - Accurate to %1$s meter - Accurate to %1$s meters - %1$s string - %1$s strings - Share Live Location - Updated in real time as you move - Pull up to see places - Finding Places… - No places found - You are sharing Live Location with %1$s chat - You are sharing Live Location with %1$s chats - Choose for how long %1$s will see your live location. - Choose for how long people in this chat will see your accurate location, including when the app is closed. - Stop Sharing Live Location - Would you like stop sharing Live Location to all chats? - Would you like stop sharing Live Location with %1$s? - sharing with %1$s chat - sharing with %1$s chats - sharing with %1$s - sharing with %1$s - You and %1$s - Stop All - Stop Sharing - Sorry, public groups are unavailable for your account. - Stop Sharing Location - Apply to all - Dropped Pin - Calculating distance… - Go - Light - Dark - Satellite - Terrain - Hybrid - typing - %1$s is typing - %1$s are typing - recording voice - %1$s is recording voice - %1$s are recording voice - sending voice - %1$s is sending voice - %1$s are sending voice - recording video - %1$s is recording video - %1$s are recording videos - choosing location - %1$s is choosing location - %1$s are choosing locations - choosing a contact… - %1$s is choosing a contact… - %1$s are choosing contacts… - recording a video message - %1$s is recording a video message - %1$s are recording video messages - sending a video message - %1$s is sending a video message - %1$s are sending video messages - sending photo - %1$s is sending photo - %1$s are sending photos - playing - %1$s is playing - %1$s are playing - sending video - %1$s is sending video - %1$s are sending videos - sending file - %1$s is sending file - %1$s are sending files - Live Locations - Report message from %1$s - Report messages from %1$s - Report %1$s\'s message - Report %1$s\'s messages - Report %1$s message - Report %1$s messages - - Are you sure you want to report message from %1$s? - Are you sure you want to report messages from %1$s? - Are you sure you want to report %1$s\'s message? - Are you sure you want to report %1$s\'s messages? - Are you sure you want to report %1$s message? - Are you sure you want to report %1$s messages? - Report - - Sticker suggestions by emoji - Installed + recommended - Only installed - None - Image Preview - Error Searching Places - Share as… - Perform action as… - Open link as… - %1$s (current) - %1$s (last used) - Proceed - Unable to detect current location. - Open in Instant View - Whenever you open a link, Telegram will try to generate an Instant View page for it. - No links - telegram.org + telegra.ph - All links - Unknown or broken link format - Sorry, this link type is not yet supported. - Update required - Update - Proxy sponsor - via %1$s - %1$s via %2$s - admin - owner - channel - group - Member tag - A title that members will see instead of \'%1$s\'. - Who can call me - Use peer-to-peer with - Visible - Hidden - Visible only for contacts - Nobody can see your Last Seen - Nobody (%1$s) can see your Last Seen - Only contacts can see your Last Seen - Only contacts (%1$s) can see your Last Seen - Everybody can see your Last Seen - Everybody (%1$s) can see your Last Seen - Nobody can add you - Nobody (%1$s) can add you - Only contacts can add you - Only contacts (%1$s) can add you - Everybody can add you - Everybody (%1$s) can add you - Allowed - Disallowed - Only contacts - Only contacts and **Telegram Premium** users - Only **Telegram Premium** users - Nobody can call you - Nobody (%1$s) can call you - Only contacts can call you - Only contacts (%1$s) can call you - Everybody can call you - Everybody (%1$s) can call you - Allowed - Disallowed - Only contacts - Disabled - Disabled (%1$s) - Only for contacts - Only for contacts (%1$s) - Enabled - Enabled (%1$s) - Allowed - Disallowed - Only contacts - Enabling notifications for this chat will override the global value in Settings > Notifications (%1$s). - Enabling notifications for these chats will override the global value in Settings > Notifications (%1$s). - Enabling notifications for some of selected chats will override the global value in Settings > Notifications (%1$s). - Use global settings (%1$s) - Enabled - Unmutes in %1$s - Disabled - %1$s (default) - Notifications from this chat are explicitly enabled. - Show error details - Hide error details - Reorder by ping - Remove proxy - Edit proxy - Delete this proxy configuration? - You can\'t add the selected users to groups because of their privacy settings. - Sync Contacts - Turn on to continuously sync contacts from this device with your account. - Contacts from this device will be added to your account. - Delete Synced Contacts - Delete Synced Contacts - This will remove your contacts from the Telegram servers. If \'Sync Contacts\' is enabled, contacts will be re-synced. - You allowed this bot to message you when you logged in on %1$s. - You allowed this bot to message you in its web-app. - You allowed this bot to message you when you added it to your attachment menu. - You allowed this bot to message you when launched its "%1$s" app. - None - Share - Reply - Link Previews - Link previews will be generated on Telegram servers. We do not store any data about the links you send. - Clear Payment and Shipping Info - Shipping info - Payment info - Delete your shipping info and instruct all payment providers to remove your saved credit cards? Note that Telegram never stores your credit card data. - Suggest Frequent Contacts - This will delete all data about the people you message frequently as well as the inline bots you are likely to use. - Delete and Disable - Mark as read - Mark as unread - Mark Folder as Read - Create Link - Create a New Link - Create an Invite Link - URL - Save - Cancel - For security reasons, you can\'t terminate older sessions from a device that you\'ve just connected. Please use an earlier connection or wait for a few hours. - Disable - Sessions - Websites - Mark as Read - %1$s message from %2$s - %1$s messages from %2$s - %1$s message from you - %1$s messages from you - %1$s message from %2$s - %1$s messages from %2$s - messages from %1$s - messages from you - messages from %1$s - %1$s - Messages from you - Messages from %1$s - Messages from %1$s - Messages from anonymous admins - Remove bot from suggestions? - Help - Settings - Clear formatting - Bold - Italic - Monospace - Spoiler - Quote - Strikethrough - Underline - Create Link - Playback through earpiece - Never - When close to an ear - Always - Try again in %1$s second - Try again in %1$s seconds - Try again in %1$s minute - Try again in %1$s minutes - Try again in %1$s hour - Try again in %1$s hours - Too many requests. %1$s - Join Channel - Warning: you will lose all your admin rights and will not be able to return to this channel unless added by an admin - Warning: you will lose all your admin rights and will not be able to return to this group unless added by another member - Warning: you will not be able to return to this channel unless added by an admin - Warning: you will not be able to return to this group unless added by another member - Warning: you might not be able to return to this channel unless added by an admin - Warning: you might not be able to return to this group unless added by another member - You will be able to return to this channel by its public link - You will be able to return to this group by its public link - Are you sure you want to delete the chat with %1$s? This action cannot be undone. - Are you sure you want to block %1$s and delete the chat with it? This action cannot be undone. - Are you sure you want to delete all **Saved Messages**? This action cannot be undone. - Are you sure you want to cancel the secret chat with %1$s? - Are you sure you want to delete the secret chat with %1$s? This action cannot be undone. - Are you sure you want to delete the secret chat with %1$s? All chat history will be deleted forever. This action cannot be undone. - Delete all messages for %1$s - Clear for all members - Chat with %1$s - Secret chat with %1$s - Leave - Delete chat from list - Destroy %1$s? - Destroy %2$s? It will disappear for you and %1$s other member. - Destroy %2$s? It will disappear for you and %1$s other members. - Copyright - Advanced - Delete my account if away for - If you do not come online at least once within this period, your account will be deleted along with all messages and contacts. - Delete All Cloud Drafts - Are you sure you want to delete all cloud drafts? - Separate photo and video tabs - Media - Photos - Videos - Voice - Video - Video Messages - GIFs - Docs - Links - Audio - Groups - Similar - Similar - Admins - Blocked - Restricted - Members - Messages - More - More - More - More options… - Pin - Pin album - Pin playlist - Pin files - Unpin - Unpin album - Unpin playlist - Unpin files - Report message - Show in chat - Cannot perform this action, because user account is deactivated. - Group upgraded to supergroup. Tap here to view older history. - Group upgraded to supergroup. - Members with restrictions - Administrators - Banned members - Banned subscribers - Bot suggestions are disabled.\nTurn them back on in Settings > Privacy and Security. - View Chat - Remove Link - Wait! Are you sure you want to make %1$s private and release its public link? While free, it might be taken by any other user. - Hold finger to view this media - When you set up an additional passcode, you\'ll need to enter it each time you access this chat. Message preview will be hidden on the chats page.\n\nNote: if you forget it, contents of this chat will be lost.\n\nIf you need a global passcode, use Settings > Privacy and Security > Passcode Lock. - Content Locked - Drag chat to reorder - Open in Maps - Map Preview Provider - When you receive a map or live location, in order to display a map preview, it has to be generated by the selected provider.\n\nThis requires sending an anonymous request with the received location coordinates. - Choose a provider to display map previews in Secret Chats.\n\nThis requires sending the selected provider an anonymous request with the received coordinates. - No Previews - Unset - Google Maps - Telegram - Invalid Localization File - Are you sure you want to apply this localization file?\n\nLanguage: %1$s (%2$s)\nLocale: %3$s, %4$s\nTranslated: %5$d%% (%6$s) - %1$s untranslated - %1$s untranslated - Apply Localization - Warning: do not install localization files from untrusted sources. - Localization successfully applied - Official - Installed - Beta - Can\'t find your language? - Got it - Create - The list of available languages is managed by the [Translation Platform](https://translations.telegram.org).\n\nTelegram will offer you to switch to your language when a corresponding translation becomes officially available.\n\nWhile you\'re waiting, you can install custom localization files, join the [translation process](https://translations.telegram.org/en/android_x/), or create [your own](https://t.me/tgx_android_translate/) localization files. - OK - Are you sure you want to delete this localization file?\n\n%1$s / %2$s will no longer be available in the list of installed languages. - Delete Localization - Localization file is empty - Share as XML - %1$s (%2$d%%) - File Name - Create Localization - Create - Edit Localization - View Strings - Current string (%1$s) has been modified. Would you like to save changes? - Save Changes - Discard Changes - Translation - Save & Exit - Copy original - Paste original - YOUR_FILE_NAME - https://telegram.org/faq#general-questions - https://telegram.org/privacy - https://telegram.org/privacy#3-4-phone-number-and-contacts - https://translations.telegram.org/en/android_x/unsorted/ - https://telegram.org/faq#q-i-have-a-new-phone-number-what-do-i-do - https://ads.telegram.org - %1$ss - %1$ss - %1$sm - %1$sm - %1$sh - %1$sh - %1$sd - %1$sd - %1$sw - %1$sw - - ends in %1$s - - Sorry, you can pin up to %1$s chat and %1$s secret chat at once. - Sorry, you can pin up to %1$s chats and %1$s secret chats at once. - - Copy String - Show Toast - Untranslated - Strings - Translation Platform - Locale. Examples: **ja-JP**, **zh-CN**, **ro-RO** - %1$s / %2$s\n\nExported from %3$s - - Main - JSON data - URLs - Formats - Relative dates - Plurals - Formatted strings - Simple strings - - Nothing to clear. - OK. Freed %1$s. - Failure. - - %1$s folder - %1$s folders - Root Directory - Application Files - Application Media - **Warning!**\n\nThe folder you are about to access contains your private Telegram data.\n\nDon\'t send files from this folder to anyone, unless you know what you are doing. - Proceed - - Save edited photos to Gallery - Remember media grouping setting - - Processing %1$s - %1$d%% %2$s - - Reinhardt - True Survivor - David Hasselhoff - Bring it on! I **LIVE** for this! - Reinhardt, we need to find you some new tunes 🎶. - Ah, you kids today with techno music! You should enjoy the classics, like Hasselhoff! - I can\'t even take you seriously right now. - - Daenerys - Angela Merkel - Julian Assange - Pierre - Weekend Plans - Are you sure it\'s safe here? - Yes, sure, don\'t worry. - Hallo alle zusammen! Is the NSA reading this? 😄 - Sorry, I\'ll have to publish this conversation on the web. - Wait, we could have made so much money on this! - - Eileen Lockhard - So, why is Telegram cool? - Well, look. Telegram is superfast and you can use it on all your devices at the same time – phones, tablets, even desktops. - 😴 - And it has secret chats, like this one, with end-to-end encryption! - End encryption to what end?? - Arrgh. Forget it. You can set a timer and send message that will disappear when the time runs out. Yay! - 😱🙈👍 - - Space Dandy - You see this chat preview because you are a **Translator**.\n\nPlease refer to @tgx_android_translate for guide on how to make your own scenes. - I knew it! Please don\'t ever tell me this again… - - 0 - - **Frogram X** was updated to version %1$s\n\nBrief overview of new features:\n%2$s - - You\'re currently offline. Please connect to the Internet in order to start messaging. - You currently have airplane mode enabled. Please turn it off or connect to Wi-Fi in order to start messaging. - Frogram X is unable to quickly establish connection with the server.\n\nPlease check your network connection or wait until this pop-up disappears automatically.\n\nProxy servers may be helpful in accessing Telegram if there is no connection in your region. - - Please send an email to %1$s and tell us about your problem - - sms@telegram.org - recover@telegram.org - - Frogram X connection issue - My Internet service provider is: (please enter the name)\n\nI\'ve just installed the application and tried to start messaging, but Frogram X is unable to connect to the server. Please help.\n\nApp version: %1$s\nLanguage: %2$s\nAwait time: %3$s\nSystem Language: %4$s\nSystem Version: %5$s - - Frogram X SMS not sent: %1$s - My Internet service provider is: (please enter the name)\n\nI\'m trying to use my mobile phone number: %1$s\nBut Telegram could not send me SMS with the confirmation code. Please help.\n\nBelow are all details that might help understanding the issue.\nError: %3$s\n%2$s - - Invalid phone number: %1$s - My mobile phone operator: (please enter the name)\nI\'m trying to use my mobile phone number: %1$s\nBut Telegram says it\'s invalid. Please help. - - Banned phone number: %1$s - I\'m trying to use my mobile phone number: %1$s\nBut Telegram says it\'s banned. Please help. - - Frogram X error: %1$s - I\'m trying to use my mobile phone number: %1$s\nBut Telegram shows an error. Please help.\nError: %2$s - - App version: %1$s\nLanguage: %2$s\nSystem Language: %3$s\nSystem Version: %4$s - - Are you sure you want to log out as %1$s?\n\nNote that you can seamlessly use Telegram on all your devices at once.\n\nRemember, logging out kills all your Secret Chats. Downloaded media will be erased from this device. - Sign out as %1$s? All secret chats on this account will be lost. Downloaded media will be erased from this device. - - Alternative options - Add another account - Set up multiple phone numbers and easily switch between them. - Set a Passcode - Lock the app with a passcode so that others can\'t open it. - Clear Cache - Free up disk space on your device; your media will stay in the cloud. - Change Phone Number - Move your contacts, groups, messages and media to a new number. - Contact Support - Tell us about any issues; logging out doesn\'t usually help. - Remember, logging out kills all your Secret Chats. Downloaded media will be erased from this device. - Sign out without deleting the account. You can sign back in using the same phone number to access your chats. - Tell us about any issues; after you delete the account, we won\'t be able to restore any data you lose in the process. - - Push Services - - TDLib Logs - **Warning:** TDLib Logs may contain **private data**.\n\nDo not share them with anyone, unless you know what you are doing. - Proceed - **Warning:** call diagnostics may contain **private data** such as IP addresses of the parties.\n\nDo not share them with anyone, unless you know what you are doing. - - No email application found - - Right-to-Left Layout - - Create New Theme - New theme will be based on the %1$s theme. - %1$s theme - Create Copy - Create - New Theme - Name - Wallpaper Link - Edit - Delete - Delete Theme - Permanently delete this theme? This action can\'t be undone. - Minimize - Close - - Accent - This list contains accent colors of the app.\nRefer to other categories for the granular setup. - Content - Header - Controls - Chats - Bubbles - Media - Instant View - Other - Service - - Text - Music Player - Icons - Background - These colors are displayed in Settings > Themes and Chats.\nMake sure they clearly represent corresponding themes on your **filling** color. - These colors are used as a transparent overlay when the corresponding wallpaper is set: dates, unread separators, inline keyboards, etc.\n\nDo not change them unless you are looking for a better color. - Unsorted - Attachment Menu - Media - - Red - Orange - Pink - Green - Purple - Cyan - Blue - - Hex - - R - G - B - A - - Default - H - S - L - A% - - Edit Name - Edit Wallpaper - Color Format - - Remove Transparency - Background (color or identifier) - Calculate - - Delete %1$s other version of %2$s?\n\nThis action cannot be undone. - Delete all %1$s other versions of %2$s?\n\nThis action cannot be undone. - Delete %1$s color - Delete %1$s colors - Delete current version of %1$s?\n\nThis action cannot be undone. - Delete Color - - Hex (#RRGGBBAA) - RGBA (Red, Green, Blue, Alpha) - HSLA (Hue, Saturation, Lightness, Alpha) - - Export - Export - If you specify the author\'s username, it will be displayed to users before they install the theme. - - Theme Author - Username or link - - %1$s (copy) - %1$s #%2$d - - Apply %1$s theme? - Apply %1$s theme by %2$s? - You can switch between installed themes in Settings > Themes and Chats - Apply theme - - %1$s color - %1$s colors - - %1$s property - %1$s properties - - %1$s item - %1$s items - - Default - - Properties - Edit Property - - Theme, %1$s - Demo - - Hold to see **fillingPressed** in action. Used on **Android 4.x only**. - Placeholder color used before image gets loaded. - Transparent background for the previews of stickers, media and chats. - Three-dot menus, sticker suggestions, small circle buttons, etc. - Swipe to see **fillingNegative** in action. - Background of the Send button in the Share menu. - Current query highlight when searching chats, contacts, etc. - Selected text background. - Pressed link background. - Buttons with neutral effect: save, done, cancel, etc. - Buttons with negative effect: delete, remove, clear, etc. - Color overlay for the drawer header. When empty, **header** color is used. - Text color for the drawer header. When empty, **headerText** color is used. - APK files - Archive files: .zip, .rar, .7z - PDF files - Light header is used when selecting media, messages, etc. - Solid chat background used when wallpaper is not set.\n\nWhen empty, **background** color is used instead. - Not yet downloaded part of the file. - Downloaded part of the file. - Playback progress of the file. - New trending sticker set - Used on **Android 5.x** and lower. - - Default values are inherited from this theme when a color or property is not explicitly set. - Replaces horizontal shadows with thin solid separators. - Depth of all shadows. Higher value means darker shadow. Default: light themes – 0.5, dark – 1.0 - Image corner radius. Usually ignored in bubble mode. - Bubble corner radius. - Bubble corner radius when merged with another bubble. - Bubble corner radius on **Android 4.x**. Max value: **6**. - Enables a solid outline for bubbles. You can configure its color with **bubbleOut_outline** or **bubbleIn_outline**.\n\nEnable this property if you change **bubbleCorner** values. - Width of the bubble outline. Used when **bubbleOutline** is enabled. - Transparency of **headerText** or **headerLightText** in the tab navigation, header subtitles, etc. - Default wallpaper identifier. 0 means wallpaper is disabled by default. Hold wallpaper thumbnail in settings to know its identifier. For solid wallpapers set to 0 and edit **bubble_chatBackground** color. - A magic property that allows sharing wallpaper settings between similar themes. **0** – light, **1** – dark, **2** – exclusive to theme.\n\nSet to **2**, if your color palette significantly differs from **parentTheme**, or if you disable default wallpaper while creating light theme. - Determines if the theme is dark and should be used at night.\n\nIt is preferable to change **parentTheme** instead of overriding this property. - Background corner radius for dates in the bubble mode. - Background corner radius for dates in the plain mode. - Adds shadow to the unread messages separator in the bubble mode. - When enabled, status bar icons will use dark colors. Used on **Android 6.x** and higher. - - These colors are used when wallpaper is disabled or not yet loaded.\n\nIf your theme does not allow disabling wallpaper, you can ignore them. - - %1$s, %2$s - - Check out %2$s\'s post: %1$s - Check out %2$s\'s message: %1$s - Check out %2$s\'s comment: %1$s - - %1$s\'s profile photo - "%1$s"\'s chat photo - %1$s\'s photo - - Check out %1$s: %2$s - Contact %1$s on Telegram: %2$s - Contact %1$s: %2$s - Contact me on Telegram: %1$s - My Telegram link: %1$s - Use %1$s on Telegram: %2$s - Join "%1$s" on Telegram: %2$s - Follow %1$s on Telegram: %2$s - Proxy for Telegram: %1$s. This link may be helpful in accessing Telegram if there is no connection in your region. - %1$s\n\nThis link may be helpful in accessing Telegram in censored regions. - Check out "%1$s" sticker set for Telegram: %2$s - Check out "%1$s" sticker set: %2$s - Check out %1$s translation for Telegram: %2$s - - Share to… - - %1$s: %2$s - %1$s (%2$s) - %1$s\n\n%2$s - - Photo from %1$s - Share photo to… - Share %1$s photo to… - Share %1$s photos to… - - Video from %1$s - Share video to… - Share %1$s video to… - Share %1$s videos to… - - GIF from %1$s - Share GIF to… - Share %1$s GIF to… - Share %1$s GIFs to… - - Music from %1$s - Share audio to… - Share %1$s audio to… - Share %1$s audios to… - - File from %1$s - Share file to… - Share %1$s file to… - Share %1$s files to… - - Share %1$s file to… - Share %1$s files to… - - Media from %1$s - Share media to… - Share %1$s media to… - Share %1$s media to… - - Share contact to… - - Message from %1$s - - Chat with %1$s - - Share Link - Share Link - Share Link - Share Bot - Share Proxy - Share Language - Share Stickers - - Share Contact - Saved - - Cancel Account Reset - Somebody with access to your phone number **%1$s** has requested to delete your Telegram account and reset your 2-Step Verification password.\n\nIf this wasn\'t you, please enter the code we\'ve just sent you via SMS to your number. You can also cancel this by **changing your phone number** to a number you control. - - %1$s mention - %1$s mentions - [edited]: %1$s - %1$s - - Mute - Mute %1$s - Mute all - - Unmute - Unmute %1$s - Unmute all - - Muted %1$s for 1 hour - Muted %1$s for 1 hour - Muted %1$s person for 1 hour - Muted %1$s people for 1 hour - - Unmuted %1$s - Unmuted %1$s - Unmuted %1$s person - Unmuted %1$s people - - Marked messages as read - Marked mentions as read - - Default - Enabled - Disabled - - Content Hidden - You have a new message - - Open Cloud Chat - - System Notification Settings - Badge Counter - Include Muted Chats - Count Unread Messages - Include Archived Chats - Switch on to show the number of unread messages instead of chats. - Switch off to show the number of unread chats instead of messages. - You can set custom notifications for specific users on their profile page. - You can set custom notifications for specific groups on their profile page. - You can set custom notifications for specific channels on their profile page. - Include Dismissed Messages - Switch on to include previously dismissed unread messages when new notification arrives from a chat. - Switch off to exclude previously dismissed unread messages when new notification arrives from a chat. - - Channels - - Mentions and Replies - - Personal Notifications - - Switch off to apply group notification settings when someone pins a message. You will receive no notification if the group is muted. - Switch on to apply private notification settings when someone pins a message. You will receive no notification if message author is muted. - - Switch off to apply group notification settings to mentions and replies. You will receive no notifications if the group is muted. - Switch on to apply private notification settings to mentions and replies. You will receive no notifications if message author is muted. - - Merge notification categories - Turn on to display notifications from private chats, groups and channels in a single notification group. - Turn off to display notifications from private chats, groups and channels separately. - - Default - Enabled - Disabled - - Default - Enabled - Disabled - - Private - Secret - Group Chats - Groups - Channels - Bots - Read - Unread - Muted - Archived - Contacts - Non-Contacts - - %1$s bot - %1$s bots - - %1$s • %2$s - - Advanced - - Pinned: %1$s - %1$s (pinned message) - - If a person has left the group in the past, you need to be in their Telegram contacts to add them back.\n\nThey can still join via the group\'s invite link as long as they are not on the Removed Users list. - The admins of this group have restricted your ability to send polls. - Sorry, this language pack doesn\'t exist - This feature is not available. Please make sure the app is up-to-date, or wait for new updates. - Page not found or no longer exists. - Sorry, you don\'t have access to this chat or channel. - Sorry, anonymous administrators cannot leave reactions or participate in polls. - Sorry, you don\'t have access to this chat or channel. - Sticker set not found or no longer exists. - Chat is inaccessible - Can\'t access the chat - Sorry, you are a member of too many groups or channels. Please leave some before joining a new one. - Sorry, this phone number is banned. Contact us at login@telegram.org if you need help. - Sorry, you have too many location-based groups already. Please delete one of your existing ones first. - This feature requires Telegram Premium subscription. - Request to join this chat has been sent. - The link is expired or was revoked by creator. - Sorry, the user restricted who can add them to chats in their privacy settings. - Sorry, the user restricted this action in their privacy settings. - Sorry, you can interact only with mutual contacts at the moment. - There are too many bots in this group. Please remove some of the bots you\'re not using first. - Sorry, this group has too many admins. Please remove one of the existing admins first. - Folder must contain at least one chat - Sorry, you have too many shareable folders. - Sorry, you have too many invite links. - The date you specified is invalid. - - Notification Style - Sound and pop-up - Vibrate and pop-up - Pop up on screen - Sound - Vibrate - Silent - Silent - Silent (lower priority) - Silent and minimised - Disabled - - %1$s exception - %1$s exceptions - - New Contacts Notification - - Notifications - Notifications are enabled by default. You can mute specific chats from the chat list. - Notifications are blocked by default. Change Notification Style value to unblock them. - Notifications are disabled by default. You can unmute specific chats from the chat list. - - Secret Chats on Lock Screen - Turn off to hide secret chat notifications when the device is locked. You will still receive sounds, if the device is not muted. - Turn on to display secret chat notifications when device is locked. This doesn\'t reveal the contents of messages. - - Hide on Lock Screen - Turn off to display secret chat notifications when device is locked. This doesn\'t reveal the contents of messages. - Turn on to hide secret chat notifications when device is locked. You will still receive sound, if device is not muted. - - Reset all notification settings, including custom notification settings for your contacts, groups and channels? - - Notifications from Telegram are blocked in system settings. Tap System Notification Settings to unblock them. - Notifications for the current account are disabled in system settings.\n\nTo enable notifications:\n• Tap System Notification Settings\n• Find the "%1$s" notification category\n• Turn the toggle on to unblock notifications. - Notifications from Telegram are blocked in your device settings.\n\nTo enable notifications:\n• Tap System Notification Settings.\n• Turn on Show Notifications. - Notifications from Telegram are blocked in your system settings.\n\nTo enable notifications:\n• Go to system settings – Applications – Frogram X.\n• Tap Notifications – Allow notifications. - You have data sync turned off in system settings. Notifications may not arrive when app is closed.\n\nData sync may be implicitly turned off by the battery optimization mode on your device. - You have data sync turned off for Frogram X. Notifications may not arrive when app is closed.\n\nData sync may be implicitly turned off by the battery optimization mode on your device. - Google Play Services are unavailable. Please check you have them installed and up-to-date.\n\nNotifications may arrive with big delays or not arrive at all without them. - **Firebase Services** have failed to function properly due to error: %1$s\n\nNotifications may arrive with big delays or not arrive at all without them.\n\nPlease make sure:\n• Google Play Services are installed and up-to-date: https://support.google.com/googleplay/answer/9037938?hl=en\n• Frogram X is up-to-date\n• Firebase services are enabled\n• They are not blocked by your Internet service or DNS provider\n• If you have firewall or ad blocking software, Firebase domains are whitelisted\n• You can see 404 message in a browser on this page: https://firebaseinstallations.googleapis.com/\n• System date and time is correct\n• Problem doesn\'t go away after restarting your device\n• All system updates are installed\n• You are using the **official** version of Frogram X: @tgx_log\n\nIf the steps above do not help, try again with VPN that you trust, as it might be caused by Internet censorship applied by authorities in your region. - **Frogram X** was unable to display some notifications for this account due to an unknown system error.\n\nPlease make sure:\n• All system updates are installed\n• Frogram X is up-to-date\n• There are no notification restrictions in system settings.\n\nIf the steps above do not help, you might want to share the detailed error report to @tgandroidtests, or look up for troubleshooting tips for your device. - **Frogram X** was unable to display some notifications from %1$s due to an unknown system error.\n\nPlease make sure:\n• All system updates are installed\n• Frogram X is up-to-date\n• There are no notification restrictions in system settings.\n\nIf the steps above do not help, you might want to share the detailed error report to @tgandroidtests, or look up for troubleshooting tips for your device. - **Frogram X** was unable to display some notifications for this account due to notification categories system limit.\n\nPlease make sure:\n• All system updates are installed\n• Frogram X is up-to-date\n• There are no notification restrictions in system settings.\n\nIf the steps above do not help, you might want to ask @tgandroidtests for troubleshooting tips for your device, or re-install Frogram X, which should help resolving this error, but requires logging in to your account again. - **Frogram X** was unable to display some notifications from %1$s due to notification categories system limit.\n\nPlease make sure:\n• All system updates are installed\n• Frogram X is up-to-date\n• There are no notification restrictions in system settings.\n\nIf the steps above do not help, you might want to ask @tgandroidtests for troubleshooting tips for your device, or re-install Frogram X, which should help resolving this error, but requires logging in to your account again. - Turn on data sync - Turn on data sync - Get Google Play Services - Share Error Report - Tap to resolve issue - Try again - Share error details - - You are already using this language pack (**%1$s**). You can change your language at any time in Settings. - You are about to apply a language pack (**%1$s**) that is %2$d%% complete.\n\nThis will translate the entire interface. You can suggest corrections via the [translation platform](%3$s).\n\nYou can change your language back at any time in Settings. - You are about to apply a custom language pack (**%1$s**) that is %2$d%% complete.\n\nThis will translate the entire interface. You can suggest corrections via the [translation platform](%3$s).\n\nYou can change your language back at any time in Settings. - Change Language - Language successfully changed - Remove Language - Are you sure you want to delete this language?\n\n%1$s / %2$s will no longer be available in the languages list.\n\nYou can return it back later by following this link:\n%3$s - - We have sent you an email to confirm your address. - Resend code - Are you sure you want to abort Two-Step Verification setup? - Are you sure you want to abort recovery email setup? - To complete recovery email setup, check %1$s (don\'t forget the spam folder) and enter the code we just sent you. - To complete recovery email change, check %1$s (don\'t forget the spam folder) and enter the code we just sent you. - Abort recovery email setup - Abort recovery email change - - Testing Utilities - **Warning**: Testing Utilities are available for **testing** and **debugging** purposes **only**. None of them are guaranteed to work.\n\nDo not use them, unless you know what you are doing. - Copy Version - Copy Report Details - Use when submitting a bug report - - Log Files - Application Logs - Turn off all logs - Delete all application log files? - - New Poll - New Quiz - Retract Vote - Stop Poll - Stop Quiz - - This message cannot be forwarded to secret chats. - - If you stop this poll now, nobody will be able to vote in it anymore.\n\nThis action cannot be undone. - If you stop this quiz now, nobody will be able to participate in it anymore.\n\nThis action cannot be undone. - - View Results - View Results - View %1$s Result - View %1$s Results - View %1$s Result - View %1$s Results - Vote - - Quiz - Poll - Question - Ask a Question - Option - Poll options - Quiz options - Discard Poll - Are you sure you want to discard this poll? - Discard Quiz - Are you sure you want to discard this quiz? - Add an option… - You can add %1$s more option - You can add %1$s more options - You have added the maximum number of options. - - Anonymous Poll - Poll - Final Results - Anonymous Quiz - Quiz - Final Results - - Poll Results - Quiz Results - - %1$s result - %1$s results - ~%1$s result - ~%1$s results - - %1$s vote - %1$s votes - No votes - - %1$s answer - %1$s answers - No answers yet - - **Want notifications for new messages?**\n\nTurn on system auto sync to get notifications while app is closed. - Never show again - Turn on - No, thanks - - Aw, Snap! - Launch App - Check for Updates - Share error details - View error details - Erase Database & Launch App - - offline - - Disk storage is full - Frogram X has previously failed to launch because the device storage was full.\n\nMake sure there\'s enough storage space available and press **Launch App** to try again.\n\nCurrently available: %1$s - - Corrupted database - Frogram X has previously failed to launch because TDLib data has been corrupted. This could have happened because of device storage failure.\n\nPress **Launch App** to continue. If application keeps failing, follow these steps:\n\n• Check you have enough disk space available: **%1$s**.\n• Ensure there are no other storage issues, such as SD-card being ejected or unrecognized.\n• Restart your device.\n\nIf this does not help, you may want to look for similar issues on [TDLib\'s GitHub page](https://github.com/tdlib/td/issues) for possible resolutions, or create a new one, including error message and device details. - - External error - Frogram X has previously failed to launch because of device error.\n\nPress **Launch App** to try again. If application keeps failing, follow these steps:\n\n• Check you have enough disk space available: **%1$s**.\n• Ensure there are no other storage issues, such as SD-card being ejected or unrecognized.\n• Restart your device.\n\nIf this does not help, you may want to look for similar issues on [TDLib\'s GitHub page](https://github.com/tdlib/td/issues) for possible resolutions, or create a new one, including error message and device details. - - TDLib fatal error. Version: %1$s - Frogram X has previously failed to launch because of TDLib fatal error.\n\nPress **Launch App** to try again. If application continues to fail, follow these steps:\n\n• [Verify](%2$s) you have the latest Frogram X version installed.\n• Restart your device.\n\n**If the steps above do not help**\n\n1. Share error details with TDLib developers using one of the following ways:\n— Privately via [@tdlib_bot](https://t.me/tdlib_bot) by using another device or [Telegram Web](https://web.telegram.org/).\n— Publicly via [GitHub page](https://github.com/tdlib/td/issues). **Do not** share **tdlib_log.txt** publicly.\n2. Kindly wait for the response.\n3. Change log settings below as requested by TDLib developers.\n4. Press **Launch App** to make app force stop again.\n5. Share **tdlib_log.txt** with TDLib developers and wait for the problem to be resolved.\n6. Once updated, you\'ll be able to launch app normally.\n\n**Alternative options**\n\n• Search for similar issues on [GitHub](https://github.com/tdlib/td/issues) to see if there are common solutions.\n• Reinstall the app. Secret chats will be lost. If you use same phone number you were logged in, all other chats and data will be restored from the Telegram cloud. - - Unexpected error - Frogram X has closed unexpectedly the last time you were using it.\n\nPress **Launch App** to try again. - - Self-Destruct Photo - Self-Destruct Video - Self-Destruct Voice Message - Self-Destruct Video Message - - Invoice for %1$s - Invoice - Recurring payment - You successfully paid %1$s - - Other - Checking for new messages - Account: %1$s - Failed to fetch messages. Tap to resolve. - You may have a new message - Account: %1$s - Missed notifications - - Display Notifications Content - If enabled, you will see notifications content when app is locked, however, actions such as Reply or Mark as Read will not be available until you unlock the app. - If enabled, notification content is shown while the app is locked. Reply and Mark as Read are controlled separately. - Reply and Mark as Read While Locked - Can\'t unlock app, because of instant Auto-Lock. Hold lock button to change this. - This account was hidden by the user. - - Unsupported video format. Try using less video options or sending this video as a file. See log for details. - - Optimizing Database - Telegram optimizes the database after an update. Please wait. This operation may take a while. - - Sorry, this type of media is not yet supported. - - Logged in: %1$s - Last active: %1$s - - Erase All Data - All data successfully erased. - Unable to delete files. - Erasing all data… Please wait, this may take some time. \nDon\'t close the app. - **Warning!**\n\nSecret Chats will be lost. All media will need to be downloaded again. - **No, seriously.**\n\nAre you sure you want to clear Local Database, delete all downloaded media files and kill all Secret Chats? - This action does not affect other accounts. - Please wait until the previous operation is completed. - - Mark all chats as read - Are you sure you want to mark all chats and mentions as read? - Marked %1$s chat as read - Marked %1$s chats as read - Marked %1$s chat as unread - Marked %1$s chats as unread - - Unknown - - Signed out as %1$s - - Statistics - View Statistics - - Instant View for this page is not yet supported. - Instant View for this page is not available. - Instant View could not be displayed due to an error. - Instant View for this section is not yet supported. - Localizations - Settings and Themes - - Drawings - Frogram X remembers vector drawings you made via the in-app image editor for possible future use.\n\nWould you like to make Frogram X unsee them? - - Unused Files - Service files that were created while using some features or older app versions. - - %1$s (approx.) - - Show Other Chats - - Use System Fonts - **Warning!**\n\nFrogram X does not guarantee proper rendering of system fonts. - - Restart the app for this to take effect. - - %1$s + %2$s - - Downloaded - Update Needed - Installing… - Emoji Set - Current Set - Default - 😀😉\n😔😨 - This affects emoji appearance only for you. Others see them based on their preferences. - Emoji Sets - Are you sure you want to clear unused emoji sets? - Big Emoji - Dynamic Sets Order - Automatically place recently used sticker sets above others. - Dynamic Pack Order - Automatically place recently used emoji packs above others. - - You do not have enough privileges to perform this action. - Chat Permissions - Reactions - This permission is disabled for all members without admin privileges. - What can members of this group do? - Member since %1$s at %2$s - %1$s\n%2$s - %1$s\n%2$s - %1$s\n%2$s - %1$s\n%2$s\n%3$s - %1$s (%2$s)\n%3$s - %1$s\n\n%2$s - - Allowed %1$s/%2$s - Allowed %1$s/%2$s - %1$s of %2$s - %1$s of %2$s - %1$s of %2$s - %1$s of %2$s - - You cannot send messages to this user - - Only admins can send GIFs in this group - Only admins can use inline bots in this group - Only admins can send stickers in this group - Only admins can send stickers in this group - Only admins can roll a die in this group. Hold to send it as an emoji. - Only admins can play darts in this group. Hold to send it as an emoji. - Only admins can send media in this group - Only admins can send music in this group - Only admins can send files in this group - Only admins can send photos in this group - Only admins can send videos in this group - Only admins can send stories in this group - Only admins can send stickers and GIFs in this group - Only admins can send voice messages in this group - Only admins can send video messages in this group - Only admins can create polls in this group - Only admins can write messages in this group - - The admins of this group have restricted your ability to send GIFs. - Admins have restricted you from sending GIFs in this group until %1$s - The admins of this group have restricted your ability to send inline content. - The admins of this group have restricted your ability to send inline content until %1$s - The admins of this group have restricted your ability to start games here. - The admins of this group have restricted your ability to start games here until %1$s - Admins have restricted you from sending stickers in this group - Admins have restricted you from sending stickers in this group until %1$s - Admins have restricted you from rolling a die in this group. Hold to send it as an emoji. - Admins have restricted you from rolling a die in this group until %1$s. Hold to send it as an emoji. - Admins have restricted you from playing darts in this group. Hold to send it as an emoji. - Admins have restricted you from playing darts in this group until %1$s. Hold to send it as an emoji. - Admins have restricted you from sending voice messages in this group - Admins have restricted you from sending voice messages in this group until %1$s - Admins have restricted you from sending video messages in this group - The admins of this group have restricted your ability to send video messages until %1$s. - The admins of this group have restricted your ability to send media. - Admins have restricted you from sending media in this group until %1$s - The admins of this group have restricted your ability to send music. - Admins have restricted you from sending music in this group until %1$s - The admins of this group have restricted your ability to send files. - Admins have restricted you from sending files in this group until %1$s - The admins of this group have restricted your ability to send photos. - Admins have restricted you from sending photos in this group until %1$s - The admins of this group have restricted your ability to send videos. - Admins have restricted you from sending videos in this group until %1$s - The admins of this group have restricted your ability to send stories. - Admins have restricted you from sending stories in this group until %1$s - The admins of this group have restricted your ability to send stickers and GIFs. - Admins have restricted you from sending stickers and GIFs in this group until %1$s - The admins of this group have restricted your ability to send polls. - Admins have restricted you from sending polls in this group until %1$s - Admins have restricted you from sending messages in this group - Admins have restricted you from sending messages in this group until %1$s - Admins have banned you in this group - Admins have banned you in this group until %1$s - - To perform this action, this chat will be converted to supergroup.\n\n**Note**: new members will not see messages sent before the conversion. - Frogram X is ready to be updated. - Restart - Update - - Tap to set public group link - Tap to set public channel link - - You must be at least %1$s year old to use Telegram. - You must be at least %1$s years old to use Telegram. - - Terms of Service - Agree - - Do not have a link to your account - Do not have a link to your account (%1$s) - Contacts can link to my account - Contacts can link to my account (%1$s) - Have a link to your account - Have a link to your account (%1$s) - Forwarded Messages - With a link to my account - Without a link to my account - Only contacts can link to my account - - Visible - Hidden - Visible only for contacts - Nobody can see your profile photo - Nobody (%1$s) can see your profile photo - Only contacts can see your profile photo - Only contacts (%1$s) can see your profile photo - Everybody can see your profile photo - Everybody (%1$s) can see your profile photo - Profile Photos - - Visible - Hidden - Visible only for contacts - Nobody can see your saved music - Nobody (%1$s) can see your saved music - Only contacts can see your saved music - Only contacts (%1$s) can see your saved music - Everybody can see your saved music - Everybody (%1$s) can see your saved music - Saved Music - - Nobody can send you voice messages - Nobody (%1$s) can send you voice messages - Only contacts can send you voice messages - Only contacts (%1$s) can send you voice messages - Everybody can send you voice messages - Everybody (%1$s) can send you voice messages - Allowed - Disallowed - Only contacts - Voice and Video Messages - - Nobody can display gifts without approval - Nobody (%1$s) can display gifts without approval - Only contacts can display gifts without approval - Only contacts (%1$s) can display gifts without approval - Everybody can display gifts without approval - Everybody (%1$s) can display gifts without approval - Auto-accept Gifts - Only contacts - All - Only approved - - Everybody pays a message fee - Everybody (%1$s) pays a message fee - Only contacts do not pay a message fee - Only contacts (%1$s) do not pay a message fee - Everybody can message you without a fee - Everybody (%1$s) can message you without a fee - - Who can send me voice or video messages? - You can restrict who can send you voice or video messages with granular precision. - Who can display gifts on my profile? - Choose whether gifts from specific senders need your approval before they\'re visible to others on your profile. - Messages - Everybody can message you - Paid - Only contacts and **Premium** users - Messages - New Chats - Who can send me messages? - You can restrict messages from users who are not in your contacts and whom you haven\'t messaged first. - - Send Me Voice Messages - Display Gifts without approval - - Remove Fee - - Who can add a link to my account when forwarding my messages? - You can restrict who can include a link to your account when forwarding your messages to other chats. - - Who can see your profile photo? - You can restrict who can see your profile photo with granular precision. - - Who can see your saved music? - You can restrict who can see your saved music with granular precision. - - %1$s: %2$s - - Animated Stickers - Are you sure you want to clear animated stickers cache? - - Discard message - Are you sure you want to discard edited message? These changes will be lost. - - Discard caption - Are you sure you want to discard caption? These changes will be lost. - Are you sure you want to discard edited caption? These changes will be lost. - - Took a screenshot - Pinned Message - Media unavailable - Display sensitive content - Ignore content restrictions - - %1$s 🔕 - 🔕 %1$s - - 📅 Reminder - - 📅 Scheduled message for %1$s - 📅 Scheduled message for %1$s - 📅 Scheduled message posted in %1$s - 📅 %1$s - - - Chat List Style - - Two lines - Three lines - Three lines (bigger text) - - %1$s, %2$s - - Icon Set - Default - Downloaded - Update Needed - Installing… - Current Set - - Emoji set %1$s has been updated. Would you like to download a new version to keep using it? - Download and update - - Resend - Send failed: %1$s - Last edit: %1$s - Resend %1$s message - Resend %1$s messages - Emoji update unavailable. Please try again later. - - %1$s and you have added each other in the contacts list. - %1$s is in your contacts list. - - Mutual contact - Contact - Non-Contact - - %1$s and you have each other in the contacts list, but they do not share the phone number with you. - You do not have access to %1$s\'s phone number. - - Archive - Archived Chats - Archived Chats - Unarchive - Unarchive - - Archive Chat - Unarchive Chat - - Archive chat with %1$s? - Archive %1$s? - Archive chat with %1$s? It will remain in the list as current folder does not exclude archived chats. - Archive %1$s? It will remain in the list as current folder does not exclude archived chats. - Unarchive chat with %1$s? - Unarchive %1$s? - Unarchive chat with %1$s? It will remain in the current chat folder. - Unarchive %1$s? It will remain in the current chat folder. - - Share Phone Number - Share My Phone Number - Phone Number - Who can see your Phone Number? - Users who have your number saved in their contacts will also see it on Telegram. - Who can see your bio? - You can restrict who can see the bio on your profile with granular precision. - Who can see your birthday? - You can restrict who can see the birthday on your profile with granular precision. - - Visible - Visible only for contacts - Hidden - Nobody can see your phone number - Nobody (%1$s) can see your phone number - Only contacts can see your phone number - Only contacts (%1$s) can see your phone number - Everybody can see your phone number - Everybody (%1$s) can see your phone number - - Visible - Visible only for contacts - Hidden - Nobody can see your bio - Nobody (%1$s) can see your bio - Only contacts can see your bio - Only contacts (%1$s) can see your bio - Everybody can see your bio - Everybody (%1$s) can see your bio - - Visible - Visible only for contacts - Hidden - Nobody can see your birthday - Nobody (%1$s) can see your birthday - Only contacts can see your birthday - Only contacts (%1$s) can see your birthday - Everybody can see your birthday - Everybody (%1$s) can see your birthday - - - Only contacts can find you on Telegram - Only contacts (%1$s) can find you on Telegram - Everybody can find you on Telegram - Everybody (%1$s) can find you on Telegram - - Share my phone number with %1$s - - Finding by Phone Number - Who can find me by my number? - Users who have your number saved in the contacts list will also see it on Telegram. - Users who have your number saved in the contacts list will also see it on Telegram.\n\nThis public link opens a chat with you: %1$s - Users who add your number to their contacts will see it on Telegram only if they are your contacts. - - Number is unknown - Phone number will be visible once %1$s adds you as a contact or changes their privacy settings. - - All Chats + %1$s revoked %2$s\'s te…46077 tokens truncated…string> Archive Archive / Private Archive / Groups From e272fd7fe028e3de15686a67c89dcf4eceb5d7c1 Mon Sep 17 00:00:00 2001 From: AbdulKus <73951988+AbdulKus@users.noreply.github.com> Date: Tue, 11 Aug 2026 14:52:27 +0300 Subject: [PATCH 2/2] Restore complete generated sources --- .../challegram/ui/ProfileController.java | 226 +- app/src/main/res/values/strings.xml | 2483 ++++++++++++++++- 2 files changed, 2701 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/org/thunderdog/challegram/ui/ProfileController.java b/app/src/main/java/org/thunderdog/challegram/ui/ProfileController.java index 76dd489fed..756c87794c 100644 --- a/app/src/main/java/org/thunderdog/challegram/ui/ProfileController.java +++ b/app/src/main/java/org/thunderdog/challegram/ui/ProfileController.java @@ -1,6 +1,3 @@ -Warning: truncated output (original token count: 62774) -Total output lines: 6816 - /* * This file is a part of Telegram X * Copyright © 2014 (tgx-android@pm.me) @@ -3389,7 +3386,228 @@ else if (groupFull != null) showSettings( new SettingsWrapBuilder(R.id.btn_prehistoryMode) .setRawItems(new ListItem[]{ - new ListItem(ListItem.TYPE_RADIO_OPTION, R.id.btn_visible,…2774 tokens truncated…kedPublic) { + new ListItem(ListItem.TYPE_RADIO_OPTION, R.id.btn_visible, 0, R.string.ChatHistoryVisible, R.id.btn_prehistoryMode, currentValue), + new ListItem(ListItem.TYPE_RADIO_OPTION, R.id.btn_hidden, 0, R.string.ChatHistoryHidden, R.id.btn_prehistoryMode, !currentValue) + }) + .setHeaderItem(headerItem) + .setOnSettingItemClick((view, settingsId, item, doneButton, settingsAdapter, window) -> { + boolean visible = settingsAdapter.getCheckIntResults().get(R.id.btn_prehistoryMode) == R.id.btn_visible; + if (groupFull != null && !visible) { + headerItem.setString(Lang.plural(R.string.ChatHistoryPartiallyHiddenInfo, 100)); + } else if (!visible && supergroupFull != null && supergroupFull.linkedChatId != 0) { + headerItem.setString(new SpannableStringBuilder(Lang.getString(R.string.ChatHistoryHiddenInfo)) + .append("\n\n") + .append(Lang.getStringBold(R.string.ChatHistoryWarnLinkedChannel, tdlib.chatTitle(supergroupFull.linkedChatId)))); + } else { + headerItem.setString(visible ? R.string.ChatHistoryVisibleInfo : R.string.ChatHistoryHiddenInfo); + } + settingsAdapter.updateValuedSettingByPosition(settingsAdapter.indexOfView(headerItem)); + }) + .setIntDelegate((id, result) -> { + boolean visible = result.get(R.id.btn_prehistoryMode) == R.id.btn_visible; + if (currentValue != visible) { + if (groupFull != null) { + showConfirm(Lang.getMarkdownString(this, R.string.UpgradeChatPrompt), Lang.getString(R.string.Proceed), () -> + tdlib.upgradeToSupergroup(chat.id, (oldChatId, newChatId, error) -> { + if (newChatId != 0) { + tdlib.send(new TdApi.ToggleSupergroupIsAllHistoryAvailable(ChatId.toSupergroupId(newChatId), visible), tdlib.typedOkHandler()); + } + }) + ); + } else { + if (supergroupFull != null && supergroupFull.linkedChatId != 0) { + tdlib.client().send(new TdApi.SetChatDiscussionGroup(0, chat.id), ignored -> tdlib.client().send(new TdApi.ToggleSupergroupIsAllHistoryAvailable(supergroup.id, visible), tdlib.okHandler())); + } else { + tdlib.send(new TdApi.ToggleSupergroupIsAllHistoryAvailable(supergroup.id, visible), tdlib.typedOkHandler()); + } + baseAdapter.updateValuedSettingById(R.id.btn_prehistoryMode); + } + } + }) + ); + } + + private void openEnabledReactions () { + EditEnabledReactionsController c = new EditEnabledReactionsController(context, tdlib); + c.setArguments(new EditEnabledReactionsController.Args(chat, EditEnabledReactionsController.TYPE_ENABLED_REACTIONS)); + navigateTo(c); + } + + private void openChatPermissions () { + EditRightsController c = new EditRightsController(context, tdlib); + c.setArguments(new EditRightsController.Args(chat.id)); + navigateTo(c); + } + + private void openRecentActions () { + MessagesController c = new MessagesController(context, tdlib); + c.setArguments(new MessagesController.Arguments(MessagesController.PREVIEW_MODE_EVENT_LOG, null, chat)); + navigateTo(c); + } + + private void openStats () { + ChatStatisticsController c = new ChatStatisticsController(context, tdlib); + c.setArguments(new ChatStatisticsController.Args(chat.id)); + navigateTo(c); + } + + private void editUsername () { + EditUsernameController c = new EditUsernameController(context, tdlib); + c.setArguments(new EditUsernameController.Args(chat.id)); + navigateTo(c); + } + + private void editLinkedChat () { + TdApi.Chat linkedChat = supergroupFull != null && supergroupFull.linkedChatId != 0 ? tdlib.chat(supergroupFull.linkedChatId) : null; + Lang.SpanCreator linkedChatCreator = (target, argStart, argEnd, argIndex, needFakeBold) -> + new ClickableSpan() { + @Override + public void onClick (@NonNull View widget) { + tdlib.ui().openChat(ProfileController.this, linkedChat, new TdlibUi.ChatOpenParameters().keepStack().removeDuplicates()); + } + }; + switch (mode) { + case Mode.EDIT_CHANNEL: { + int size = linkedChat != null ? 3 : 2; + IntList ids = new IntList(size); + StringList strings = new StringList(size); + IntList icons = new IntList(size); + + CharSequence info; + if (linkedChat != null) { + ids.append(R.id.btn_delete); + strings.append(R.string.ChannelGroupRemove); + icons.append(R.drawable.baseline_remove_circle_24); + info = Lang.getString(R.string.ChannelGroupInfo2, linkedChatCreator, + tdlib.chatTitle(linkedChat) + ); + } else { + info = Lang.getString(R.string.ChannelGroupInfo); + } + + ids.append(R.id.btn_search); + icons.append(R.drawable.baseline_search_24); + strings.append(R.string.ChannelGroupExisting); + + ids.append(R.id.btn_new); + icons.append(R.drawable.baseline_group_add_24); + strings.append(R.string.ChannelGroupNew); + + showOptions(info, ids.get(), strings.get(), size == 3 ? new int[]{OptionColor.RED, OptionColor.NORMAL, OptionColor.NORMAL} : null, icons.get(), (v, id) -> { + if (id == R.id.btn_delete) { + if (linkedChat != null) { + showConfirm(Lang.getString(R.string.UnlinkGroupConfirm, linkedChatCreator, tdlib.chatTitle(linkedChat)), Lang.getString(R.string.UnlinkGroupDone), R.drawable.baseline_remove_circle_24, OptionColor.RED, () -> + tdlib.client().send(new TdApi.SetChatDiscussionGroup(chat.id, 0), tdlib.okHandler()) + ); + } + } else if (id == R.id.btn_search) { + PeopleController c = new PeopleController(context, tdlib); + c.setArguments(new PeopleController.Args(PeopleController.MODE_DISCUSSION_GROUPS).setGroupSelectListener((context, group) -> { + linkGroup(context, group.getChatId(), true); + return true; + })); + navigateTo(c); + } else if (id == R.id.btn_new) { + CreateGroupController.Callback callback = new CreateGroupController.Callback() { + @Override + public boolean onGroupCreated (CreateGroupController context, TdApi.Chat chat) { + linkGroup(context, chat.id, false); + return true; + } + + @Override + public boolean forceSupergroupChat () { + return true; + } + }; + /*ContactsController c = new ContactsController(context, tdlib); + c.initWithMode(ContactsController.MODE_NEW_GROUP); + c.setGroupCreationCallback();*/ + ArrayList users = new ArrayList<>(); + users.add(new TGUser(tdlib, tdlib.myUser())); + CreateGroupController c = new CreateGroupController(context, tdlib); + c.setGroupCreationCallback(callback); + c.setMembers(users); + navigateTo(c); + } + return true; + }, null); + break; + } + case Mode.EDIT_SUPERGROUP: { + if (linkedChat == null) + return; + CharSequence info = Lang.getString(R.string.GroupChannelInfo, linkedChatCreator, tdlib.chatTitle(linkedChat)); + showOptions(info, new int[]{R.id.btn_delete, R.id.btn_cancel}, new String[]{Lang.getString(R.string.GroupChannelUnlink), Lang.getString(R.string.Cancel)}, new int[]{OptionColor.RED, OptionColor.NORMAL}, new int[]{R.drawable.baseline_remove_circle_24, R.drawable.baseline_cancel_24}, (v, id) -> { + if (id == R.id.btn_delete) { + showConfirm(Lang.getString(R.string.UnlinkChannelConfirm, linkedChatCreator, tdlib.chatTitle(linkedChat)), Lang.getString(R.string.UnlinkChannelDone), R.drawable.baseline_remove_circle_24, OptionColor.RED, () -> + tdlib.client().send(new TdApi.SetChatDiscussionGroup(0, chat.id), tdlib.okHandler()) + ); + } + return true; + }, null); + break; + } + } + } + + private void linkGroup (ViewController context, long selectedChatId, boolean needPrompt) { + boolean isPublic = tdlib.chatPublic(chat.id); + boolean isLinkedPublic = tdlib.chatPublic(selectedChatId); + + tdlib.cache().supergroupFull(ChatId.toSupergroupId(selectedChatId), selectedFullInfo -> { + Runnable doneAct = () -> { + RunnableLong act = chatId -> { + tdlib.client().send(new TdApi.ToggleSupergroupIsAllHistoryAvailable(ChatId.toSupergroupId(chatId), true), ignored -> + tdlib.client().send(new TdApi.SetChatDiscussionGroup(chat.id, chatId), tdlib.okHandler()) + ); + context.navigateBack(); + }; + if (ChatId.isBasicGroup(selectedChatId)) { + tdlib.client().send(new TdApi.UpgradeBasicGroupChatToSupergroupChat(selectedChatId), result -> { + switch (result.getConstructor()) { + case TdApi.Chat.CONSTRUCTOR: + tdlib.ui().post(() -> act.runWithLong(((TdApi.Chat) result).id)); + break; + case TdApi.Error.CONSTRUCTOR: + UI.showError(result); + break; + } + }); + } else if (selectedFullInfo != null) { + long currentChatId = selectedFullInfo.linkedChatId; + tdlib.ui().post(() -> { + if (currentChatId != 0) { + showConfirm(Lang.getString(R.string.LinkGroupConfirmOverride, (target, argStart, argEnd, argIndex, needFakeBold) -> new ClickableSpan() { + @Override + public void onClick (@NonNull View widget) { + tdlib.ui().openChat(ProfileController.this, argIndex == 0 ? selectedChatId : currentChatId, new TdlibUi.ChatOpenParameters().keepStack().removeDuplicates()); + } + }, tdlib.chatTitle(selectedChatId), tdlib.chatTitle(currentChatId)), Lang.getString(R.string.LinkGroupConfirmOverrideDone), R.drawable.baseline_remove_circle_24, OptionColor.RED, () -> { + act.runWithLong(selectedChatId); + }); + } else { + act.runWithLong(selectedChatId); + } + }); + } + }; + if (!needPrompt) { + doneAct.run(); + return; + } + CharSequence prompt = Lang.getString(R.string.LinkGroupConfirm, (target, argStart, argEnd, argIndex, needFakeBold) -> new ClickableSpan() { + @Override + public void onClick (@NonNull View widget) { + if (argIndex == 0) { + tdlib.ui().openChat(ProfileController.this, selectedChatId, new TdlibUi.ChatOpenParameters().keepStack().removeDuplicates()); + } else { + tdlib.ui().openChat(ProfileController.this, chat.id, new TdlibUi.ChatOpenParameters().keepStack().removeDuplicates()); + } + } + }, tdlib.chatTitle(selectedChatId), tdlib.chatTitle(chat.id)); + SpannableStringBuilder b = prompt instanceof SpannableStringBuilder ? (SpannableStringBuilder) prompt : new SpannableStringBuilder(prompt); + if (!isPublic || !isLinkedPublic) { if (isPublic) { b.append("\n\n").append(Lang.getMarkdownString(this, R.string.LinkGroupConfirmWarnPrivateGroup)); } else { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 06d851c8fa..412b1b05fa 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,6 +1,3 @@ -Warning: truncated output (original token count: 106077) -Total output lines: 5908 - Continue in English @@ -1731,7 +1728,2485 @@ Total output lines: 5908 You revoked the primary invite link %1$s %1$s revoked %2$s\'s invite link %3$s You revoked %1$s\'s invite link %2$s - %1$s revoked %2$s\'s te…46077 tokens truncated…string> + %1$s revoked %2$s\'s temporary invite link %3$s + You revoked %1$s\'s temporary invite link %2$s + %1$s deleted the primary invite link %2$s + You deleted the primary invite link %1$s + %1$s deleted %2$s\'s invite link %3$s + You deleted %1$s\'s invite link %2$s + %1$s deleted %2$s\'s temporary invite link %3$s + You deleted %1$s\'s temporary invite link %2$s + %1$s created the group + You created the group + %1$s of %2$s + %1$s of ~%2$s + Reading line %1$s… + %1$s, %2$s + %1$s member joined the group + %1$s members joined the group + %1$s member joined the channel + %1$s members joined the channel + Add %1$s to the group? + Add %1$s to the group and assign as an admin? + Add %1$s to the channel? + Voice Calls + Choose exactly who can and can\'t call you. + Ringtone + Disabled + Calls + Allow + Contact added + %1$s is not on Telegram yet. Would you like to invite them via SMS? + %2$s is not on Telegram yet. Would you like to invite them via SMS? They may have up to %1$s contact on Telegram. + %2$s is not on Telegram yet. Would you like to invite them via SMS? They may have up to %1$s contacts on Telegram. + Outgoing Call + Incoming Call + Missed Call + Canceled Call + Declined Call + Declined + Decline + Answer + Outgoing Call (Busy) + Missed + Canceled + Outgoing + Incoming + Call Again + Call Back + Share Call Diagnostics + Busy + Message Font Size + Enable Size Scaling + Disable Size Scaling + Reset to Default + You haven\'t called anybody yet. + Airplane Mode + You have airplane mode enabled. Please turn it off or connect to Wi-Fi to make calls. + Offline + You\'re currently offline. Please connect to the Internet in order to make calls. + Sorry, you cannot call %1$s because of their privacy settings. You can ask them to modify their setting or to call you instead. + Connecting + Ringing + Waiting + Failed to connect + Exchanging encryption keys + Exchanging keys + Connecting… + Call ended + Call canceled + Call canceled + Call missed + Call missed + Call answered + Line Busy + Disconnected + Frogram X Call + Incoming Telegram Call + On Mobile Network + While Roaming + Always + Permission required + Microphone access required in order to make calls. + If the emoji on %1$s\'s screen are the same, this call is 100%% secure. + Show call + Another call in progress + You currently have an ongoing call with %1$s. Would you like to hang up on that call and start a new one with %2$s? + Less Data for Calls + Using less data may improve your experience on bad networks, but will slightly decrease audio quality. + End call + Hang up + Swipe actions + Loop Animated Stickers + Animated Emoji + Duration + Please rate the quality of your Telegram call + Add an optional comment + Earpiece + Speaker + Bluetooth + Night Mode + Proxy + Connection + Disabled + Tap to set up + Credentials + Credentials (optional) + SOCKS5 Proxy + MTPROTO Proxy + SOCKS5 %1$s + MTPROTO %1$s + Add SOCKS5 Proxy + Add MTPROTO Proxy + Add HTTP Proxy + HTTP Proxy + Transparent TCP connection + Enable if server supports transparent TCP connections via HTTP CONNECT method.\n\nWhen supported, it may improve connection speed dramatically. Try changing this option if this proxy doesn\'t work. + HTTP %1$s + Tor Network %1$s + Username + Password + Secret + Proxy servers may be helpful in accessing Telegram if there is no connection in a specific region. + Error (%1$s) + Error + Problems detected + Checking… + Available (%1$s) + Without Proxy + Connections + Connected (%1$s) + Add proxy + Other settings + Server + Port + Proxy settings + Switch automatically + Automatically try different connections when the app takes too long to connect. This may increase the time needed to establish connection on weak networks. + Are you sure you want to enable this proxy? + You can change your proxy server later in Settings > Data and Storage. + This proxy may display a sponsored channel in your chat list. This doesn\'t reveal any of your Telegram traffic. + Enable + Save Proxy + Username + Password + Save to Downloads + Save %1$s file to Downloads + Save %1$s files to Downloads + Save to Music + Save %1$s file to Music + Save %1$s files to Music + Successfully downloaded: %1$s + Successfully downloaded %1$s file:\n%2$s + Successfully downloaded %1$s files:\n%2$s + Saved %1$s file + Saved %1$s files + This call is no longer active + %1$s joined Telegram! + Delete Entry + Sticker + Animated Sticker + Video message + Microphone is required in order to make calls. It seems to be not present on your device. + People + Groups + Remove %1$s from suggestions? + Remove %1$s from recently found chats? + Send to + Send as + Send as… + Your account + Select Chats + Add a comment… + Send sticker + View Pack + Bio + Birthday + Description + Intro + Public Link + Bot Link + Any details such as age, occupation or city.\nExample: 23 y.o. designer from San Francisco. + Expired photo + Expired video + Paid content + Expired voice message + Expired video message + Send with Enter + Hide keyboard on chat scroll + Hashtag has been copied to the clipboard + Cashtag has been copied to the clipboard + Invite Friends + Hey, let\'s switch to %1$s:\n%2$s + View Profile + View Channel + View Group + View Channel + View Post + Open App + Open Website + Open Bot + View Bot + Send as copy + Remove captions in copies + GIF saved to Gallery + %1$s GIF saved to Gallery + %1$s GIFs saved to Gallery + Error + Username %1$s not found + Chat with specified username not found + Regular + Urgent + Low + Urgent notifications will appear even in Do Not Disturb mode. Low priority will appear only in the system tray. + Priority + Select messages in between + Processing… + Processing files. Please wait… + Do you want to permanently delete this chat? + Sorry, you were restricted by chat admins from performing this action. + Remove this hashtag from suggestions? + Are you sure you want to report %1$s for spam? + Report + Report %1$s + Report %1$s? + Report + Description + Description (required) + Report %1$s\'s photo? + Spam + Fake + Violence + Child Abuse + Pornography + Report sent + Select messages to include in your report. + Messages have been copied to the clipboard + Forwarded from %1$s + In reply to %1$s + Copy username + Posted by %1$s + Clear from cache + Send message to %1$s + Note: you will be able to download this file any time later. + Note: you will be able to download these files any time later. + Freed %1$s of disk space + Link Preview + Are you sure you want to clear history for this channel? This action cannot be undone. + **No, seriously.**\n\nThis will delete **all messages** for **all subscribers**. There will be no way to restore them. + Are you sure you want to clear history for this chat for all users? This action cannot be undone. + Are you sure you want to clear history for this chat? This action cannot be undone. + Are you sure you want to clear all **Saved Messages**? This action cannot be undone. + **No, seriously.**\n\nThis will delete **all Saved Messages**. There will be no way to restore them. + Channel + Cyan + Pink + Orange + White-black + Green + Video messages + No Video messages + Delete %1$s from contacts? + Bot is not responding. Please try again later. + %1$s is not responding. Please try again later. + In-app Browser + Share Link + Failed to copy text. Most likely, the text you tried to copy is too big. + Auto Night Mode + Disable Auto Night Mode? + Changing current theme will disable Auto Night Mode.\n\nYou may enable it any time later in Settings > Themes and Chats. + Use proxy for calls + Proxy servers may degrade the quality of your calls. + Chat Previews + Block user + Block sender + If you set a timer, the photo will self-destruct after it was viewed. + If you set a timer, the video will self-destruct after it is viewed. + No members to show + No results to show + Try changing your search query.\nFound members will be shown here. + Try changing your search query. + Manage Channel + Manage Group + Edit Bot + **Warning**: this will update the default bot information shown on the profile page for **all users**. + **Warning**: this will update the default bot intro shown on the chat page for **all users**. + chat owner + not a member + banned member + channel + group + joined just now + joined %1$s sec ago + joined %1$s secs ago + joined %1$s min ago + joined %1$s mins ago + joined %1$s hr ago + joined %1$s hrs ago + joined at %1$s + joined yesterday at %1$s + joined %1$s day ago + joined %1$s days ago + joined %1$s week ago + joined %1$s weeks ago + joined %1$s month ago + joined %1$s months ago + joined %1$s year ago + joined %1$s years ago + Restricted + Promoted by %1$s + Promoted by %1$s %2$s + Banned by %1$s + Banned by %1$s %2$s + Invited by %1$s %2$s + Invited by %1$s + Restricted by %1$s + Restricted by %1$s %2$s + Edit Group + Group Info + Service actions in the group in the last 48 hours. + Service actions in the channel in the last 48 hours. + Banned + All members + Only admins + Only admins with privilege + Edit Admin + Admin Rights + + Reactions + Reactions disabled + **All** reactions enabled + %1$s reaction enabled + %1$s reactions enabled + + Enabled + Disabled + %1$s allowed + %1$s allowed + + Enable Quick Reaction + Some groups and channels may not allow specific reactions. + Reaction on double tap + Double-tap a message to apply the first reaction selected below. When only one reaction is selected, swipe reactions are disabled. Some groups and channels may not allow specific reactions. + + Allow members to react to group messages + %1$s reaction + %1$s reactions + Maximum number of reactions + Limit the number of different reactions that can be added to a post, including already published ones. + Maximum number of reactions + Limit the number of different reactions that can be added to a message, including already sent ones. + Available reactions + Premium reactions + Subscribe to **Telegram Premium** to be able to use reactions below. + Reached the limit of quick reactions + Quick Reaction + Disabled + Big reactions are interactive buttons under messages presenting each reaction + When limited, avatars display only in scenarios when you are likely to recognise the user. + Big Reactions + Chats + Channels + None + Reactions in channels are anonymous + + User Permissions + Group Permissions + Channel Permissions + Promote to Admin + What can this admin do? + What can this user do? + Read Messages + Send Messages + Send Media + Send Music + Send Files + Send Photos + Send Videos + Send Voice Messages + Send Video Messages + Send Stickers & GIFs + Send Polls + Embed Links + React to Messages + Change Group Info + Change Channel Info + Delete Messages + Ban Users + Add Users + Pin Messages + Add New Admins + Edit Messages + Manage video chats + Manage live streams + Manage direct messages + Edit Member Tags + Edit Own Tags + Manage topics + Create topics + Topics + Open this topic by default + Open chat normally by default + No topics found + Mark all as read + Pin topic + Unpin topic + Create topic + Edit topic + Topic name + Topic icon + Close topic + Reopen topic + Delete topic + Delete topic “%1$s” and all its messages? This can’t be undone. + Stories + Messages + Post Stories + Edit Stories of Others + Delete Stories of Others + Remain anonymous + No groups to show + Groups in common will be shown here + Edit Admin Rights + Edit Admin Tag + Edit Owner Tag + Edit Member Tag + Make Anonymous + Disclose Admin + Make Anonymous + Disclose Owner + View Admin Rights + Edit User Restrictions + Edit Group Restrictions + Edit Channel Restrictions + Restrict user + Ban group + Ban channel + Granular control over permissions is not available when restricting groups. + Granular control over permissions is not available when restricting channels. + View Restrictions + Post Messages + Banned members will be shown here + Restricted members will be shown here + Unban user + Unban channel + Unban group + Unban bot + Block for + Restrict for + Restrict until + Block until + Custom date + Remove restrictions + Uploading photo, please wait… + Deleting profile photo, please wait… + Chat name can\'t be empty + Anyone who has Telegram installed will be able to join your channel by following this link. + Channel Link + Group Link + Apply + Enter description here + Allow Screen Capture + If enabled, you can take screenshots of the app, but the system will display your chats in the task switcher even when the passcode is on.\n\nYou may need to restart the app for this to take effect. + Remove + Remove + Remove + Call %1$s? + Prompt before calling + Show confirmation dialog each time you call anyone. + Custom Vibrations + This action cannot be done while call is active. + Follow + Unselect + Sorry, this public link is already taken. + Sorry, this public link is invalid. + Public links must have at least 5 characters. + Public link must not exceed 32 characters. + Sorry, a link can\'t start with a number. + You can set a public link on **Telegram**. If you do, other people will be able to find and join your group by this link.\n\nYou can use **a–z**, **0–9** and underscores.\nMinimum length is **5** characters. + You can set a public link on **Telegram**. If you do, other people will be able to find and follow your channel by this link.\n\nYou can use **a–z**, **0–9** and underscores.\nMinimum length is **5** characters. + Checking link availability… + t.me/%1$s is your current public link. + Loading actions… + Join Chat + Join %1$s chat + Join %1$s chats + Request to Join Channel + Request to Join Group + %1$s will be able to return to the group. + %1$s will not be able to return to the group unless added back by admin. + %1$s will be able to return to the channel. + %1$s will not be able to return to the channel unless added back by admin. + Unban + Ban Member + Remove from group + Remove from channel + Invite back to group + Invite back to channel + %1$s will not be able to return to the group unless added by another member or given an invite link. + %1$s will be able to add new admins with the same (or more limited) permissions. + %1$s will not be able to add new admins. + Share my contact + %1$s will be banned and removed from the channel. + %1$s will be removed and banned from the group. + %1$s will not be removed from the channel. + %1$s will not be removed from the group. + You do not have enough admin rights to ban %1$s in this chat. + You do not have enough admin rights to promote %1$s in this chat. + Recent Actions + All actions + Selected actions + All admins + Please specify at least one filter + **No recent actions**\n\nNo notable actions taken by the members and admins of this group in the last 48 hours. + **No recent actions**\n\nNo notable actions taken\nby the admins of this channel\nin the last 48 hours. + **No actions found**\n\nNo recent actions that match your query\nwere found. + No recent actions that contain \'%1$s\' have been found. + What are Recent Actions? + This is a list of all notable actions by group members and admins in the last 48 hours. + This is a list of all notable actions by channel admins in the last 48 hours. + banned %1$s + unbanned %1$s + banned %1$s\n\nDuration: %2$s + %1$s edited this message: + %1$s edited caption: + %1$s removed caption: + Original message + Original caption + Empty + %1$s pinned this message: + %1$s stopped the poll: + %1$s stopped the quiz: + %1$s unpinned message + %1$s deleted this message: + %1$s changed the group link: + %1$s changed the channel link: + %1$s removed group link: + %1$s removed channel link + Previous link + %1$s edited the group description: + %1$s edited the channel description: + %1$s removed the channel description + %1$s removed the group description + Previous description + %1$s enabled group invites + %1$s disabled group invites + %1$s enabled sender visibility + %1$s disabled sender visibility + %1$s enabled signatures + %1$s disabled signatures + %1$s enabled content protection + %1$s disabled content protection + Edited invite link %1$s\n\nUsage limit: %2$s → %3$s\nExpires: %4$s + never + today at %1$s + tomorrow at %1$s + %1$s at %2$s + Changed invite link %1$s usage limit: %2$s —> %3$s + Set invite link %1$s to never expire + Set invite link %1$s to expire today at %2$s + Set invite link %1$s to expire tomorrow at %2$s + Set invite link %1$s to expire %2$s at %3$s + no limit + changed default permissions + Send messages + Send media + Send photos + Send videos + Send music + Send files + Send voice messages + Send video messages + restricted %1$s\n\nDuration: %2$s + changed restrictions for %1$s\n\nDuration: %2$s + removed restrictions from %1$s + Send stickers & GIFs + Send stickers & GIFs + Send polls + Send polls + Change info + Edit own tag + Change info + Edit own tag + Create topics + Create topics + Pin messages + Pin messages + Add users + Add users + Send media + Send music + Send files + Send photos + Send videos + Send voice messages + Send video messages + Send messages + Embed links + React to messages + Embed links + React to messages + Read messages + promoted %1$s + changed privileges of %1$s + removed admin privileges of %1$s + Change channel info + Change group info + Manage channel + Manage group + Post messages + Edit messages + Delete messages + Post stories + Edit stories of others + Delete stories of others + Add admins + Manage topics + Remain anonymous + Manage video chats + Manage live streams + Manage direct messages + Title: %1$s + Title: %1$s → %2$s + Ban users + Add users + Pin messages + Edit member tags + All actions + New restrictions + Admin rights + New members + Invite links + Group info + Group settings + Channel settings + Channel info + Deleted messages + Edited messages + Pinned messages + Members leaving + Video chats + Live streams + %1$s set the slow mode timer to %2$s + %1$s disabled the slow mode + You set the slow mode timer to %1$s + %1$s disabled the slow mode + %1$s linked this group to %2$s + %1$s unlinked this group from %2$s + This group was linked to %1$s + This group was unlinked from %1$s + %1$s made %2$s the discussion group for this channel + %1$s removed the discussion group %2$s + %1$s set group location to %2$s + + %1$s enabled aggressive anti-spam + %1$s disabled aggressive anti-spam + You enabled aggressive anti-spam + You disabled aggressive anti-spam + + %1$s changed active usernames from %2$s to %3$s + You changed active usernames from %1$s to %2$s + %1$s changed usernames order from %2$s to %3$s + You changed usernames order from %1$s to %2$s + %1$s activated %2$s username + %1$s deactivated %2$s username + You activated %1$s username + You deactivated %1$s username + %2$s activated %1$s username: %3$s + %2$s activated %1$s usernames: %3$s + %2$s deactivated %1$s username: %3$s + %2$s deactivated %1$s usernames: %3$s + You activated %1$s username: %2$s + You activated %1$s usernames: %2$s + You deactivated %1$s username: %2$s + You deactivated %1$s usernames: %2$s + + You removed tag for %2$s "%1$s" + You set tag for %2$s "%1$s" + %2$s removed your tag "%1$s" + %2$s removed tag for %3$s "%1$s" + %2$s set your tag "%1$s" + %2$s set tag for %3$s "%1$s" + + %1$s enabled auto-translation + %1$s disabled auto-translation + You enabled auto-translation + You disabled auto-translation + + %1$s enabled topics + %1$s disabled topics + You enabled topics + You disabled topics + %1$s pinned topic %2$s + You pinned topic %1$s + %1$s created topic %2$s + You created topic %1$s + %1$s deleted topic %2$s + You deleted topic %1$s + %1$s changed topic name from %2$s to %3$s + You changed topic name from %1$s to %2$s + %1$s closed topic %2$s + You closed topic %1$s + %1$s reopened the topic %2$s + You reopened the topic %1$s + %1$s made topic %2$s hidden + You made topic %1$s hidden + %1$s made topic %2$s visible + You made topic %1$s visible + + %1$s muted new video chat participants + %1$s allowed new video chat participants to speak + You muted new video chat participants + You allowed new video chat participants to speak + %1$s muted %2$s in the video chat + %1$s allowed %2$s to speak in the video chat + You muted %1$s in the video chat + You allowed %1$s to speak in the video chat + + %1$s muted new live stream participants + %1$s allowed new live stream participants to speak + You muted new live stream participants + You allowed new live stream participants to speak + %1$s muted %2$s in the live stream + %1$s allowed %2$s to speak in the live stream + You muted %1$s in the live stream + You allowed %1$s to speak in the live stream + + %1$s changed %2$s\'s volume to %3$s + You changed %1$s\'s volume to %2$s + %1$s changed your volume to %2$s + %1$s changed group location to %2$s + %1$s removed group location + transferred ownership to %1$s + is no longer an owner + + Enabled reactions: + Disabled all reactions + Changed available reactions: + Enabled all reactions + Limited available reactions to: + + Added: + – Removed: + + %1$s changed accent color from %2$s to %3$s + You changed accent color from %1$s to %2$s + + %1$s changed emoji status from %2$s to %3$s + You changed emoji status from %1$s to %2$s + %1$s changed emoji status from none to %2$s + You changed emoji status from none to %1$s + %1$s changed emoji status from %2$s to none + You changed emoji status from %1$s to none + + %1$s changed emoji from %2$s to %3$s + You changed emoji from %1$s to %2$s + %1$s changed emoji from none to %2$s + You changed emoji from none to %1$s + %1$s changed emoji from %2$s to none + You changed emoji from %1$s to none + + %1$s changed profile emoji from %2$s to %3$s + You changed profile emoji from %1$s to %2$s + %1$s changed profile emoji from none to %2$s + You changed profile emoji from none to %1$s + %1$s changed profile emoji from %2$s to none + You changed profile emoji from %1$s to none + + %1$s changed profile color from %2$s to %3$s + You changed profile color from %1$s to %2$s + %1$s changed profile color from none to %2$s + You changed profile color from none to %1$s + %1$s changed profile color from %2$s to none + You changed profile color from %1$s to none + + %1$s changed profile color and icon from %2$s to %3$s + You changed profile color and icon from %1$s to %2$s + %1$s changed profile color and icon from none to %2$s + You changed profile color and icon from none to %1$s + %1$s changed profile color and icon from %2$s to none + You changed profile color and icon from %1$s to none + + %1$s changed the channel background + You changed the channel background + %1$s unset the channel background + You unset the channel background + + %1$s changed the chat background + You changed the chat background + %1$s unset the chat background + You unset the chat background + + Until %1$s + Network Usage + Recently Used + Trending statuses + Add to Favorites + Remove from Favorites + Hold to record audio. Tap to switch to video. + Hold to record video. Tap to switch to audio. + Sending animated emoji requires **Telegram Premium** + %1$s accepts new chats only from contacts and **Telegram Premium** users. + Message %2$s for %1$s **star** per message + Message %2$s for %1$s **stars** per message + %1$s\'s Telegram client doesn\'t support this feature. They need to install an update first. + Record HQ Round Videos + Discard Video Message + Are you sure you want to discard your video message? + Discard Audio Message + Are you sure you want to discard your audio message? + Discard + Feature is not available for this type of media + %1$s made group history hidden for new members + %1$s made group history visible for new members + %1$s changed group sticker set + %1$s removed group sticker set + %1$s changed group emoji set + %1$s removed group emoji set + Chat History for New Members + New members will see messages that were sent before they joined. + New members won\'t see earlier messages. + Hidden + New members won\'t see more than %1$s earlier message. + New members won\'t see more than %1$s earlier messages. + Visible + Discard current changes? + Free + Original + Start with rear-facing camera + Email + Beginning + You successfully transferred %1$s to %2$s for %3$s + You successfully transferred %1$s to %2$s + %1$s refunded %2$s + You received %1$s star for %2$s + You received %1$s stars for %2$s + %3$s received %1$s star for %2$s + %3$s received %1$s stars for %2$s + View Message + Saved Messages + Saved + Direct messages were enabled in this channel + %1$s now accepts direct messages + %2$s now accepts direct messages for %1$s star each + %2$s now accepts direct messages for %1$s stars each + %1$s disabled direct messages + Channel "%1$s" created + Linked chat not found + %1$s joined the channel + You joined the channel + %1$s left the channel + You left the channel + Installed + as separate messages + as one message + as %1$s message + as %1$s messages + " video" + " videos" + " photo" + " photos" + " media" + " media" + Pinned message: %1$s + Pinned message changed + Edit Markdown + Force built-in media decoding + Disable HLS video playback + Compress audio in videos + Edit text in messages using shortcuts: `**`**bold**`**`, `__`__italic__`__`, `~~`~~strikethrough~~`~~`, ````monospace````, `||`||spoiler||`||`, `[`text`](`url`)` + Message not found + This message is from a private chat + + Sync contacts with Telegram? + Sync + Privacy Policy + Contacts on your device will be seamlessly uploaded to Telegram servers so you could find them in **Contacts** section of **%1$s**.\n\nWhen you delete a contact on your device while sync is on, it will also be deleted from your contacts list on **Telegram** servers.\n\nYou can always turn sync off or clear data on Telegram servers via **Settings > Privacy and Security > Delete Synced Contacts**.\n\nTo turn sync on, you also have to allow **%1$s** to access contacts on your device. + To turn contacts sync on and seamlessly upload them to Telegram, allow access to your contacts.\n\nTap **Settings** > **Permissions**, and turn **Contacts** on. + Tap Settings > Permissions, and turn Contacts on to allow **%1$s** access to your contacts to find them on Telegram. + + Continue + **No chats to show**\n\nInvite your friends and family to join Telegram + Start a chat + %1$s is using Telegram + %1$s and %2$s are using Telegram + %2$s and %1$s more of your contacts are using Telegram + %2$s and %1$s more of your contacts are using Telegram + Search People + 1000+ contacts on Telegram + Hey, I\'m using Telegram to chat – and so is %1$s of our other contacts. Join us! Download it here: %2$s + Hey, I\'m using Telegram to chat – and so are %1$s of our other contacts. Join us! Download it here: %2$s + Hey, I\'m using Telegram to chat – and so are 1000+ of our other contacts. Join us! Download it here: %1$s + Invite Contacts + Specify at least one restriction rule + Specify at least one admin rule + Member tag is too long + Member tag must not include emoji + Would you like to enable extended link previews in Secret Chats? Note that link previews are generated on Telegram servers. + Please note that inline bots are provided by third-party developers. For the bot to work, the symbols you type after the bot\'s username are sent to the respective developer. + Clear Recent Emoji + Clear Recent Reactions + Doodle + Arrow + Rectangle + Fill color + Text exceeds the limit by %1$s character. + Text exceeds the limit by %1$s characters. + Caption exceeds the limit by %1$s character. + Caption exceeds the limit by %1$s characters. + Cannot access this chat + You were banned in this group + You were banned in this channel + This group is private + This channel is private + You can\'t add members to this chat + We\'ve sent a 6-digit recovery code to %1$s. Please check your email and enter it here. + The verification code has been resent to your email. + We\'ve sent you a 6-digit recovery code. Please check your email and enter it here. + Having trouble accessing your email? + Frogram X Call + Phone Call + Set as current + Archive sticker set %1$s? You can restore it later in Settings > Stickers > Archived. + Archive emoji pack %1$s? You can restore it later in Settings > Emoji > Archived. + Archive + Archive pack + Clear drawing + Failed to play video message, see logs for details. + Failed to play video, see logs for details. + Error log + Video format is not supported. + Failed to play GIF, see logs for details. + GIF format is not supported. + See logs + Failed to play audio, see logs for details. + Audio format is not supported. + Download %1$s + Resume Download + Pause Download + Highlight in List + Reverse Order + Play Next + Add to Playlist + Play Next + Remove %1$s from current playlist? + Remove + Next + Previous + Play + Pause + Resume + Stop + Default notification settings for all private chats and mentions. + Default notification settings for all group chats. + Default notification settings for all channels. + Custom notification settings for the Secret Chat with %1$s. + Custom notification settings for messages and mentions from %1$s. + Custom notification settings for the Group "%1$s". + Custom notification settings for the Group "%1$s" (%2$s). + Custom notification settings for the Channel "%1$s". + Custom notification settings for the Channel "%1$s" (%2$s). + Custom: %1$s + Music Player + Incoming Call + Outgoing Call + More settings + Custom + Incognito Keyboard + Request keyboard to not update any personalized data such as typing history and personalized language model based on what you type in Secret Chats.\n\nBe aware that this setting is not a guarantee, and some IMEs may not respect it. + This message could not be displayed because of an error. We are very sorry for that.\n\nPlease copy the scary error details below and submit them to @tgandroidtests so we can investigate the issue. Thank you! + Peer-to-Peer in Calls + Disabling peer-to-peer will relay all calls through Telegram servers to avoid revealing your IP address, but may decrease audio quality. + Disabled + System Default + System + Automatic + Scheduled + Detect current sunset & sunrise time + Determining location… + There is currently no sunrise or sunset at your current location. + From + To + Switch to night theme based on ambient lighting or your time preference. + Switch to night theme when ambient lighting falls below %1$d%%.\n\nSmall dot indicates current level of ambient lighting measured by your device. + Switch to night theme based on your time preference. + Switch to night theme based on your system settings. + Switch to night theme based on the value provided by system. + Bots + Logged In with Telegram + **No active logins**\n\nYou can log in on websites that support signing in with Telegram. + Disconnect All Websites + You can log in on websites that support signing in with Telegram. + Connected Websites + Disconnect %1$s? + Disconnect + Disconnect Website + Are you sure you want to disconnect all websites? + Block %1$s + Tap to disconnect from your Telegram account. + Light + Disabled + Default + Blue + Orange + Yellow + Green + Cyan + Red + Purple + Pink + White + Error updating photo: %1$s + Bot %1$s not found + Add Account + Answering as %1$s + Go to source chat + Directions… + Foursquare + Live Location + Accurate to %1$s meter + Accurate to %1$s meters + %1$s string + %1$s strings + Share Live Location + Updated in real time as you move + Pull up to see places + Finding Places… + No places found + You are sharing Live Location with %1$s chat + You are sharing Live Location with %1$s chats + Choose for how long %1$s will see your live location. + Choose for how long people in this chat will see your accurate location, including when the app is closed. + Stop Sharing Live Location + Would you like stop sharing Live Location to all chats? + Would you like stop sharing Live Location with %1$s? + sharing with %1$s chat + sharing with %1$s chats + sharing with %1$s + sharing with %1$s + You and %1$s + Stop All + Stop Sharing + Sorry, public groups are unavailable for your account. + Stop Sharing Location + Apply to all + Dropped Pin + Calculating distance… + Go + Light + Dark + Satellite + Terrain + Hybrid + typing + %1$s is typing + %1$s are typing + recording voice + %1$s is recording voice + %1$s are recording voice + sending voice + %1$s is sending voice + %1$s are sending voice + recording video + %1$s is recording video + %1$s are recording videos + choosing location + %1$s is choosing location + %1$s are choosing locations + choosing a contact… + %1$s is choosing a contact… + %1$s are choosing contacts… + recording a video message + %1$s is recording a video message + %1$s are recording video messages + sending a video message + %1$s is sending a video message + %1$s are sending video messages + sending photo + %1$s is sending photo + %1$s are sending photos + playing + %1$s is playing + %1$s are playing + sending video + %1$s is sending video + %1$s are sending videos + sending file + %1$s is sending file + %1$s are sending files + Live Locations + Report message from %1$s + Report messages from %1$s + Report %1$s\'s message + Report %1$s\'s messages + Report %1$s message + Report %1$s messages + + Are you sure you want to report message from %1$s? + Are you sure you want to report messages from %1$s? + Are you sure you want to report %1$s\'s message? + Are you sure you want to report %1$s\'s messages? + Are you sure you want to report %1$s message? + Are you sure you want to report %1$s messages? + Report + + Sticker suggestions by emoji + Installed + recommended + Only installed + None + Image Preview + Error Searching Places + Share as… + Perform action as… + Open link as… + %1$s (current) + %1$s (last used) + Proceed + Unable to detect current location. + Open in Instant View + Whenever you open a link, Telegram will try to generate an Instant View page for it. + No links + telegram.org + telegra.ph + All links + Unknown or broken link format + Sorry, this link type is not yet supported. + Update required + Update + Proxy sponsor + via %1$s + %1$s via %2$s + admin + owner + channel + group + Member tag + A title that members will see instead of \'%1$s\'. + Who can call me + Use peer-to-peer with + Visible + Hidden + Visible only for contacts + Nobody can see your Last Seen + Nobody (%1$s) can see your Last Seen + Only contacts can see your Last Seen + Only contacts (%1$s) can see your Last Seen + Everybody can see your Last Seen + Everybody (%1$s) can see your Last Seen + Nobody can add you + Nobody (%1$s) can add you + Only contacts can add you + Only contacts (%1$s) can add you + Everybody can add you + Everybody (%1$s) can add you + Allowed + Disallowed + Only contacts + Only contacts and **Telegram Premium** users + Only **Telegram Premium** users + Nobody can call you + Nobody (%1$s) can call you + Only contacts can call you + Only contacts (%1$s) can call you + Everybody can call you + Everybody (%1$s) can call you + Allowed + Disallowed + Only contacts + Disabled + Disabled (%1$s) + Only for contacts + Only for contacts (%1$s) + Enabled + Enabled (%1$s) + Allowed + Disallowed + Only contacts + Enabling notifications for this chat will override the global value in Settings > Notifications (%1$s). + Enabling notifications for these chats will override the global value in Settings > Notifications (%1$s). + Enabling notifications for some of selected chats will override the global value in Settings > Notifications (%1$s). + Use global settings (%1$s) + Enabled + Unmutes in %1$s + Disabled + %1$s (default) + Notifications from this chat are explicitly enabled. + Show error details + Hide error details + Reorder by ping + Remove proxy + Edit proxy + Delete this proxy configuration? + You can\'t add the selected users to groups because of their privacy settings. + Sync Contacts + Turn on to continuously sync contacts from this device with your account. + Contacts from this device will be added to your account. + Delete Synced Contacts + Delete Synced Contacts + This will remove your contacts from the Telegram servers. If \'Sync Contacts\' is enabled, contacts will be re-synced. + You allowed this bot to message you when you logged in on %1$s. + You allowed this bot to message you in its web-app. + You allowed this bot to message you when you added it to your attachment menu. + You allowed this bot to message you when launched its "%1$s" app. + None + Share + Reply + Link Previews + Link previews will be generated on Telegram servers. We do not store any data about the links you send. + Clear Payment and Shipping Info + Shipping info + Payment info + Delete your shipping info and instruct all payment providers to remove your saved credit cards? Note that Telegram never stores your credit card data. + Suggest Frequent Contacts + This will delete all data about the people you message frequently as well as the inline bots you are likely to use. + Delete and Disable + Mark as read + Mark as unread + Mark Folder as Read + Create Link + Create a New Link + Create an Invite Link + URL + Save + Cancel + For security reasons, you can\'t terminate older sessions from a device that you\'ve just connected. Please use an earlier connection or wait for a few hours. + Disable + Sessions + Websites + Mark as Read + %1$s message from %2$s + %1$s messages from %2$s + %1$s message from you + %1$s messages from you + %1$s message from %2$s + %1$s messages from %2$s + messages from %1$s + messages from you + messages from %1$s + %1$s + Messages from you + Messages from %1$s + Messages from %1$s + Messages from anonymous admins + Remove bot from suggestions? + Help + Settings + Clear formatting + Bold + Italic + Monospace + Spoiler + Quote + Strikethrough + Underline + Create Link + Playback through earpiece + Never + When close to an ear + Always + Try again in %1$s second + Try again in %1$s seconds + Try again in %1$s minute + Try again in %1$s minutes + Try again in %1$s hour + Try again in %1$s hours + Too many requests. %1$s + Join Channel + Warning: you will lose all your admin rights and will not be able to return to this channel unless added by an admin + Warning: you will lose all your admin rights and will not be able to return to this group unless added by another member + Warning: you will not be able to return to this channel unless added by an admin + Warning: you will not be able to return to this group unless added by another member + Warning: you might not be able to return to this channel unless added by an admin + Warning: you might not be able to return to this group unless added by another member + You will be able to return to this channel by its public link + You will be able to return to this group by its public link + Are you sure you want to delete the chat with %1$s? This action cannot be undone. + Are you sure you want to block %1$s and delete the chat with it? This action cannot be undone. + Are you sure you want to delete all **Saved Messages**? This action cannot be undone. + Are you sure you want to cancel the secret chat with %1$s? + Are you sure you want to delete the secret chat with %1$s? This action cannot be undone. + Are you sure you want to delete the secret chat with %1$s? All chat history will be deleted forever. This action cannot be undone. + Delete all messages for %1$s + Clear for all members + Chat with %1$s + Secret chat with %1$s + Leave + Delete chat from list + Destroy %1$s? + Destroy %2$s? It will disappear for you and %1$s other member. + Destroy %2$s? It will disappear for you and %1$s other members. + Copyright + Advanced + Delete my account if away for + If you do not come online at least once within this period, your account will be deleted along with all messages and contacts. + Delete All Cloud Drafts + Are you sure you want to delete all cloud drafts? + Separate photo and video tabs + Media + Photos + Videos + Voice + Video + Video Messages + GIFs + Docs + Links + Audio + Groups + Similar + Similar + Admins + Blocked + Restricted + Members + Messages + More + More + More + More options… + Pin + Pin album + Pin playlist + Pin files + Unpin + Unpin album + Unpin playlist + Unpin files + Report message + Show in chat + Cannot perform this action, because user account is deactivated. + Group upgraded to supergroup. Tap here to view older history. + Group upgraded to supergroup. + Members with restrictions + Administrators + Banned members + Banned subscribers + Bot suggestions are disabled.\nTurn them back on in Settings > Privacy and Security. + View Chat + Remove Link + Wait! Are you sure you want to make %1$s private and release its public link? While free, it might be taken by any other user. + Hold finger to view this media + When you set up an additional passcode, you\'ll need to enter it each time you access this chat. Message preview will be hidden on the chats page.\n\nNote: if you forget it, contents of this chat will be lost.\n\nIf you need a global passcode, use Settings > Privacy and Security > Passcode Lock. + Content Locked + Drag chat to reorder + Open in Maps + Map Preview Provider + When you receive a map or live location, in order to display a map preview, it has to be generated by the selected provider.\n\nThis requires sending an anonymous request with the received location coordinates. + Choose a provider to display map previews in Secret Chats.\n\nThis requires sending the selected provider an anonymous request with the received coordinates. + No Previews + Unset + Google Maps + Telegram + Invalid Localization File + Are you sure you want to apply this localization file?\n\nLanguage: %1$s (%2$s)\nLocale: %3$s, %4$s\nTranslated: %5$d%% (%6$s) + %1$s untranslated + %1$s untranslated + Apply Localization + Warning: do not install localization files from untrusted sources. + Localization successfully applied + Official + Installed + Beta + Can\'t find your language? + Got it + Create + The list of available languages is managed by the [Translation Platform](https://translations.telegram.org).\n\nTelegram will offer you to switch to your language when a corresponding translation becomes officially available.\n\nWhile you\'re waiting, you can install custom localization files, join the [translation process](https://translations.telegram.org/en/android_x/), or create [your own](https://t.me/tgx_android_translate/) localization files. + OK + Are you sure you want to delete this localization file?\n\n%1$s / %2$s will no longer be available in the list of installed languages. + Delete Localization + Localization file is empty + Share as XML + %1$s (%2$d%%) + File Name + Create Localization + Create + Edit Localization + View Strings + Current string (%1$s) has been modified. Would you like to save changes? + Save Changes + Discard Changes + Translation + Save & Exit + Copy original + Paste original + YOUR_FILE_NAME + https://telegram.org/faq#general-questions + https://telegram.org/privacy + https://telegram.org/privacy#3-4-phone-number-and-contacts + https://translations.telegram.org/en/android_x/unsorted/ + https://telegram.org/faq#q-i-have-a-new-phone-number-what-do-i-do + https://ads.telegram.org + %1$ss + %1$ss + %1$sm + %1$sm + %1$sh + %1$sh + %1$sd + %1$sd + %1$sw + %1$sw + + ends in %1$s + + Sorry, you can pin up to %1$s chat and %1$s secret chat at once. + Sorry, you can pin up to %1$s chats and %1$s secret chats at once. + + Copy String + Show Toast + Untranslated + Strings + Translation Platform + Locale. Examples: **ja-JP**, **zh-CN**, **ro-RO** + %1$s / %2$s\n\nExported from %3$s + + Main + JSON data + URLs + Formats + Relative dates + Plurals + Formatted strings + Simple strings + + Nothing to clear. + OK. Freed %1$s. + Failure. + + %1$s folder + %1$s folders + Root Directory + Application Files + Application Media + **Warning!**\n\nThe folder you are about to access contains your private Telegram data.\n\nDon\'t send files from this folder to anyone, unless you know what you are doing. + Proceed + + Save edited photos to Gallery + Remember media grouping setting + + Processing %1$s + %1$d%% %2$s + + Reinhardt + True Survivor + David Hasselhoff + Bring it on! I **LIVE** for this! + Reinhardt, we need to find you some new tunes 🎶. + Ah, you kids today with techno music! You should enjoy the classics, like Hasselhoff! + I can\'t even take you seriously right now. + + Daenerys + Angela Merkel + Julian Assange + Pierre + Weekend Plans + Are you sure it\'s safe here? + Yes, sure, don\'t worry. + Hallo alle zusammen! Is the NSA reading this? 😄 + Sorry, I\'ll have to publish this conversation on the web. + Wait, we could have made so much money on this! + + Eileen Lockhard + So, why is Telegram cool? + Well, look. Telegram is superfast and you can use it on all your devices at the same time – phones, tablets, even desktops. + 😴 + And it has secret chats, like this one, with end-to-end encryption! + End encryption to what end?? + Arrgh. Forget it. You can set a timer and send message that will disappear when the time runs out. Yay! + 😱🙈👍 + + Space Dandy + You see this chat preview because you are a **Translator**.\n\nPlease refer to @tgx_android_translate for guide on how to make your own scenes. + I knew it! Please don\'t ever tell me this again… + + 0 + + **Frogram X** was updated to version %1$s\n\nBrief overview of new features:\n%2$s + + You\'re currently offline. Please connect to the Internet in order to start messaging. + You currently have airplane mode enabled. Please turn it off or connect to Wi-Fi in order to start messaging. + Frogram X is unable to quickly establish connection with the server.\n\nPlease check your network connection or wait until this pop-up disappears automatically.\n\nProxy servers may be helpful in accessing Telegram if there is no connection in your region. + + Please send an email to %1$s and tell us about your problem + + sms@telegram.org + recover@telegram.org + + Frogram X connection issue + My Internet service provider is: (please enter the name)\n\nI\'ve just installed the application and tried to start messaging, but Frogram X is unable to connect to the server. Please help.\n\nApp version: %1$s\nLanguage: %2$s\nAwait time: %3$s\nSystem Language: %4$s\nSystem Version: %5$s + + Frogram X SMS not sent: %1$s + My Internet service provider is: (please enter the name)\n\nI\'m trying to use my mobile phone number: %1$s\nBut Telegram could not send me SMS with the confirmation code. Please help.\n\nBelow are all details that might help understanding the issue.\nError: %3$s\n%2$s + + Invalid phone number: %1$s + My mobile phone operator: (please enter the name)\nI\'m trying to use my mobile phone number: %1$s\nBut Telegram says it\'s invalid. Please help. + + Banned phone number: %1$s + I\'m trying to use my mobile phone number: %1$s\nBut Telegram says it\'s banned. Please help. + + Frogram X error: %1$s + I\'m trying to use my mobile phone number: %1$s\nBut Telegram shows an error. Please help.\nError: %2$s + + App version: %1$s\nLanguage: %2$s\nSystem Language: %3$s\nSystem Version: %4$s + + Are you sure you want to log out as %1$s?\n\nNote that you can seamlessly use Telegram on all your devices at once.\n\nRemember, logging out kills all your Secret Chats. Downloaded media will be erased from this device. + Sign out as %1$s? All secret chats on this account will be lost. Downloaded media will be erased from this device. + + Alternative options + Add another account + Set up multiple phone numbers and easily switch between them. + Set a Passcode + Lock the app with a passcode so that others can\'t open it. + Clear Cache + Free up disk space on your device; your media will stay in the cloud. + Change Phone Number + Move your contacts, groups, messages and media to a new number. + Contact Support + Tell us about any issues; logging out doesn\'t usually help. + Remember, logging out kills all your Secret Chats. Downloaded media will be erased from this device. + Sign out without deleting the account. You can sign back in using the same phone number to access your chats. + Tell us about any issues; after you delete the account, we won\'t be able to restore any data you lose in the process. + + Push Services + + TDLib Logs + **Warning:** TDLib Logs may contain **private data**.\n\nDo not share them with anyone, unless you know what you are doing. + Proceed + **Warning:** call diagnostics may contain **private data** such as IP addresses of the parties.\n\nDo not share them with anyone, unless you know what you are doing. + + No email application found + + Right-to-Left Layout + + Create New Theme + New theme will be based on the %1$s theme. + %1$s theme + Create Copy + Create + New Theme + Name + Wallpaper Link + Edit + Delete + Delete Theme + Permanently delete this theme? This action can\'t be undone. + Minimize + Close + + Accent + This list contains accent colors of the app.\nRefer to other categories for the granular setup. + Content + Header + Controls + Chats + Bubbles + Media + Instant View + Other + Service + + Text + Music Player + Icons + Background + These colors are displayed in Settings > Themes and Chats.\nMake sure they clearly represent corresponding themes on your **filling** color. + These colors are used as a transparent overlay when the corresponding wallpaper is set: dates, unread separators, inline keyboards, etc.\n\nDo not change them unless you are looking for a better color. + Unsorted + Attachment Menu + Media + + Red + Orange + Pink + Green + Purple + Cyan + Blue + + Hex + + R + G + B + A + + Default + H + S + L + A% + + Edit Name + Edit Wallpaper + Color Format + + Remove Transparency + Background (color or identifier) + Calculate + + Delete %1$s other version of %2$s?\n\nThis action cannot be undone. + Delete all %1$s other versions of %2$s?\n\nThis action cannot be undone. + Delete %1$s color + Delete %1$s colors + Delete current version of %1$s?\n\nThis action cannot be undone. + Delete Color + + Hex (#RRGGBBAA) + RGBA (Red, Green, Blue, Alpha) + HSLA (Hue, Saturation, Lightness, Alpha) + + Export + Export + If you specify the author\'s username, it will be displayed to users before they install the theme. + + Theme Author + Username or link + + %1$s (copy) + %1$s #%2$d + + Apply %1$s theme? + Apply %1$s theme by %2$s? + You can switch between installed themes in Settings > Themes and Chats + Apply theme + + %1$s color + %1$s colors + + %1$s property + %1$s properties + + %1$s item + %1$s items + + Default + + Properties + Edit Property + + Theme, %1$s + Demo + + Hold to see **fillingPressed** in action. Used on **Android 4.x only**. + Placeholder color used before image gets loaded. + Transparent background for the previews of stickers, media and chats. + Three-dot menus, sticker suggestions, small circle buttons, etc. + Swipe to see **fillingNegative** in action. + Background of the Send button in the Share menu. + Current query highlight when searching chats, contacts, etc. + Selected text background. + Pressed link background. + Buttons with neutral effect: save, done, cancel, etc. + Buttons with negative effect: delete, remove, clear, etc. + Color overlay for the drawer header. When empty, **header** color is used. + Text color for the drawer header. When empty, **headerText** color is used. + APK files + Archive files: .zip, .rar, .7z + PDF files + Light header is used when selecting media, messages, etc. + Solid chat background used when wallpaper is not set.\n\nWhen empty, **background** color is used instead. + Not yet downloaded part of the file. + Downloaded part of the file. + Playback progress of the file. + New trending sticker set + Used on **Android 5.x** and lower. + + Default values are inherited from this theme when a color or property is not explicitly set. + Replaces horizontal shadows with thin solid separators. + Depth of all shadows. Higher value means darker shadow. Default: light themes – 0.5, dark – 1.0 + Image corner radius. Usually ignored in bubble mode. + Bubble corner radius. + Bubble corner radius when merged with another bubble. + Bubble corner radius on **Android 4.x**. Max value: **6**. + Enables a solid outline for bubbles. You can configure its color with **bubbleOut_outline** or **bubbleIn_outline**.\n\nEnable this property if you change **bubbleCorner** values. + Width of the bubble outline. Used when **bubbleOutline** is enabled. + Transparency of **headerText** or **headerLightText** in the tab navigation, header subtitles, etc. + Default wallpaper identifier. 0 means wallpaper is disabled by default. Hold wallpaper thumbnail in settings to know its identifier. For solid wallpapers set to 0 and edit **bubble_chatBackground** color. + A magic property that allows sharing wallpaper settings between similar themes. **0** – light, **1** – dark, **2** – exclusive to theme.\n\nSet to **2**, if your color palette significantly differs from **parentTheme**, or if you disable default wallpaper while creating light theme. + Determines if the theme is dark and should be used at night.\n\nIt is preferable to change **parentTheme** instead of overriding this property. + Background corner radius for dates in the bubble mode. + Background corner radius for dates in the plain mode. + Adds shadow to the unread messages separator in the bubble mode. + When enabled, status bar icons will use dark colors. Used on **Android 6.x** and higher. + + These colors are used when wallpaper is disabled or not yet loaded.\n\nIf your theme does not allow disabling wallpaper, you can ignore them. + + %1$s, %2$s + + Check out %2$s\'s post: %1$s + Check out %2$s\'s message: %1$s + Check out %2$s\'s comment: %1$s + + %1$s\'s profile photo + "%1$s"\'s chat photo + %1$s\'s photo + + Check out %1$s: %2$s + Contact %1$s on Telegram: %2$s + Contact %1$s: %2$s + Contact me on Telegram: %1$s + My Telegram link: %1$s + Use %1$s on Telegram: %2$s + Join "%1$s" on Telegram: %2$s + Follow %1$s on Telegram: %2$s + Proxy for Telegram: %1$s. This link may be helpful in accessing Telegram if there is no connection in your region. + %1$s\n\nThis link may be helpful in accessing Telegram in censored regions. + Check out "%1$s" sticker set for Telegram: %2$s + Check out "%1$s" sticker set: %2$s + Check out %1$s translation for Telegram: %2$s + + Share to… + + %1$s: %2$s + %1$s (%2$s) + %1$s\n\n%2$s + + Photo from %1$s + Share photo to… + Share %1$s photo to… + Share %1$s photos to… + + Video from %1$s + Share video to… + Share %1$s video to… + Share %1$s videos to… + + GIF from %1$s + Share GIF to… + Share %1$s GIF to… + Share %1$s GIFs to… + + Music from %1$s + Share audio to… + Share %1$s audio to… + Share %1$s audios to… + + File from %1$s + Share file to… + Share %1$s file to… + Share %1$s files to… + + Share %1$s file to… + Share %1$s files to… + + Media from %1$s + Share media to… + Share %1$s media to… + Share %1$s media to… + + Share contact to… + + Message from %1$s + + Chat with %1$s + + Share Link + Share Link + Share Link + Share Bot + Share Proxy + Share Language + Share Stickers + + Share Contact + Saved + + Cancel Account Reset + Somebody with access to your phone number **%1$s** has requested to delete your Telegram account and reset your 2-Step Verification password.\n\nIf this wasn\'t you, please enter the code we\'ve just sent you via SMS to your number. You can also cancel this by **changing your phone number** to a number you control. + + %1$s mention + %1$s mentions + [edited]: %1$s + %1$s + + Mute + Mute %1$s + Mute all + + Unmute + Unmute %1$s + Unmute all + + Muted %1$s for 1 hour + Muted %1$s for 1 hour + Muted %1$s person for 1 hour + Muted %1$s people for 1 hour + + Unmuted %1$s + Unmuted %1$s + Unmuted %1$s person + Unmuted %1$s people + + Marked messages as read + Marked mentions as read + + Default + Enabled + Disabled + + Content Hidden + You have a new message + + Open Cloud Chat + + System Notification Settings + Badge Counter + Include Muted Chats + Count Unread Messages + Include Archived Chats + Switch on to show the number of unread messages instead of chats. + Switch off to show the number of unread chats instead of messages. + You can set custom notifications for specific users on their profile page. + You can set custom notifications for specific groups on their profile page. + You can set custom notifications for specific channels on their profile page. + Include Dismissed Messages + Switch on to include previously dismissed unread messages when new notification arrives from a chat. + Switch off to exclude previously dismissed unread messages when new notification arrives from a chat. + + Channels + + Mentions and Replies + + Personal Notifications + + Switch off to apply group notification settings when someone pins a message. You will receive no notification if the group is muted. + Switch on to apply private notification settings when someone pins a message. You will receive no notification if message author is muted. + + Switch off to apply group notification settings to mentions and replies. You will receive no notifications if the group is muted. + Switch on to apply private notification settings to mentions and replies. You will receive no notifications if message author is muted. + + Merge notification categories + Turn on to display notifications from private chats, groups and channels in a single notification group. + Turn off to display notifications from private chats, groups and channels separately. + + Default + Enabled + Disabled + + Default + Enabled + Disabled + + Private + Secret + Group Chats + Groups + Channels + Bots + Read + Unread + Muted + Archived + Contacts + Non-Contacts + + %1$s bot + %1$s bots + + %1$s • %2$s + + Advanced + + Pinned: %1$s + %1$s (pinned message) + + If a person has left the group in the past, you need to be in their Telegram contacts to add them back.\n\nThey can still join via the group\'s invite link as long as they are not on the Removed Users list. + The admins of this group have restricted your ability to send polls. + Sorry, this language pack doesn\'t exist + This feature is not available. Please make sure the app is up-to-date, or wait for new updates. + Page not found or no longer exists. + Sorry, you don\'t have access to this chat or channel. + Sorry, anonymous administrators cannot leave reactions or participate in polls. + Sorry, you don\'t have access to this chat or channel. + Sticker set not found or no longer exists. + Chat is inaccessible + Can\'t access the chat + Sorry, you are a member of too many groups or channels. Please leave some before joining a new one. + Sorry, this phone number is banned. Contact us at login@telegram.org if you need help. + Sorry, you have too many location-based groups already. Please delete one of your existing ones first. + This feature requires Telegram Premium subscription. + Request to join this chat has been sent. + The link is expired or was revoked by creator. + Sorry, the user restricted who can add them to chats in their privacy settings. + Sorry, the user restricted this action in their privacy settings. + Sorry, you can interact only with mutual contacts at the moment. + There are too many bots in this group. Please remove some of the bots you\'re not using first. + Sorry, this group has too many admins. Please remove one of the existing admins first. + Folder must contain at least one chat + Sorry, you have too many shareable folders. + Sorry, you have too many invite links. + The date you specified is invalid. + + Notification Style + Sound and pop-up + Vibrate and pop-up + Pop up on screen + Sound + Vibrate + Silent + Silent + Silent (lower priority) + Silent and minimised + Disabled + + %1$s exception + %1$s exceptions + + New Contacts Notification + + Notifications + Notifications are enabled by default. You can mute specific chats from the chat list. + Notifications are blocked by default. Change Notification Style value to unblock them. + Notifications are disabled by default. You can unmute specific chats from the chat list. + + Secret Chats on Lock Screen + Turn off to hide secret chat notifications when the device is locked. You will still receive sounds, if the device is not muted. + Turn on to display secret chat notifications when device is locked. This doesn\'t reveal the contents of messages. + + Hide on Lock Screen + Turn off to display secret chat notifications when device is locked. This doesn\'t reveal the contents of messages. + Turn on to hide secret chat notifications when device is locked. You will still receive sound, if device is not muted. + + Reset all notification settings, including custom notification settings for your contacts, groups and channels? + + Notifications from Telegram are blocked in system settings. Tap System Notification Settings to unblock them. + Notifications for the current account are disabled in system settings.\n\nTo enable notifications:\n• Tap System Notification Settings\n• Find the "%1$s" notification category\n• Turn the toggle on to unblock notifications. + Notifications from Telegram are blocked in your device settings.\n\nTo enable notifications:\n• Tap System Notification Settings.\n• Turn on Show Notifications. + Notifications from Telegram are blocked in your system settings.\n\nTo enable notifications:\n• Go to system settings – Applications – Frogram X.\n• Tap Notifications – Allow notifications. + You have data sync turned off in system settings. Notifications may not arrive when app is closed.\n\nData sync may be implicitly turned off by the battery optimization mode on your device. + You have data sync turned off for Frogram X. Notifications may not arrive when app is closed.\n\nData sync may be implicitly turned off by the battery optimization mode on your device. + Google Play Services are unavailable. Please check you have them installed and up-to-date.\n\nNotifications may arrive with big delays or not arrive at all without them. + **Firebase Services** have failed to function properly due to error: %1$s\n\nNotifications may arrive with big delays or not arrive at all without them.\n\nPlease make sure:\n• Google Play Services are installed and up-to-date: https://support.google.com/googleplay/answer/9037938?hl=en\n• Frogram X is up-to-date\n• Firebase services are enabled\n• They are not blocked by your Internet service or DNS provider\n• If you have firewall or ad blocking software, Firebase domains are whitelisted\n• You can see 404 message in a browser on this page: https://firebaseinstallations.googleapis.com/\n• System date and time is correct\n• Problem doesn\'t go away after restarting your device\n• All system updates are installed\n• You are using the **official** version of Frogram X: @tgx_log\n\nIf the steps above do not help, try again with VPN that you trust, as it might be caused by Internet censorship applied by authorities in your region. + **Frogram X** was unable to display some notifications for this account due to an unknown system error.\n\nPlease make sure:\n• All system updates are installed\n• Frogram X is up-to-date\n• There are no notification restrictions in system settings.\n\nIf the steps above do not help, you might want to share the detailed error report to @tgandroidtests, or look up for troubleshooting tips for your device. + **Frogram X** was unable to display some notifications from %1$s due to an unknown system error.\n\nPlease make sure:\n• All system updates are installed\n• Frogram X is up-to-date\n• There are no notification restrictions in system settings.\n\nIf the steps above do not help, you might want to share the detailed error report to @tgandroidtests, or look up for troubleshooting tips for your device. + **Frogram X** was unable to display some notifications for this account due to notification categories system limit.\n\nPlease make sure:\n• All system updates are installed\n• Frogram X is up-to-date\n• There are no notification restrictions in system settings.\n\nIf the steps above do not help, you might want to ask @tgandroidtests for troubleshooting tips for your device, or re-install Frogram X, which should help resolving this error, but requires logging in to your account again. + **Frogram X** was unable to display some notifications from %1$s due to notification categories system limit.\n\nPlease make sure:\n• All system updates are installed\n• Frogram X is up-to-date\n• There are no notification restrictions in system settings.\n\nIf the steps above do not help, you might want to ask @tgandroidtests for troubleshooting tips for your device, or re-install Frogram X, which should help resolving this error, but requires logging in to your account again. + Turn on data sync + Turn on data sync + Get Google Play Services + Share Error Report + Tap to resolve issue + Try again + Share error details + + You are already using this language pack (**%1$s**). You can change your language at any time in Settings. + You are about to apply a language pack (**%1$s**) that is %2$d%% complete.\n\nThis will translate the entire interface. You can suggest corrections via the [translation platform](%3$s).\n\nYou can change your language back at any time in Settings. + You are about to apply a custom language pack (**%1$s**) that is %2$d%% complete.\n\nThis will translate the entire interface. You can suggest corrections via the [translation platform](%3$s).\n\nYou can change your language back at any time in Settings. + Change Language + Language successfully changed + Remove Language + Are you sure you want to delete this language?\n\n%1$s / %2$s will no longer be available in the languages list.\n\nYou can return it back later by following this link:\n%3$s + + We have sent you an email to confirm your address. + Resend code + Are you sure you want to abort Two-Step Verification setup? + Are you sure you want to abort recovery email setup? + To complete recovery email setup, check %1$s (don\'t forget the spam folder) and enter the code we just sent you. + To complete recovery email change, check %1$s (don\'t forget the spam folder) and enter the code we just sent you. + Abort recovery email setup + Abort recovery email change + + Testing Utilities + **Warning**: Testing Utilities are available for **testing** and **debugging** purposes **only**. None of them are guaranteed to work.\n\nDo not use them, unless you know what you are doing. + Copy Version + Copy Report Details + Use when submitting a bug report + + Log Files + Application Logs + Turn off all logs + Delete all application log files? + + New Poll + New Quiz + Retract Vote + Stop Poll + Stop Quiz + + This message cannot be forwarded to secret chats. + + If you stop this poll now, nobody will be able to vote in it anymore.\n\nThis action cannot be undone. + If you stop this quiz now, nobody will be able to participate in it anymore.\n\nThis action cannot be undone. + + View Results + View Results + View %1$s Result + View %1$s Results + View %1$s Result + View %1$s Results + Vote + + Quiz + Poll + Question + Ask a Question + Option + Poll options + Quiz options + Discard Poll + Are you sure you want to discard this poll? + Discard Quiz + Are you sure you want to discard this quiz? + Add an option… + You can add %1$s more option + You can add %1$s more options + You have added the maximum number of options. + + Anonymous Poll + Poll + Final Results + Anonymous Quiz + Quiz + Final Results + + Poll Results + Quiz Results + + %1$s result + %1$s results + ~%1$s result + ~%1$s results + + %1$s vote + %1$s votes + No votes + + %1$s answer + %1$s answers + No answers yet + + **Want notifications for new messages?**\n\nTurn on system auto sync to get notifications while app is closed. + Never show again + Turn on + No, thanks + + Aw, Snap! + Launch App + Check for Updates + Share error details + View error details + Erase Database & Launch App + + offline + + Disk storage is full + Frogram X has previously failed to launch because the device storage was full.\n\nMake sure there\'s enough storage space available and press **Launch App** to try again.\n\nCurrently available: %1$s + + Corrupted database + Frogram X has previously failed to launch because TDLib data has been corrupted. This could have happened because of device storage failure.\n\nPress **Launch App** to continue. If application keeps failing, follow these steps:\n\n• Check you have enough disk space available: **%1$s**.\n• Ensure there are no other storage issues, such as SD-card being ejected or unrecognized.\n• Restart your device.\n\nIf this does not help, you may want to look for similar issues on [TDLib\'s GitHub page](https://github.com/tdlib/td/issues) for possible resolutions, or create a new one, including error message and device details. + + External error + Frogram X has previously failed to launch because of device error.\n\nPress **Launch App** to try again. If application keeps failing, follow these steps:\n\n• Check you have enough disk space available: **%1$s**.\n• Ensure there are no other storage issues, such as SD-card being ejected or unrecognized.\n• Restart your device.\n\nIf this does not help, you may want to look for similar issues on [TDLib\'s GitHub page](https://github.com/tdlib/td/issues) for possible resolutions, or create a new one, including error message and device details. + + TDLib fatal error. Version: %1$s + Frogram X has previously failed to launch because of TDLib fatal error.\n\nPress **Launch App** to try again. If application continues to fail, follow these steps:\n\n• [Verify](%2$s) you have the latest Frogram X version installed.\n• Restart your device.\n\n**If the steps above do not help**\n\n1. Share error details with TDLib developers using one of the following ways:\n— Privately via [@tdlib_bot](https://t.me/tdlib_bot) by using another device or [Telegram Web](https://web.telegram.org/).\n— Publicly via [GitHub page](https://github.com/tdlib/td/issues). **Do not** share **tdlib_log.txt** publicly.\n2. Kindly wait for the response.\n3. Change log settings below as requested by TDLib developers.\n4. Press **Launch App** to make app force stop again.\n5. Share **tdlib_log.txt** with TDLib developers and wait for the problem to be resolved.\n6. Once updated, you\'ll be able to launch app normally.\n\n**Alternative options**\n\n• Search for similar issues on [GitHub](https://github.com/tdlib/td/issues) to see if there are common solutions.\n• Reinstall the app. Secret chats will be lost. If you use same phone number you were logged in, all other chats and data will be restored from the Telegram cloud. + + Unexpected error + Frogram X has closed unexpectedly the last time you were using it.\n\nPress **Launch App** to try again. + + Self-Destruct Photo + Self-Destruct Video + Self-Destruct Voice Message + Self-Destruct Video Message + + Invoice for %1$s + Invoice + Recurring payment + You successfully paid %1$s + + Other + Checking for new messages + Account: %1$s + Failed to fetch messages. Tap to resolve. + You may have a new message + Account: %1$s + Missed notifications + + Display Notifications Content + If enabled, you will see notifications content when app is locked, however, actions such as Reply or Mark as Read will not be available until you unlock the app. + If enabled, notification content is shown while the app is locked. Reply and Mark as Read are controlled separately. + Reply and Mark as Read While Locked + Can\'t unlock app, because of instant Auto-Lock. Hold lock button to change this. + This account was hidden by the user. + + Unsupported video format. Try using less video options or sending this video as a file. See log for details. + + Optimizing Database + Telegram optimizes the database after an update. Please wait. This operation may take a while. + + Sorry, this type of media is not yet supported. + + Logged in: %1$s + Last active: %1$s + + Erase All Data + All data successfully erased. + Unable to delete files. + Erasing all data… Please wait, this may take some time. \nDon\'t close the app. + **Warning!**\n\nSecret Chats will be lost. All media will need to be downloaded again. + **No, seriously.**\n\nAre you sure you want to clear Local Database, delete all downloaded media files and kill all Secret Chats? + This action does not affect other accounts. + Please wait until the previous operation is completed. + + Mark all chats as read + Are you sure you want to mark all chats and mentions as read? + Marked %1$s chat as read + Marked %1$s chats as read + Marked %1$s chat as unread + Marked %1$s chats as unread + + Unknown + + Signed out as %1$s + + Statistics + View Statistics + + Instant View for this page is not yet supported. + Instant View for this page is not available. + Instant View could not be displayed due to an error. + Instant View for this section is not yet supported. + Localizations + Settings and Themes + + Drawings + Frogram X remembers vector drawings you made via the in-app image editor for possible future use.\n\nWould you like to make Frogram X unsee them? + + Unused Files + Service files that were created while using some features or older app versions. + + %1$s (approx.) + + Show Other Chats + + Use System Fonts + **Warning!**\n\nFrogram X does not guarantee proper rendering of system fonts. + + Restart the app for this to take effect. + + %1$s + %2$s + + Downloaded + Update Needed + Installing… + Emoji Set + Current Set + Default + 😀😉\n😔😨 + This affects emoji appearance only for you. Others see them based on their preferences. + Emoji Sets + Are you sure you want to clear unused emoji sets? + Big Emoji + Dynamic Sets Order + Automatically place recently used sticker sets above others. + Dynamic Pack Order + Automatically place recently used emoji packs above others. + + You do not have enough privileges to perform this action. + Chat Permissions + Reactions + This permission is disabled for all members without admin privileges. + What can members of this group do? + Member since %1$s at %2$s + %1$s\n%2$s + %1$s\n%2$s + %1$s\n%2$s + %1$s\n%2$s\n%3$s + %1$s (%2$s)\n%3$s + %1$s\n\n%2$s + + Allowed %1$s/%2$s + Allowed %1$s/%2$s + %1$s of %2$s + %1$s of %2$s + %1$s of %2$s + %1$s of %2$s + + You cannot send messages to this user + + Only admins can send GIFs in this group + Only admins can use inline bots in this group + Only admins can send stickers in this group + Only admins can send stickers in this group + Only admins can roll a die in this group. Hold to send it as an emoji. + Only admins can play darts in this group. Hold to send it as an emoji. + Only admins can send media in this group + Only admins can send music in this group + Only admins can send files in this group + Only admins can send photos in this group + Only admins can send videos in this group + Only admins can send stories in this group + Only admins can send stickers and GIFs in this group + Only admins can send voice messages in this group + Only admins can send video messages in this group + Only admins can create polls in this group + Only admins can write messages in this group + + The admins of this group have restricted your ability to send GIFs. + Admins have restricted you from sending GIFs in this group until %1$s + The admins of this group have restricted your ability to send inline content. + The admins of this group have restricted your ability to send inline content until %1$s + The admins of this group have restricted your ability to start games here. + The admins of this group have restricted your ability to start games here until %1$s + Admins have restricted you from sending stickers in this group + Admins have restricted you from sending stickers in this group until %1$s + Admins have restricted you from rolling a die in this group. Hold to send it as an emoji. + Admins have restricted you from rolling a die in this group until %1$s. Hold to send it as an emoji. + Admins have restricted you from playing darts in this group. Hold to send it as an emoji. + Admins have restricted you from playing darts in this group until %1$s. Hold to send it as an emoji. + Admins have restricted you from sending voice messages in this group + Admins have restricted you from sending voice messages in this group until %1$s + Admins have restricted you from sending video messages in this group + The admins of this group have restricted your ability to send video messages until %1$s. + The admins of this group have restricted your ability to send media. + Admins have restricted you from sending media in this group until %1$s + The admins of this group have restricted your ability to send music. + Admins have restricted you from sending music in this group until %1$s + The admins of this group have restricted your ability to send files. + Admins have restricted you from sending files in this group until %1$s + The admins of this group have restricted your ability to send photos. + Admins have restricted you from sending photos in this group until %1$s + The admins of this group have restricted your ability to send videos. + Admins have restricted you from sending videos in this group until %1$s + The admins of this group have restricted your ability to send stories. + Admins have restricted you from sending stories in this group until %1$s + The admins of this group have restricted your ability to send stickers and GIFs. + Admins have restricted you from sending stickers and GIFs in this group until %1$s + The admins of this group have restricted your ability to send polls. + Admins have restricted you from sending polls in this group until %1$s + Admins have restricted you from sending messages in this group + Admins have restricted you from sending messages in this group until %1$s + Admins have banned you in this group + Admins have banned you in this group until %1$s + + To perform this action, this chat will be converted to supergroup.\n\n**Note**: new members will not see messages sent before the conversion. + Frogram X is ready to be updated. + Restart + Update + + Tap to set public group link + Tap to set public channel link + + You must be at least %1$s year old to use Telegram. + You must be at least %1$s years old to use Telegram. + + Terms of Service + Agree + + Do not have a link to your account + Do not have a link to your account (%1$s) + Contacts can link to my account + Contacts can link to my account (%1$s) + Have a link to your account + Have a link to your account (%1$s) + Forwarded Messages + With a link to my account + Without a link to my account + Only contacts can link to my account + + Visible + Hidden + Visible only for contacts + Nobody can see your profile photo + Nobody (%1$s) can see your profile photo + Only contacts can see your profile photo + Only contacts (%1$s) can see your profile photo + Everybody can see your profile photo + Everybody (%1$s) can see your profile photo + Profile Photos + + Visible + Hidden + Visible only for contacts + Nobody can see your saved music + Nobody (%1$s) can see your saved music + Only contacts can see your saved music + Only contacts (%1$s) can see your saved music + Everybody can see your saved music + Everybody (%1$s) can see your saved music + Saved Music + + Nobody can send you voice messages + Nobody (%1$s) can send you voice messages + Only contacts can send you voice messages + Only contacts (%1$s) can send you voice messages + Everybody can send you voice messages + Everybody (%1$s) can send you voice messages + Allowed + Disallowed + Only contacts + Voice and Video Messages + + Nobody can display gifts without approval + Nobody (%1$s) can display gifts without approval + Only contacts can display gifts without approval + Only contacts (%1$s) can display gifts without approval + Everybody can display gifts without approval + Everybody (%1$s) can display gifts without approval + Auto-accept Gifts + Only contacts + All + Only approved + + Everybody pays a message fee + Everybody (%1$s) pays a message fee + Only contacts do not pay a message fee + Only contacts (%1$s) do not pay a message fee + Everybody can message you without a fee + Everybody (%1$s) can message you without a fee + + Who can send me voice or video messages? + You can restrict who can send you voice or video messages with granular precision. + Who can display gifts on my profile? + Choose whether gifts from specific senders need your approval before they\'re visible to others on your profile. + Messages + Everybody can message you + Paid + Only contacts and **Premium** users + Messages + New Chats + Who can send me messages? + You can restrict messages from users who are not in your contacts and whom you haven\'t messaged first. + + Send Me Voice Messages + Display Gifts without approval + + Remove Fee + + Who can add a link to my account when forwarding my messages? + You can restrict who can include a link to your account when forwarding your messages to other chats. + + Who can see your profile photo? + You can restrict who can see your profile photo with granular precision. + + Who can see your saved music? + You can restrict who can see your saved music with granular precision. + + %1$s: %2$s + + Animated Stickers + Are you sure you want to clear animated stickers cache? + + Discard message + Are you sure you want to discard edited message? These changes will be lost. + + Discard caption + Are you sure you want to discard caption? These changes will be lost. + Are you sure you want to discard edited caption? These changes will be lost. + + Took a screenshot + Pinned Message + Media unavailable + Display sensitive content + Ignore content restrictions + + %1$s 🔕 + 🔕 %1$s + + 📅 Reminder + + 📅 Scheduled message for %1$s + 📅 Scheduled message for %1$s + 📅 Scheduled message posted in %1$s + 📅 %1$s + + + Chat List Style + + Two lines + Three lines + Three lines (bigger text) + + %1$s, %2$s + + Icon Set + Default + Downloaded + Update Needed + Installing… + Current Set + + Emoji set %1$s has been updated. Would you like to download a new version to keep using it? + Download and update + + Resend + Send failed: %1$s + Last edit: %1$s + Resend %1$s message + Resend %1$s messages + Emoji update unavailable. Please try again later. + + %1$s and you have added each other in the contacts list. + %1$s is in your contacts list. + + Mutual contact + Contact + Non-Contact + + %1$s and you have each other in the contacts list, but they do not share the phone number with you. + You do not have access to %1$s\'s phone number. + + Archive + Archived Chats + Archived Chats + Unarchive + Unarchive + + Archive Chat + Unarchive Chat + + Archive chat with %1$s? + Archive %1$s? + Archive chat with %1$s? It will remain in the list as current folder does not exclude archived chats. + Archive %1$s? It will remain in the list as current folder does not exclude archived chats. + Unarchive chat with %1$s? + Unarchive %1$s? + Unarchive chat with %1$s? It will remain in the current chat folder. + Unarchive %1$s? It will remain in the current chat folder. + + Share Phone Number + Share My Phone Number + Phone Number + Who can see your Phone Number? + Users who have your number saved in their contacts will also see it on Telegram. + Who can see your bio? + You can restrict who can see the bio on your profile with granular precision. + Who can see your birthday? + You can restrict who can see the birthday on your profile with granular precision. + + Visible + Visible only for contacts + Hidden + Nobody can see your phone number + Nobody (%1$s) can see your phone number + Only contacts can see your phone number + Only contacts (%1$s) can see your phone number + Everybody can see your phone number + Everybody (%1$s) can see your phone number + + Visible + Visible only for contacts + Hidden + Nobody can see your bio + Nobody (%1$s) can see your bio + Only contacts can see your bio + Only contacts (%1$s) can see your bio + Everybody can see your bio + Everybody (%1$s) can see your bio + + Visible + Visible only for contacts + Hidden + Nobody can see your birthday + Nobody (%1$s) can see your birthday + Only contacts can see your birthday + Only contacts (%1$s) can see your birthday + Everybody can see your birthday + Everybody (%1$s) can see your birthday + + + Only contacts can find you on Telegram + Only contacts (%1$s) can find you on Telegram + Everybody can find you on Telegram + Everybody (%1$s) can find you on Telegram + + Share my phone number with %1$s + + Finding by Phone Number + Who can find me by my number? + Users who have your number saved in the contacts list will also see it on Telegram. + Users who have your number saved in the contacts list will also see it on Telegram.\n\nThis public link opens a chat with you: %1$s + Users who add your number to their contacts will see it on Telegram only if they are your contacts. + + Number is unknown + Phone number will be visible once %1$s adds you as a contact or changes their privacy settings. + + All Chats Archive Archive / Private Archive / Groups