mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-17 07:23:21 +01:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e486a4baef | ||
|
|
5fc11baf9e | ||
|
|
157777cac1 | ||
|
|
99d0ee6725 | ||
|
|
b5c1051506 |
@@ -33,8 +33,8 @@ ktlint {
|
||||
version = "0.49.1"
|
||||
}
|
||||
|
||||
def canonicalVersionCode = 1354
|
||||
def canonicalVersionName = "6.39.0"
|
||||
def canonicalVersionCode = 1355
|
||||
def canonicalVersionName = "6.39.1"
|
||||
|
||||
def postFixSize = 100
|
||||
def abiPostFix = ['universal' : 0,
|
||||
|
||||
@@ -17,13 +17,15 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter;
|
||||
import org.thoughtcrime.securesms.database.MediaTable;
|
||||
import org.thoughtcrime.securesms.mediapreview.MediaPreviewCache;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.mms.Slide;
|
||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ThreadPhotoRailView extends FrameLayout {
|
||||
|
||||
@NonNull private final RecyclerView recyclerView;
|
||||
@@ -56,11 +58,11 @@ public class ThreadPhotoRailView extends FrameLayout {
|
||||
}
|
||||
}
|
||||
|
||||
public void setCursor(@NonNull GlideRequests glideRequests, @Nullable Cursor cursor) {
|
||||
this.recyclerView.setAdapter(new ThreadPhotoRailAdapter(getContext(), glideRequests, cursor, this.listener));
|
||||
public void setMediaRecords(@NonNull GlideRequests glideRequests, @NonNull List<MediaTable.MediaRecord> mediaRecords) {
|
||||
this.recyclerView.setAdapter(new ThreadPhotoRailAdapter(getContext(), glideRequests, mediaRecords, this.listener));
|
||||
}
|
||||
|
||||
private static class ThreadPhotoRailAdapter extends CursorRecyclerViewAdapter<ThreadPhotoRailAdapter.ThreadPhotoViewHolder> {
|
||||
private static class ThreadPhotoRailAdapter extends RecyclerView.Adapter<ThreadPhotoRailAdapter.ThreadPhotoViewHolder> {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final String TAG = Log.tag(ThreadPhotoRailAdapter.class);
|
||||
@@ -69,18 +71,27 @@ public class ThreadPhotoRailView extends FrameLayout {
|
||||
|
||||
@Nullable private OnItemClickedListener clickedListener;
|
||||
|
||||
private final List<MediaTable.MediaRecord> mediaRecords = new ArrayList<>();
|
||||
|
||||
private ThreadPhotoRailAdapter(@NonNull Context context,
|
||||
@NonNull GlideRequests glideRequests,
|
||||
@Nullable Cursor cursor,
|
||||
@NonNull List<MediaTable.MediaRecord> mediaRecords,
|
||||
@Nullable OnItemClickedListener listener)
|
||||
{
|
||||
super(context, cursor);
|
||||
this.glideRequests = glideRequests;
|
||||
this.clickedListener = listener;
|
||||
|
||||
this.mediaRecords.clear();
|
||||
this.mediaRecords.addAll(mediaRecords);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThreadPhotoViewHolder onCreateItemViewHolder(ViewGroup parent, int viewType) {
|
||||
public int getItemCount() {
|
||||
return mediaRecords.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull ThreadPhotoViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View itemView = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.recipient_preference_photo_rail_item, parent, false);
|
||||
|
||||
@@ -88,18 +99,14 @@ public class ThreadPhotoRailView extends FrameLayout {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindItemViewHolder(ThreadPhotoViewHolder viewHolder, @NonNull Cursor cursor) {
|
||||
ThumbnailView imageView = viewHolder.imageView;
|
||||
MediaTable.MediaRecord mediaRecord = MediaTable.MediaRecord.from(cursor);
|
||||
public void onBindViewHolder(@NonNull ThreadPhotoViewHolder viewHolder, int position) {
|
||||
MediaTable.MediaRecord mediaRecord = mediaRecords.get(position);
|
||||
Slide slide = MediaUtil.getSlideForAttachment(mediaRecord.getAttachment());
|
||||
|
||||
if (slide != null) {
|
||||
imageView.setImageResource(glideRequests, slide, false, false);
|
||||
}
|
||||
|
||||
imageView.setOnClickListener(v -> {
|
||||
MediaPreviewCache.INSTANCE.setDrawable(imageView.getImageDrawable());
|
||||
if (clickedListener != null) clickedListener.onItemClicked(imageView, mediaRecord);
|
||||
viewHolder.imageView.setImageResource(glideRequests, slide, false, false);
|
||||
viewHolder.imageView.setOnClickListener(v -> {
|
||||
MediaPreviewCache.INSTANCE.setDrawable(viewHolder.imageView.getImageDrawable());
|
||||
if (clickedListener != null) clickedListener.onItemClicked(viewHolder.imageView, mediaRecord);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -555,7 +555,7 @@ class ConversationSettingsFragment : DSLSettingsFragment(
|
||||
}
|
||||
}
|
||||
|
||||
if (state.sharedMedia != null && state.sharedMedia.count > 0) {
|
||||
if (state.sharedMedia.isNotEmpty()) {
|
||||
dividerPref()
|
||||
|
||||
sectionHeaderPref(R.string.recipient_preference_activity__shared_media)
|
||||
@@ -563,7 +563,7 @@ class ConversationSettingsFragment : DSLSettingsFragment(
|
||||
@Suppress("DEPRECATION")
|
||||
customPref(
|
||||
SharedMediaPreference.Model(
|
||||
mediaCursor = state.sharedMedia,
|
||||
mediaRecords = state.sharedMedia,
|
||||
mediaIds = state.sharedMediaIds,
|
||||
onMediaRecordClick = { view, mediaRecord, isLtr ->
|
||||
view.transitionName = "thumb"
|
||||
|
||||
@@ -30,7 +30,6 @@ import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.recipients.RecipientUtil
|
||||
import org.thoughtcrime.securesms.util.FeatureFlags
|
||||
import java.io.IOException
|
||||
import java.util.Optional
|
||||
|
||||
private val TAG = Log.tag(ConversationSettingsRepository::class.java)
|
||||
|
||||
@@ -56,11 +55,11 @@ class ConversationSettingsRepository(
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
fun getThreadMedia(threadId: Long): Optional<Cursor> {
|
||||
return if (threadId <= 0) {
|
||||
Optional.empty()
|
||||
fun getThreadMedia(threadId: Long, limit: Int): Cursor? {
|
||||
return if (threadId > 0) {
|
||||
SignalDatabase.media.getGalleryMediaForThread(threadId, MediaTable.Sorting.Newest, limit)
|
||||
} else {
|
||||
Optional.of(SignalDatabase.media.getGalleryMediaForThread(threadId, MediaTable.Sorting.Newest))
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package org.thoughtcrime.securesms.components.settings.conversation
|
||||
|
||||
import android.database.Cursor
|
||||
import org.thoughtcrime.securesms.components.settings.conversation.preferences.ButtonStripPreference
|
||||
import org.thoughtcrime.securesms.components.settings.conversation.preferences.CallPreference
|
||||
import org.thoughtcrime.securesms.components.settings.conversation.preferences.LegacyGroupPreference
|
||||
import org.thoughtcrime.securesms.database.MediaTable
|
||||
import org.thoughtcrime.securesms.database.model.IdentityRecord
|
||||
import org.thoughtcrime.securesms.database.model.StoryViewState
|
||||
import org.thoughtcrime.securesms.groups.GroupId
|
||||
@@ -18,7 +18,7 @@ data class ConversationSettingsState(
|
||||
val buttonStripState: ButtonStripPreference.State = ButtonStripPreference.State(),
|
||||
val disappearingMessagesLifespan: Int = 0,
|
||||
val canModifyBlockedState: Boolean = false,
|
||||
val sharedMedia: Cursor? = null,
|
||||
val sharedMedia: List<MediaTable.MediaRecord> = emptyList(),
|
||||
val sharedMediaIds: List<Long> = listOf(),
|
||||
val displayInternalRecipientDetails: Boolean = false,
|
||||
val calls: List<CallPreference.Model> = emptyList(),
|
||||
|
||||
@@ -13,13 +13,13 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import io.reactivex.rxjava3.subjects.PublishSubject
|
||||
import io.reactivex.rxjava3.subjects.Subject
|
||||
import org.signal.core.util.CursorUtil
|
||||
import org.signal.core.util.ThreadUtil
|
||||
import org.signal.core.util.concurrent.SignalExecutors
|
||||
import org.signal.core.util.readToList
|
||||
import org.thoughtcrime.securesms.components.settings.conversation.preferences.ButtonStripPreference
|
||||
import org.thoughtcrime.securesms.components.settings.conversation.preferences.CallPreference
|
||||
import org.thoughtcrime.securesms.components.settings.conversation.preferences.LegacyGroupPreference
|
||||
import org.thoughtcrime.securesms.database.AttachmentTable
|
||||
import org.thoughtcrime.securesms.database.MediaTable
|
||||
import org.thoughtcrime.securesms.database.RecipientTable
|
||||
import org.thoughtcrime.securesms.database.model.StoryViewState
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
@@ -34,7 +34,6 @@ import org.thoughtcrime.securesms.util.FeatureFlags
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil
|
||||
import org.thoughtcrime.securesms.util.livedata.Store
|
||||
import java.util.Optional
|
||||
|
||||
sealed class ConversationSettingsViewModel(
|
||||
private val callMessageIds: LongArray,
|
||||
@@ -42,8 +41,6 @@ sealed class ConversationSettingsViewModel(
|
||||
specificSettingsState: SpecificSettingsState
|
||||
) : ViewModel() {
|
||||
|
||||
private val openedMediaCursors = HashSet<Cursor>()
|
||||
|
||||
@Volatile
|
||||
private var cleared = false
|
||||
|
||||
@@ -66,37 +63,26 @@ sealed class ConversationSettingsViewModel(
|
||||
val threadId: LiveData<Long> = state.map { it.threadId }.distinctUntilChanged()
|
||||
val updater: LiveData<Long> = LiveDataUtil.combineLatest(threadId, sharedMediaUpdateTrigger) { tId, _ -> tId }
|
||||
|
||||
val sharedMedia: LiveData<Optional<Cursor>> = LiveDataUtil.mapAsync(SignalExecutors.BOUNDED, updater) { tId ->
|
||||
repository.getThreadMedia(tId)
|
||||
val sharedMedia: LiveData<List<MediaTable.MediaRecord>> = LiveDataUtil.mapAsync(SignalExecutors.BOUNDED, updater) { tId ->
|
||||
repository.getThreadMedia(threadId = tId, limit = 100)?.readToList { cursor ->
|
||||
MediaTable.MediaRecord.from(cursor)
|
||||
} ?: emptyList()
|
||||
}
|
||||
|
||||
store.update(repository.getCallEvents(callMessageIds).toObservable()) { callRecords, state ->
|
||||
state.copy(calls = callRecords.map { (call, messageRecord) -> CallPreference.Model(call, messageRecord) })
|
||||
}
|
||||
|
||||
store.update(sharedMedia) { cursor, state ->
|
||||
store.update(sharedMedia) { mediaRecords, state ->
|
||||
if (!cleared) {
|
||||
if (cursor.isPresent) {
|
||||
openedMediaCursors.add(cursor.get())
|
||||
}
|
||||
|
||||
val ids: List<Long> = cursor.map<List<Long>> {
|
||||
val result = mutableListOf<Long>()
|
||||
while (it.moveToNext()) {
|
||||
result.add(CursorUtil.requireLong(it, AttachmentTable.ROW_ID))
|
||||
}
|
||||
result
|
||||
}.orElse(listOf())
|
||||
|
||||
state.copy(
|
||||
sharedMedia = cursor.orElse(null),
|
||||
sharedMediaIds = ids,
|
||||
sharedMedia = mediaRecords,
|
||||
sharedMediaIds = mediaRecords.mapNotNull { it.attachment?.attachmentId?.rowId },
|
||||
sharedMediaLoaded = true,
|
||||
displayInternalRecipientDetails = repository.isInternalRecipientDetailsEnabled()
|
||||
)
|
||||
} else {
|
||||
cursor.orElse(null).ensureClosed()
|
||||
state.copy(sharedMedia = null)
|
||||
state.copy(sharedMedia = emptyList())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,7 +109,6 @@ sealed class ConversationSettingsViewModel(
|
||||
|
||||
override fun onCleared() {
|
||||
cleared = true
|
||||
openedMediaCursors.forEach { it.ensureClosed() }
|
||||
store.clear()
|
||||
disposable.clear()
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.thoughtcrime.securesms.components.settings.conversation.preferences
|
||||
|
||||
import android.database.Cursor
|
||||
import android.view.View
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.ThreadPhotoRailView
|
||||
@@ -22,7 +21,7 @@ object SharedMediaPreference {
|
||||
}
|
||||
|
||||
class Model(
|
||||
val mediaCursor: Cursor,
|
||||
val mediaRecords: List<MediaTable.MediaRecord>,
|
||||
val mediaIds: List<Long>,
|
||||
val onMediaRecordClick: (View, MediaTable.MediaRecord, Boolean) -> Unit
|
||||
) : PreferenceModel<Model>() {
|
||||
@@ -41,7 +40,7 @@ object SharedMediaPreference {
|
||||
private val rail: ThreadPhotoRailView = itemView.findViewById(R.id.rail_view)
|
||||
|
||||
override fun bind(model: Model) {
|
||||
rail.setCursor(GlideApp.with(rail), model.mediaCursor)
|
||||
rail.setMediaRecords(GlideApp.with(rail), model.mediaRecords)
|
||||
rail.setListener { v, m ->
|
||||
model.onMediaRecordClick(v, m, ViewUtil.isLtr(rail))
|
||||
}
|
||||
|
||||
@@ -76,22 +76,46 @@ class GroupReceiptTable(context: Context?, databaseHelper: SignalDatabase?) : Da
|
||||
}
|
||||
|
||||
fun setUnidentified(results: Collection<Pair<RecipientId, Boolean>>, mmsId: Long) {
|
||||
val mmsMatchPrefix = "$MMS_ID = $mmsId AND"
|
||||
val unidentifiedQueries = SqlUtil.buildCollectionQuery(
|
||||
column = RECIPIENT_ID,
|
||||
values = results.filter { it.second() }.map { it.first().serialize() },
|
||||
prefix = mmsMatchPrefix
|
||||
)
|
||||
val identifiedQueries = SqlUtil.buildCollectionQuery(
|
||||
column = RECIPIENT_ID,
|
||||
values = results.filterNot { it.second() }.map { it.first().serialize() },
|
||||
prefix = mmsMatchPrefix
|
||||
)
|
||||
writableDatabase.withinTransaction { db ->
|
||||
for (result in results) {
|
||||
unidentifiedQueries.forEach {
|
||||
db.update(TABLE_NAME)
|
||||
.values(UNIDENTIFIED to if (result.second()) 1 else 0)
|
||||
.where("$MMS_ID = ? AND $RECIPIENT_ID = ?", mmsId.toString(), result.first().serialize())
|
||||
.values(UNIDENTIFIED to 1)
|
||||
.where(it.where, it.whereArgs)
|
||||
.run()
|
||||
}
|
||||
|
||||
identifiedQueries.forEach {
|
||||
db.update(TABLE_NAME)
|
||||
.values(UNIDENTIFIED to 0)
|
||||
.where(it.where, it.whereArgs)
|
||||
.run()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setSkipped(recipients: Collection<RecipientId>, mmsId: Long) {
|
||||
val mmsMatchPrefix = "$MMS_ID = $mmsId AND"
|
||||
val queries = SqlUtil.buildCollectionQuery(
|
||||
column = RECIPIENT_ID,
|
||||
values = recipients.map { it.serialize() },
|
||||
prefix = mmsMatchPrefix
|
||||
)
|
||||
writableDatabase.withinTransaction { db ->
|
||||
for (recipient in recipients) {
|
||||
queries.forEach {
|
||||
db.update(TABLE_NAME)
|
||||
.values(STATUS to STATUS_SKIPPED)
|
||||
.where("$MMS_ID = ? AND $RECIPIENT_ID = ?", mmsId.toString(), recipient.serialize())
|
||||
.where(it.where, it.whereArgs)
|
||||
.run()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,13 +143,19 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD
|
||||
}
|
||||
}
|
||||
|
||||
fun getGalleryMediaForThread(threadId: Long, sorting: Sorting): Cursor {
|
||||
val query = if (FeatureFlags.instantVideoPlayback()) {
|
||||
@JvmOverloads
|
||||
fun getGalleryMediaForThread(threadId: Long, sorting: Sorting, limit: Int = 0): Cursor {
|
||||
var query = if (FeatureFlags.instantVideoPlayback()) {
|
||||
sorting.applyToQuery(applyEqualityOperator(threadId, GALLERY_MEDIA_QUERY_INCLUDING_TEMP_VIDEOS))
|
||||
} else {
|
||||
sorting.applyToQuery(applyEqualityOperator(threadId, GALLERY_MEDIA_QUERY))
|
||||
}
|
||||
val args = arrayOf(threadId.toString() + "")
|
||||
|
||||
if (limit > 0) {
|
||||
query = "$query LIMIT $limit"
|
||||
}
|
||||
|
||||
return readableDatabase.rawQuery(query, args)
|
||||
}
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ public class StorageAccountRestoreJob extends BaseJob {
|
||||
Log.i(TAG, "Applying changes locally...");
|
||||
SignalDatabase.getRawDatabase().beginTransaction();
|
||||
try {
|
||||
StorageSyncHelper.applyAccountStorageSyncUpdates(context, Recipient.self(), accountRecord, false);
|
||||
StorageSyncHelper.applyAccountStorageSyncUpdates(context, Recipient.self().fresh(), accountRecord, false);
|
||||
SignalDatabase.getRawDatabase().setTransactionSuccessful();
|
||||
} finally {
|
||||
SignalDatabase.getRawDatabase().endTransaction();
|
||||
|
||||
@@ -199,7 +199,7 @@ internal class AccountValues internal constructor(store: KeyValueStore) : Signal
|
||||
fun generateAciIdentityKeyIfNecessary() {
|
||||
synchronized(this) {
|
||||
if (store.containsKey(KEY_ACI_IDENTITY_PUBLIC_KEY)) {
|
||||
Log.w(TAG, "Tried to generate an ANI identity, but one was already set!", Throwable())
|
||||
Log.w(TAG, "Tried to generate an ACI identity, but one was already set!", Throwable())
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -157,8 +157,9 @@ public final class LiveRecipient {
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
public void refresh() {
|
||||
public LiveRecipient refresh() {
|
||||
refresh(getId());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1196,7 +1196,7 @@ public class Recipient {
|
||||
* Forces retrieving a fresh copy of the recipient, regardless of its state.
|
||||
*/
|
||||
public @NonNull Recipient fresh() {
|
||||
return live().resolve();
|
||||
return live().refresh().resolve();
|
||||
}
|
||||
|
||||
public @NonNull LiveRecipient live() {
|
||||
|
||||
@@ -36,6 +36,7 @@ import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
import org.whispersystems.signalservice.internal.storage.protos.AccountRecord;
|
||||
import org.whispersystems.signalservice.internal.storage.protos.OptionalBool;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@@ -126,9 +127,15 @@ public final class StorageSyncHelper {
|
||||
record = recipientTable.getRecordForSync(self.getId());
|
||||
}
|
||||
|
||||
if (record == null) {
|
||||
Log.w(TAG, "[buildAccountRecord] Could not find a RecipientRecord for ourselves! ID: " + self.getId());
|
||||
} else if (!Arrays.equals(record.getStorageId(), self.getStorageServiceId())) {
|
||||
Log.w(TAG, "[buildAccountRecord] StorageId on RecipientRecord did not match self! ID: " + self.getId());
|
||||
}
|
||||
|
||||
final boolean hasReadOnboardingStory = SignalStore.storyValues().getUserHasViewedOnboardingStory() || SignalStore.storyValues().getUserHasReadOnboardingStory();
|
||||
|
||||
SignalAccountRecord.Builder account = new SignalAccountRecord.Builder(self.getStorageServiceId(), record != null ? record.getSyncExtras().getStorageProto() : null)
|
||||
SignalAccountRecord.Builder account = new SignalAccountRecord.Builder(record != null ? record.getStorageId() : self.getStorageServiceId(), record != null ? record.getSyncExtras().getStorageProto() : null)
|
||||
.setProfileKey(self.getProfileKey())
|
||||
.setGivenName(self.getProfileName().getGivenName())
|
||||
.setFamilyName(self.getProfileName().getFamilyName())
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
<string name="yes">Да</string>
|
||||
<string name="no">Не</string>
|
||||
<string name="delete">Обриши</string>
|
||||
<string name="delete">Избриши</string>
|
||||
<string name="please_wait">Сачекајте…</string>
|
||||
<string name="save">Сачувај</string>
|
||||
<string name="note_to_self">Моја белешка</string>
|
||||
@@ -79,7 +79,7 @@
|
||||
|
||||
<!-- AttachmentKeyboard -->
|
||||
<string name="AttachmentKeyboard_gallery">Галерија</string>
|
||||
<string name="AttachmentKeyboard_file">Fajl</string>
|
||||
<string name="AttachmentKeyboard_file">Фајл</string>
|
||||
<string name="AttachmentKeyboard_contact">Контакт</string>
|
||||
<string name="AttachmentKeyboard_location">Локација</string>
|
||||
<string name="AttachmentKeyboard_Signal_needs_permission_to_show_your_photos_and_videos">Сигналу су потребне дозволе да прикаже ваше слике и видео.</string>
|
||||
@@ -1032,8 +1032,8 @@
|
||||
<string name="CustomNotificationsDialogFragment__notification_sound">Звук обавештења</string>
|
||||
<string name="CustomNotificationsDialogFragment__vibrate">Режим вибрирања</string>
|
||||
<!-- Button text for customizing notification options -->
|
||||
<string name="CustomNotificationsDialogFragment__customize">Прилагодити</string>
|
||||
<string name="CustomNotificationsDialogFragment__change_sound_and_vibration">Променити звук и вибрацију</string>
|
||||
<string name="CustomNotificationsDialogFragment__customize">Прилагоди</string>
|
||||
<string name="CustomNotificationsDialogFragment__change_sound_and_vibration">Промени звук и вибрацију</string>
|
||||
<string name="CustomNotificationsDialogFragment__call_settings">Поставке позива</string>
|
||||
<string name="CustomNotificationsDialogFragment__ringtone">Звоно</string>
|
||||
<string name="CustomNotificationsDialogFragment__default">Подразумеван</string>
|
||||
@@ -2052,7 +2052,7 @@
|
||||
<string name="ThreadRecord_view_once_photo">Једнократна фотографија</string>
|
||||
<string name="ThreadRecord_view_once_video">Једнократни видео запис</string>
|
||||
<string name="ThreadRecord_view_once_media">Једнократни медиј</string>
|
||||
<string name="ThreadRecord_this_message_was_deleted">Ова порука је обрисана.</string>
|
||||
<string name="ThreadRecord_this_message_was_deleted">Ова порука је избрисана.</string>
|
||||
<string name="ThreadRecord_you_deleted_this_message">Избрисали сте ову поруку.</string>
|
||||
<!-- Displayed in the notification when the user sends a request to activate payments -->
|
||||
<string name="ThreadRecord_you_sent_request">Послали сте захтев за активирање плаћања</string>
|
||||
@@ -2077,7 +2077,7 @@
|
||||
<string name="ThreadRecord_photo">Фотографија</string>
|
||||
<string name="ThreadRecord_gif">GIF</string>
|
||||
<string name="ThreadRecord_voice_message">Гласовна порука</string>
|
||||
<string name="ThreadRecord_file">Fajl</string>
|
||||
<string name="ThreadRecord_file">Фајл</string>
|
||||
<string name="ThreadRecord_video">Видео запис</string>
|
||||
<string name="ThreadRecord_chat_session_refreshed">Сесија ћаскања је освежена</string>
|
||||
<!-- Displayed in the notification when the user is sent a gift -->
|
||||
@@ -2581,22 +2581,22 @@
|
||||
<string name="expiration_off">Искључено</string>
|
||||
|
||||
<plurals name="expiration_seconds">
|
||||
<item quantity="one">%1$d сек.</item>
|
||||
<item quantity="other">%1$d сек.</item>
|
||||
<item quantity="one">%1$d s</item>
|
||||
<item quantity="other">%1$d s</item>
|
||||
</plurals>
|
||||
|
||||
<string name="expiration_seconds_abbreviated">%1$d s</string>
|
||||
|
||||
<plurals name="expiration_minutes">
|
||||
<item quantity="one">%1$d мин.</item>
|
||||
<item quantity="other">%1$d мин.</item>
|
||||
<item quantity="one">%1$d min</item>
|
||||
<item quantity="other">%1$d min</item>
|
||||
</plurals>
|
||||
|
||||
<string name="expiration_minutes_abbreviated">%1$d m</string>
|
||||
|
||||
<plurals name="expiration_hours">
|
||||
<item quantity="one">%1$d сат</item>
|
||||
<item quantity="other">%1$d сати</item>
|
||||
<item quantity="one">%1$d h</item>
|
||||
<item quantity="other">%1$d h</item>
|
||||
</plurals>
|
||||
|
||||
<string name="expiration_hours_abbreviated">%1$d h</string>
|
||||
@@ -2609,8 +2609,8 @@
|
||||
<string name="expiration_days_abbreviated">%1$d д</string>
|
||||
|
||||
<plurals name="expiration_weeks">
|
||||
<item quantity="one">%1$d сед.</item>
|
||||
<item quantity="other">%1$d сед.</item>
|
||||
<item quantity="one">%1$d нед.</item>
|
||||
<item quantity="other">%1$d нед.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="expiration_weeks_abbreviated">%1$d с</string>
|
||||
@@ -2689,7 +2689,7 @@
|
||||
<string name="EditAboutFragment_encrypted">Шифровано</string>
|
||||
<string name="EditAboutFragment_be_kind">Будите љубазни</string>
|
||||
<string name="EditAboutFragment_coffee_lover">Љубитељ кафе</string>
|
||||
<string name="EditAboutFragment_free_to_chat">Доступан за ћаскање</string>
|
||||
<string name="EditAboutFragment_free_to_chat">Можемо да ћаскамо</string>
|
||||
<string name="EditAboutFragment_taking_a_break">Правим паузу</string>
|
||||
<string name="EditAboutFragment_working_on_something_new">Радим на нечему новом</string>
|
||||
|
||||
@@ -2785,19 +2785,19 @@
|
||||
<string name="HelpFragment__please_be_as_descriptive_as_possible">Будите што описнији како бисте нам помогли да разумемо проблем.</string>
|
||||
<string-array name="HelpFragment__categories_5">
|
||||
<item>Изаберите опцију</item>
|
||||
<item>Nešto ne radi</item>
|
||||
<item>Zahtev za funkciju</item>
|
||||
<item>Pitanje</item>
|
||||
<item>Komentar</item>
|
||||
<item>Нешто не ради</item>
|
||||
<item>Захтев за функцију</item>
|
||||
<item>Питање</item>
|
||||
<item>Коментар</item>
|
||||
<item>Остало</item>
|
||||
<item>Plaćanja (MobileCoin)</item>
|
||||
<item>Плаћања (MobileCoin)</item>
|
||||
<item>Донације и значке</item>
|
||||
<item>Извоз SMS порука</item>
|
||||
</string-array>
|
||||
<!-- Subject of email when submitting debug logs to help debug slow notifications -->
|
||||
<string name="DebugLogsPromptDialogFragment__signal_android_support_request">Слање евиденције за отклањање грешака за Signal Android</string>
|
||||
<!-- Category to organize the support email sent -->
|
||||
<string name="DebugLogsPromptDialogFragment__slow_notifications_category">Спора обавештења</string>
|
||||
<string name="DebugLogsPromptDialogFragment__slow_notifications_category">Обавештења касне</string>
|
||||
<!-- Category to organize the support email sent -->
|
||||
<string name="DebugLogsPromptDialogFragment__crash_category">Пад апликације</string>
|
||||
<!-- Action to submit logs and take user to send an e-mail -->
|
||||
@@ -2821,12 +2821,12 @@
|
||||
|
||||
<!-- arrays.xml -->
|
||||
<string name="arrays__use_default">Користи подразумевано</string>
|
||||
<string name="arrays__use_custom">Користи посебно</string>
|
||||
<string name="arrays__use_custom">Користи прилагођено</string>
|
||||
|
||||
<string name="arrays__mute_for_one_hour">Искључи обавештења 1 сат</string>
|
||||
<string name="arrays__mute_for_eight_hours">Искључи обавештења 8 сати</string>
|
||||
<string name="arrays__mute_for_one_day">Искључи обавештења 1 дан</string>
|
||||
<string name="arrays__mute_for_seven_days">Искључи обавештења 7 сати</string>
|
||||
<string name="arrays__mute_for_one_hour">Искључи обавештења на 1 сат</string>
|
||||
<string name="arrays__mute_for_eight_hours">Искључи обавештења на 8 сати</string>
|
||||
<string name="arrays__mute_for_one_day">Искључи обавештења на 1 дан</string>
|
||||
<string name="arrays__mute_for_seven_days">Искључи обавештења на 7 сати</string>
|
||||
<string name="arrays__always">Увек</string>
|
||||
|
||||
<string name="arrays__settings_default">Подразумевана поставка</string>
|
||||
@@ -2876,7 +2876,7 @@
|
||||
<string name="preferences__auto_lock_signal_after_a_specified_time_interval_of_inactivity">Аутоматски закључај Signal након одређеног интервала неактивности</string>
|
||||
<string name="preferences__inactivity_timeout_passphrase">Интервал истека лозинке</string>
|
||||
<string name="preferences__inactivity_timeout_interval">Интервал неактивности</string>
|
||||
<string name="preferences__notifications">Обавештавања</string>
|
||||
<string name="preferences__notifications">Обавештења</string>
|
||||
<string name="preferences__led_color">Боја ЛЕД светла</string>
|
||||
<string name="preferences__led_color_unknown">Непозната</string>
|
||||
<string name="preferences__pref_led_blink_title">Трептање ЛЕД светла</string>
|
||||
@@ -3997,7 +3997,7 @@
|
||||
<string name="ChatWallpaperFragment__reset_chat_colors">Ресетовати боје ћаскања</string>
|
||||
<string name="ChatWallpaperFragment__reset_chat_color">Ресетовати боје ћаскања</string>
|
||||
<string name="ChatWallpaperFragment__reset_chat_color_question">Ресетовати боје ћаскања?</string>
|
||||
<string name="ChatWallpaperFragment__set_wallpaper">Поставити позадину</string>
|
||||
<string name="ChatWallpaperFragment__set_wallpaper">Постави позадину</string>
|
||||
<string name="ChatWallpaperFragment__dark_mode_dims_wallpaper">Тамни режим затамњује позадину</string>
|
||||
<string name="ChatWallpaperFragment__contact_name">Име контакта</string>
|
||||
<string name="ChatWallpaperFragment__reset">Ресетуј</string>
|
||||
@@ -4454,18 +4454,18 @@
|
||||
<string name="KeyboardPagerFragment_search_giphy">Тражити GIPHY</string>
|
||||
|
||||
<!-- StickerSearchDialogFragment -->
|
||||
<string name="StickerSearchDialogFragment_search_stickers">Тражити налепнице</string>
|
||||
<string name="StickerSearchDialogFragment_search_stickers">Претрага налепница</string>
|
||||
<string name="StickerSearchDialogFragment_no_results_found">Нема резултата</string>
|
||||
<string name="EmojiSearchFragment__no_results_found">Нема резултата</string>
|
||||
<string name="NotificationsSettingsFragment__unknown_ringtone">Непозната мелодија звона</string>
|
||||
|
||||
<!-- ConversationSettingsFragment -->
|
||||
<!-- Dialog title displayed when non-admin tries to add a story to an audience group -->
|
||||
<string name="ConversationSettingsFragment__cant_add_to_group_story">Додавање садржаја у групну причу није успело</string>
|
||||
<string name="ConversationSettingsFragment__cant_add_to_group_story">Додавање у групну причу није успело</string>
|
||||
<!-- Dialog message displayed when non-admin tries to add a story to an audience group -->
|
||||
<string name="ConversationSettingsFragment__only_admins_of_this_group_can_add_to_its_story">Само администратори ове групе могу да додају садржаје у ову причу</string>
|
||||
<!-- Error toasted when no activity can handle the add contact intent -->
|
||||
<string name="ConversationSettingsFragment__contacts_app_not_found">Aplikacija za kontakte nije pronađena</string>
|
||||
<string name="ConversationSettingsFragment__contacts_app_not_found">Апликација за контакте није пронађена</string>
|
||||
<string name="ConversationSettingsFragment__start_video_call">Започните видео позив</string>
|
||||
<string name="ConversationSettingsFragment__start_audio_call">Започни гласовни позив</string>
|
||||
<!-- Button label with hyphenation. Translation can use soft hyphen - Unicode U+00AD -->
|
||||
@@ -4473,9 +4473,9 @@
|
||||
<!-- Button label with hyphenation. Translation can use soft hyphen - Unicode U+00AD -->
|
||||
<string name="ConversationSettingsFragment__message">Порука</string>
|
||||
<!-- Button label with hyphenation. Translation can use soft hyphen - Unicode U+00AD -->
|
||||
<string name="ConversationSettingsFragment__video">Видео запис</string>
|
||||
<string name="ConversationSettingsFragment__video">Видео</string>
|
||||
<!-- Button label with hyphenation. Translation can use soft hyphen - Unicode U+00AD -->
|
||||
<string name="ConversationSettingsFragment__audio">Звучни запис</string>
|
||||
<string name="ConversationSettingsFragment__audio">Звук</string>
|
||||
<!-- Button label with hyphenation. Translation can use soft hyphen - Unicode U+00AD -->
|
||||
<string name="ConversationSettingsFragment__call">Позови</string>
|
||||
<!-- Button label with hyphenation. Translation can use soft hyphen - Unicode U+00AD -->
|
||||
@@ -4483,7 +4483,7 @@
|
||||
<!-- Button label with hyphenation. Translation can use soft hyphen - Unicode U+00AD -->
|
||||
<string name="ConversationSettingsFragment__muted">Обавештења су искључена</string>
|
||||
<!-- Button label with hyphenation. Translation can use soft hyphen - Unicode U+00AD -->
|
||||
<string name="ConversationSettingsFragment__search">Претрага</string>
|
||||
<string name="ConversationSettingsFragment__search">Претражите</string>
|
||||
<string name="ConversationSettingsFragment__disappearing_messages">Самонестајуће поруке</string>
|
||||
<string name="ConversationSettingsFragment__sounds_and_notifications">Звук и обавештења</string>
|
||||
<!-- Removed by excludeNonTranslatables <string name="ConversationSettingsFragment__internal_details" translatable="false">Internal details</string> -->
|
||||
@@ -4588,7 +4588,7 @@
|
||||
<string name="AvatarPickerFragment__text">Текст</string>
|
||||
<string name="AvatarPickerFragment__save">Сачувај</string>
|
||||
<string name="AvatarPickerFragment__clear_avatar">Уклонити слику</string>
|
||||
<string name="AvatarPickerRepository__failed_to_save_avatar">Неуспех сачувавања аватара</string>
|
||||
<string name="AvatarPickerRepository__failed_to_save_avatar">Чување аватара није успело</string>
|
||||
|
||||
<!-- TextAvatarCreationFragment -->
|
||||
<string name="TextAvatarCreationFragment__preview">Преглед</string>
|
||||
@@ -4606,17 +4606,17 @@
|
||||
<string name="ShareInterstitialActivity__share">Поделите</string>
|
||||
|
||||
<!-- DSLSettingsToolbar -->
|
||||
<string name="DSLSettingsToolbar__navigate_up">Ићи на горе</string>
|
||||
<string name="MultiselectForwardFragment__forward_to">Напред на</string>
|
||||
<string name="DSLSettingsToolbar__navigate_up">Иди на врх</string>
|
||||
<string name="MultiselectForwardFragment__forward_to">Проследите кориснику</string>
|
||||
<!-- Displayed when sharing content via the fragment -->
|
||||
<string name="MultiselectForwardFragment__share_with">Подели са</string>
|
||||
<string name="MultiselectForwardFragment__add_a_message">Додати поруку</string>
|
||||
<string name="MultiselectForwardFragment__faster_forwards">Убрзавање прослеђивање</string>
|
||||
<string name="MultiselectForwardFragment__add_a_message">Додајте поруку</string>
|
||||
<string name="MultiselectForwardFragment__faster_forwards">Брже прослеђивање</string>
|
||||
<!-- Displayed when user selects a video that will be clipped before sharing to a story -->
|
||||
<string name="MultiselectForwardFragment__videos_will_be_trimmed">Видео снимци ће бити скраћени на клипове од 30 секунди и послати као више прича.</string>
|
||||
<!-- Displayed when user selects a video that cannot be sent as a story -->
|
||||
<string name="MultiselectForwardFragment__videos_sent_to_stories_cant">Видео снимци објављени у причама не могу бити дужи од 30 секунди.</string>
|
||||
<string name="MultiselectForwardFragment__forwarded_messages_are_now">Прослеђивање поруке је сада урађено сместа.</string>
|
||||
<string name="MultiselectForwardFragment__forwarded_messages_are_now">Прослеђене поруке се сада шаљу одмах.</string>
|
||||
<plurals name="MultiselectForwardFragment_send_d_messages">
|
||||
<item quantity="one">Пошаљи %1$d поруку</item>
|
||||
<item quantity="other">Пошаљи поруке (%1$d)</item>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
ext.service_ips='new String[]{"13.248.212.111","76.223.92.165"}'
|
||||
ext.storage_ips='new String[]{"142.250.72.115"}'
|
||||
ext.cdn_ips='new String[]{"18.238.49.106","18.238.49.6","18.238.49.66","18.238.49.90"}'
|
||||
ext.cdn_ips='new String[]{"18.161.21.122","18.161.21.4","18.161.21.66","18.161.21.70"}'
|
||||
ext.cdn2_ips='new String[]{"104.18.37.148","172.64.150.108"}'
|
||||
ext.cdn3_ips='new String[]{"104.18.37.148","172.64.150.108"}'
|
||||
ext.sfu_ips='new String[]{"35.186.192.249"}'
|
||||
|
||||
Reference in New Issue
Block a user