diff --git a/app/build.gradle b/app/build.gradle index 5944f8c9a10..88609da7af1 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -88,7 +88,6 @@ android { buildConfigField "String", "CONTENT_PROXY_HOST", "\"contentproxy.signal.org\"" buildConfigField "int", "CONTENT_PROXY_PORT", "443" buildConfigField "String", "USER_AGENT", "\"OWA\"" - buildConfigField "String[]", "LANGUAGES", "new String[]{\"" + autoResConfig().collect { s -> s.replace('-r', '_') }.join('", "') + '"}' buildConfigField "int", "CANONICAL_VERSION_CODE", "$canonicalVersionCode" resourceConfigurations += [] diff --git a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java index 1391499026e..ca362fea4f4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java +++ b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java @@ -35,14 +35,12 @@ import androidx.lifecycle.ProcessLifecycleOwner; import org.conscrypt.Conscrypt; -import org.session.libsession.avatars.AvatarHelper; import org.session.libsession.database.MessageDataProvider; import org.session.libsession.messaging.MessagingModuleConfiguration; import org.session.libsession.messaging.sending_receiving.notifications.MessageNotifier; import org.session.libsession.messaging.sending_receiving.pollers.ClosedGroupPollerV2; import org.session.libsession.messaging.sending_receiving.pollers.Poller; import org.session.libsession.snode.SnodeModule; -import org.session.libsession.utilities.Address; import org.session.libsession.utilities.ConfigFactoryUpdateListener; import org.session.libsession.utilities.Device; import org.session.libsession.utilities.Environment; @@ -51,8 +49,6 @@ import org.session.libsession.utilities.TextSecurePreferences; import org.session.libsession.utilities.Util; import org.session.libsession.utilities.WindowDebouncer; -import org.session.libsession.utilities.dynamiclanguage.DynamicLanguageContextWrapper; -import org.session.libsession.utilities.dynamiclanguage.LocaleParser; import org.session.libsignal.utilities.HTTP; import org.session.libsignal.utilities.JsonUtil; import org.session.libsignal.utilities.Log; @@ -91,17 +87,14 @@ import org.thoughtcrime.securesms.sskenvironment.TypingStatusRepository; import org.thoughtcrime.securesms.util.Broadcaster; import org.thoughtcrime.securesms.util.VersionDataFetcher; -import org.thoughtcrime.securesms.util.dynamiclanguage.LocaleParseHelper; import org.thoughtcrime.securesms.webrtc.CallMessageProcessor; import org.webrtc.PeerConnectionFactory; import org.webrtc.PeerConnectionFactory.InitializationOptions; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.security.Security; import java.util.Arrays; -import java.util.Date; import java.util.List; import java.util.Timer; import java.util.concurrent.Executors; @@ -110,7 +103,6 @@ import dagger.hilt.EntryPoints; import dagger.hilt.android.HiltAndroidApp; -import kotlin.Unit; import network.loki.messenger.BuildConfig; import network.loki.messenger.R; import network.loki.messenger.libsession_util.ConfigBase; @@ -320,10 +312,6 @@ public void onTerminate() { super.onTerminate(); } - public void initializeLocaleParser() { - LocaleParser.Companion.configure(new LocaleParseHelper()); - } - public ExpiringMessageManager getExpiringMessageManager() { return expiringMessageManager; } @@ -424,12 +412,6 @@ private void initializeBlobProvider() { }); } - @Override - protected void attachBaseContext(Context base) { - initializeLocaleParser(); - super.attachBaseContext(DynamicLanguageContextWrapper.updateContext(base, TextSecurePreferences.getLanguage(base))); - } - private static class ProviderInitializationException extends RuntimeException { } private void setUpPollingIfNeeded() { String userPublicKey = TextSecurePreferences.getLocalNumber(this); diff --git a/app/src/main/java/org/thoughtcrime/securesms/BaseActionBarActivity.java b/app/src/main/java/org/thoughtcrime/securesms/BaseActionBarActivity.java index a99fe83430a..c3321504ea8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/BaseActionBarActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/BaseActionBarActivity.java @@ -17,8 +17,6 @@ import androidx.appcompat.app.AppCompatActivity; import org.session.libsession.utilities.TextSecurePreferences; -import org.session.libsession.utilities.dynamiclanguage.DynamicLanguageActivityHelper; -import org.session.libsession.utilities.dynamiclanguage.DynamicLanguageContextWrapper; import org.thoughtcrime.securesms.conversation.v2.WindowUtil; import org.thoughtcrime.securesms.util.ActivityUtilitiesKt; import org.thoughtcrime.securesms.util.ThemeState; @@ -97,7 +95,6 @@ protected void onCreate(Bundle savedInstanceState) { protected void onResume() { super.onResume(); initializeScreenshotSecurity(true); - DynamicLanguageActivityHelper.recreateIfNotInCorrectLanguage(this, TextSecurePreferences.getLanguage(this)); String name = getResources().getString(R.string.app_name); Bitmap icon = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_foreground); int color = getResources().getColor(R.color.app_icon_background); @@ -137,9 +134,4 @@ private void initializeScreenshotSecurity(boolean isResume) { } } } - - @Override - protected void attachBaseContext(Context newBase) { - super.attachBaseContext(DynamicLanguageContextWrapper.updateContext(newBase, TextSecurePreferences.getLanguage(newBase))); - } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/BaseActivity.java b/app/src/main/java/org/thoughtcrime/securesms/BaseActivity.java index d44978b05b3..8722c0e0921 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/BaseActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/BaseActivity.java @@ -1,31 +1,20 @@ package org.thoughtcrime.securesms; import android.app.ActivityManager; -import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import androidx.fragment.app.FragmentActivity; -import org.session.libsession.utilities.TextSecurePreferences; -import org.session.libsession.utilities.dynamiclanguage.DynamicLanguageActivityHelper; -import org.session.libsession.utilities.dynamiclanguage.DynamicLanguageContextWrapper; - import network.loki.messenger.R; public abstract class BaseActivity extends FragmentActivity { @Override protected void onResume() { super.onResume(); - DynamicLanguageActivityHelper.recreateIfNotInCorrectLanguage(this, TextSecurePreferences.getLanguage(this)); String name = getResources().getString(R.string.app_name); Bitmap icon = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_foreground); int color = getResources().getColor(R.color.app_icon_background); setTaskDescription(new ActivityManager.TaskDescription(name, icon, color)); } - - @Override - protected void attachBaseContext(Context newBase) { - super.attachBaseContext(DynamicLanguageContextWrapper.updateContext(newBase, TextSecurePreferences.getLanguage(newBase))); - } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/DeleteMediaDialog.kt b/app/src/main/java/org/thoughtcrime/securesms/DeleteMediaDialog.kt index 77b77f863e1..3d38857b504 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/DeleteMediaDialog.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/DeleteMediaDialog.kt @@ -10,7 +10,7 @@ class DeleteMediaDialog { iconAttribute(R.attr.dialog_alert_icon) title(context.resources.getQuantityString(R.plurals.deleteMessage, recordCount, recordCount)) text(context.resources.getString(R.string.deleteMessageDescriptionEveryone)) - button(R.string.delete) { doDelete.run() } + dangerButton(R.string.delete) { doDelete.run() } cancelButton() } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/MissingMicrophonePermissionDialog.kt b/app/src/main/java/org/thoughtcrime/securesms/MissingMicrophonePermissionDialog.kt deleted file mode 100644 index eb7280f6285..00000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/MissingMicrophonePermissionDialog.kt +++ /dev/null @@ -1,21 +0,0 @@ -package org.thoughtcrime.securesms - -import android.content.Context -import android.content.Intent -import android.net.Uri -import com.squareup.phrase.Phrase -import network.loki.messenger.R -import org.session.libsession.utilities.StringSubstitutionConstants.APP_NAME_KEY -import org.thoughtcrime.securesms.permissions.SettingsDialog - -class MissingMicrophonePermissionDialog { - companion object { - @JvmStatic - fun show(context: Context) = SettingsDialog.show( - context, - Phrase.from(context, R.string.permissionsMicrophoneAccessRequired) - .put(APP_NAME_KEY, context.getString(R.string.app_name)) - .format().toString() - ) - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActionBarView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActionBarView.kt index ff7f781ebf8..2a88aac463e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActionBarView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActionBarView.kt @@ -11,26 +11,21 @@ import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback import com.google.android.material.tabs.TabLayoutMediator -import com.squareup.phrase.Phrase import dagger.hilt.android.AndroidEntryPoint -import javax.inject.Inject -import kotlin.time.Duration.Companion.milliseconds import network.loki.messenger.R import network.loki.messenger.databinding.ViewConversationActionBarBinding import network.loki.messenger.databinding.ViewConversationSettingBinding import network.loki.messenger.libsession_util.util.ExpiryMode.AfterRead -import org.session.libsession.LocalisedTimeUtil import org.session.libsession.messaging.messages.ExpirationConfiguration import org.session.libsession.messaging.open_groups.OpenGroup import org.session.libsession.utilities.ExpirationUtil -import org.session.libsession.utilities.StringSubstitutionConstants.DISAPPEARING_MESSAGES_TYPE_KEY import org.session.libsession.utilities.StringSubstitutionConstants.TIME_KEY -import org.session.libsession.utilities.StringSubstitutionConstants.TIME_LARGE_KEY import org.session.libsession.utilities.modifyLayoutParams import org.session.libsession.utilities.recipients.Recipient import org.thoughtcrime.securesms.database.GroupDatabase import org.thoughtcrime.securesms.database.LokiAPIDatabase import org.thoughtcrime.securesms.ui.getSubbedString +import javax.inject.Inject @AndroidEntryPoint class ConversationActionBarView @JvmOverloads constructor( @@ -125,7 +120,7 @@ class ConversationActionBarView @JvmOverloads constructor( settings += ConversationSetting( recipient.mutedUntil.takeUnless { it == Long.MAX_VALUE } ?.let { - context.getString(R.string.notificationsHeaderMute) + context.getString(R.string.notificationsMuted) } ?: context.getString(R.string.notificationsMuted), ConversationSettingType.NOTIFICATION, diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index b7933b7bbb2..d21574ec964 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -2084,7 +2084,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe showSessionDialog { title(resources.getQuantityString(R.plurals.deleteMessage, messages.count(), messages.count())) text(resources.getString(R.string.deleteMessageDescriptionEveryone)) - button(R.string.delete) { messages.forEach(viewModel::deleteForEveryone); endActionMode() } + dangerButton(R.string.delete) { messages.forEach(viewModel::deleteForEveryone); endActionMode() } cancelButton { endActionMode() } } // Otherwise if this is a 1-on-1 conversation we may decided to delete just for ourselves or delete for everyone diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt index 8b468c3606d..880dacb0708 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt @@ -1,10 +1,7 @@ package org.thoughtcrime.securesms.conversation.v2 -import android.Manifest import android.content.Context -import android.content.Intent import android.database.Cursor -import android.net.Uri import android.util.SparseArray import android.util.SparseBooleanArray import android.view.MotionEvent @@ -14,33 +11,22 @@ import androidx.core.util.getOrDefault import androidx.core.util.set import androidx.lifecycle.LifecycleCoroutineScope import androidx.recyclerview.widget.RecyclerView.ViewHolder -import java.util.concurrent.atomic.AtomicLong -import kotlin.math.min +import com.bumptech.glide.RequestManager import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.isActive import kotlinx.coroutines.launch -import network.loki.messenger.R import org.session.libsession.messaging.contacts.Contact import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment -import org.session.libsession.utilities.StringSubstitutionConstants.NAME_KEY import org.thoughtcrime.securesms.conversation.v2.messages.ControlMessageView import org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageView import org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageViewDelegate import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter import org.thoughtcrime.securesms.database.model.MessageRecord import org.thoughtcrime.securesms.dependencies.DatabaseComponent -import com.bumptech.glide.RequestManager -import com.squareup.phrase.Phrase -import org.session.libsession.utilities.StringSubstitutionConstants.APP_NAME_KEY -import org.session.libsession.utilities.TextSecurePreferences -import org.thoughtcrime.securesms.MissingMicrophonePermissionDialog -import org.thoughtcrime.securesms.permissions.Permissions -import org.thoughtcrime.securesms.preferences.PrivacySettingsActivity -import org.thoughtcrime.securesms.showSessionDialog -import org.thoughtcrime.securesms.ui.getSubbedCharSequence -import org.thoughtcrime.securesms.ui.getSubbedString +import java.util.concurrent.atomic.AtomicLong +import kotlin.math.min class ConversationAdapter( context: Context, diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt index d6b6b25f907..0997db18717 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt @@ -5,7 +5,6 @@ import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.graphics.BitmapFactory -import android.net.Uri import android.os.AsyncTask import android.view.Menu import android.view.MenuInflater @@ -19,7 +18,6 @@ import androidx.core.content.pm.ShortcutInfoCompat import androidx.core.content.pm.ShortcutManagerCompat import androidx.core.graphics.drawable.IconCompat import com.squareup.phrase.Phrase -import java.io.IOException import network.loki.messenger.R import org.session.libsession.messaging.sending_receiving.MessageSender import org.session.libsession.messaging.sending_receiving.leave @@ -31,8 +29,6 @@ import org.session.libsession.utilities.recipients.Recipient import org.session.libsignal.utilities.Log import org.session.libsignal.utilities.guava.Optional import org.session.libsignal.utilities.toHexString -import org.thoughtcrime.securesms.MissingMicrophonePermissionDialog -import org.thoughtcrime.securesms.media.MediaOverviewActivity import org.thoughtcrime.securesms.ShortcutLauncherActivity import org.thoughtcrime.securesms.calls.WebRtcCallActivity import org.thoughtcrime.securesms.contacts.SelectContactsActivity @@ -41,12 +37,16 @@ import org.thoughtcrime.securesms.conversation.v2.utilities.NotificationUtils import org.thoughtcrime.securesms.dependencies.DatabaseComponent import org.thoughtcrime.securesms.groups.EditClosedGroupActivity import org.thoughtcrime.securesms.groups.EditClosedGroupActivity.Companion.groupIDKey +import org.thoughtcrime.securesms.media.MediaOverviewActivity import org.thoughtcrime.securesms.permissions.Permissions import org.thoughtcrime.securesms.preferences.PrivacySettingsActivity import org.thoughtcrime.securesms.service.WebRtcCallService import org.thoughtcrime.securesms.showMuteDialog import org.thoughtcrime.securesms.showSessionDialog +import org.thoughtcrime.securesms.ui.findActivity +import org.thoughtcrime.securesms.ui.getSubbedString import org.thoughtcrime.securesms.util.BitmapUtil +import java.io.IOException object ConversationMenuHelper { @@ -183,7 +183,15 @@ object ConversationMenuHelper { // or if the user has not granted audio/microphone permissions else if (!Permissions.hasAll(context, Manifest.permission.RECORD_AUDIO)) { Log.d("Loki", "Attempted to make a call without audio permissions") - MissingMicrophonePermissionDialog.show(context) + + Permissions.with(context.findActivity()) + .request(Manifest.permission.RECORD_AUDIO) + .withPermanentDenialDialog( + context.getSubbedString(R.string.permissionsMicrophoneAccessRequired, + APP_NAME_KEY to context.getString(R.string.app_name)) + ) + .execute() + return } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt index 80092587b30..ceb68eaad31 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt @@ -18,10 +18,10 @@ import network.loki.messenger.databinding.ViewControlMessageBinding import network.loki.messenger.libsession_util.util.ExpiryMode import org.session.libsession.messaging.MessagingModuleConfiguration import org.session.libsession.messaging.messages.ExpirationConfiguration +import org.session.libsession.utilities.StringSubstitutionConstants.APP_NAME_KEY import org.session.libsession.utilities.StringSubstitutionConstants.NAME_KEY import org.session.libsession.utilities.TextSecurePreferences import org.session.libsession.utilities.getColorFromAttr -import org.thoughtcrime.securesms.MissingMicrophonePermissionDialog import org.thoughtcrime.securesms.conversation.disappearingmessages.DisappearingMessages import org.thoughtcrime.securesms.conversation.disappearingmessages.expiryMode import org.thoughtcrime.securesms.database.model.MessageRecord @@ -29,6 +29,7 @@ import org.thoughtcrime.securesms.dependencies.DatabaseComponent import org.thoughtcrime.securesms.permissions.Permissions import org.thoughtcrime.securesms.preferences.PrivacySettingsActivity import org.thoughtcrime.securesms.showSessionDialog +import org.thoughtcrime.securesms.ui.findActivity import org.thoughtcrime.securesms.ui.getSubbedCharSequence import org.thoughtcrime.securesms.ui.getSubbedString import javax.inject.Inject @@ -138,7 +139,13 @@ class ControlMessageView : LinearLayout { !Permissions.hasAll(context, Manifest.permission.RECORD_AUDIO) -> { showInfo() setOnClickListener { - MissingMicrophonePermissionDialog.show(context) + Permissions.with(context.findActivity()) + .request(Manifest.permission.RECORD_AUDIO) + .withPermanentDenialDialog( + context.getSubbedString(R.string.permissionsMicrophoneAccessRequired, + APP_NAME_KEY to context.getString(R.string.app_name)) + ) + .execute() } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/AttachmentManager.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/AttachmentManager.java index d042a301968..11a39dc1aaa 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/AttachmentManager.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/AttachmentManager.java @@ -254,7 +254,7 @@ public static void selectDocument(Activity activity, int requestCode) { .request(Manifest.permission.READ_MEDIA_IMAGES) .request(Manifest.permission.READ_MEDIA_AUDIO) .withRationaleDialog( - Phrase.from(c, R.string.permissionsStorageSend) + Phrase.from(c, R.string.permissionsMusicAudio) .put(APP_NAME_KEY, c.getString(R.string.app_name)).format().toString() ) .withPermanentDenialDialog( diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/loaders/BucketedThreadMediaLoader.java b/app/src/main/java/org/thoughtcrime/securesms/database/loaders/BucketedThreadMediaLoader.java deleted file mode 100644 index 40b8c36dd2c..00000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/database/loaders/BucketedThreadMediaLoader.java +++ /dev/null @@ -1,236 +0,0 @@ -package org.thoughtcrime.securesms.database.loaders; - - -import android.content.Context; -import android.database.ContentObserver; -import android.database.Cursor; - -import androidx.annotation.NonNull; -import androidx.loader.content.AsyncTaskLoader; - -import com.annimon.stream.Stream; - -import org.session.libsession.utilities.Address; -import org.session.libsession.utilities.recipients.Recipient; -import org.thoughtcrime.securesms.database.MediaDatabase; -import org.thoughtcrime.securesms.dependencies.DatabaseComponent; -import org.thoughtcrime.securesms.util.DateUtils; -import org.thoughtcrime.securesms.util.RelativeDay; - -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -import network.loki.messenger.R; - -public class BucketedThreadMediaLoader extends AsyncTaskLoader { - - @SuppressWarnings("unused") - private static final String TAG = BucketedThreadMediaLoader.class.getSimpleName(); - - private final Address address; - private final ContentObserver observer; - - public BucketedThreadMediaLoader(@NonNull Context context, @NonNull Address address) { - super(context); - this.address = address; - this.observer = new ForceLoadContentObserver(); - - onContentChanged(); - } - - @Override - protected void onStartLoading() { - if (takeContentChanged()) { - forceLoad(); - } - } - - @Override - protected void onStopLoading() { - cancelLoad(); - } - - @Override - protected void onAbandon() { - DatabaseComponent.get(getContext()).mediaDatabase().unsubscribeToMediaChanges(observer); - } - - @Override - public BucketedThreadMedia loadInBackground() { - BucketedThreadMedia result = new BucketedThreadMedia(getContext()); - long threadId = DatabaseComponent.get(getContext()).threadDatabase().getOrCreateThreadIdFor(Recipient.from(getContext(), address, true)); - - MediaDatabase mediaDatabase = DatabaseComponent.get(getContext()).mediaDatabase(); - - mediaDatabase.subscribeToMediaChanges(observer); - try (Cursor cursor = mediaDatabase.getGalleryMediaForThread(threadId)) { - while (cursor != null && cursor.moveToNext()) { - result.add(MediaDatabase.MediaRecord.from(getContext(), cursor)); - } - } - - return result; - } - - public static class BucketedThreadMedia { - - private final TimeBucket TODAY; - private final TimeBucket YESTERDAY; - private final TimeBucket THIS_WEEK; - private final TimeBucket THIS_MONTH; - private final MonthBuckets OLDER; - - private final TimeBucket[] TIME_SECTIONS; - - public BucketedThreadMedia(@NonNull Context context) { - String localisedTodayString = DateUtils.INSTANCE.getLocalisedRelativeDayString(RelativeDay.TODAY); - String localisedYesterdayString = DateUtils.INSTANCE.getLocalisedRelativeDayString(RelativeDay.YESTERDAY); - - this.TODAY = new TimeBucket(localisedTodayString, TimeBucket.addToCalendar(Calendar.DAY_OF_YEAR, -1), TimeBucket.addToCalendar(Calendar.DAY_OF_YEAR, 1000)); - this.YESTERDAY = new TimeBucket(localisedYesterdayString, TimeBucket.addToCalendar(Calendar.DAY_OF_YEAR, -2), TimeBucket.addToCalendar(Calendar.DAY_OF_YEAR, -1)); - this.THIS_WEEK = new TimeBucket(context.getString(R.string.attachmentsThisWeek), TimeBucket.addToCalendar(Calendar.DAY_OF_YEAR, -7), TimeBucket.addToCalendar(Calendar.DAY_OF_YEAR, -2)); - this.THIS_MONTH = new TimeBucket(context.getString(R.string.attachmentsThisMonth), TimeBucket.addToCalendar(Calendar.DAY_OF_YEAR, -30), TimeBucket.addToCalendar(Calendar.DAY_OF_YEAR, -7)); - this.TIME_SECTIONS = new TimeBucket[] { TODAY, YESTERDAY, THIS_WEEK, THIS_MONTH }; - this.OLDER = new MonthBuckets(); - } - - public void add(MediaDatabase.MediaRecord mediaRecord) { - for (TimeBucket timeSection : TIME_SECTIONS) { - if (timeSection.inRange(mediaRecord.getDate())) { - timeSection.add(mediaRecord); - return; - } - } - - OLDER.add(mediaRecord); - } - - public int getSectionCount() { - return (int)Stream.of(TIME_SECTIONS) - .filter(timeBucket -> !timeBucket.isEmpty()) - .count() + - OLDER.getSectionCount(); - } - - public int getSectionItemCount(int section) { - List activeTimeBuckets = Stream.of(TIME_SECTIONS).filter(timeBucket -> !timeBucket.isEmpty()).toList(); - - if (section < activeTimeBuckets.size()) return activeTimeBuckets.get(section).getItemCount(); - else return OLDER.getSectionItemCount(section - activeTimeBuckets.size()); - } - - public MediaDatabase.MediaRecord get(int section, int item) { - List activeTimeBuckets = Stream.of(TIME_SECTIONS).filter(timeBucket -> !timeBucket.isEmpty()).toList(); - - if (section < activeTimeBuckets.size()) return activeTimeBuckets.get(section).getItem(item); - else return OLDER.getItem(section - activeTimeBuckets.size(), item); - } - - public String getName(int section, Locale locale) { - List activeTimeBuckets = Stream.of(TIME_SECTIONS).filter(timeBucket -> !timeBucket.isEmpty()).toList(); - - if (section < activeTimeBuckets.size()) return activeTimeBuckets.get(section).getName(); - else return OLDER.getName(section - activeTimeBuckets.size(), locale); - } - - private static class TimeBucket { - - private final List records = new LinkedList<>(); - - private final long startTime; - private final long endtime; - private final String name; - - TimeBucket(String name, long startTime, long endtime) { - this.name = name; - this.startTime = startTime; - this.endtime = endtime; - } - - void add(MediaDatabase.MediaRecord record) { - this.records.add(record); - } - - boolean inRange(long timestamp) { - return timestamp > startTime && timestamp <= endtime; - } - - boolean isEmpty() { - return records.isEmpty(); - } - - int getItemCount() { - return records.size(); - } - - MediaDatabase.MediaRecord getItem(int position) { - return records.get(position); - } - - String getName() { - return name; - } - - static long addToCalendar(int field, int amount) { - Calendar calendar = Calendar.getInstance(); - calendar.add(field, amount); - return calendar.getTimeInMillis(); - } - } - - private static class MonthBuckets { - - private final Map> months = new HashMap<>(); - - void add(MediaDatabase.MediaRecord record) { - Calendar calendar = Calendar.getInstance(); - calendar.setTimeInMillis(record.getDate()); - - int year = calendar.get(Calendar.YEAR) - 1900; - int month = calendar.get(Calendar.MONTH); - Date date = new Date(year, month, 1); - - if (months.containsKey(date)) { - months.get(date).add(record); - } else { - List list = new LinkedList<>(); - list.add(record); - months.put(date, list); - } - } - - int getSectionCount() { - return months.size(); - } - - int getSectionItemCount(int section) { - return months.get(getSection(section)).size(); - } - - MediaDatabase.MediaRecord getItem(int section, int position) { - return months.get(getSection(section)).get(position); - } - - Date getSection(int section) { - ArrayList keys = new ArrayList<>(months.keySet()); - Collections.sort(keys, Collections.reverseOrder()); - - return keys.get(section); - } - - String getName(int section, Locale locale) { - Date sectionDate = getSection(section); - - return new SimpleDateFormat("MMMM, yyyy", locale).format(sectionDate); - } - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/media/FixedTimeBuckets.kt b/app/src/main/java/org/thoughtcrime/securesms/media/FixedTimeBuckets.kt index 85b00f66bc2..ecfab34aab4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/media/FixedTimeBuckets.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/media/FixedTimeBuckets.kt @@ -1,7 +1,10 @@ package org.thoughtcrime.securesms.media +import android.content.Context import androidx.annotation.StringRes import network.loki.messenger.R +import org.thoughtcrime.securesms.util.DateUtils +import org.thoughtcrime.securesms.util.RelativeDay import java.time.ZonedDateTime import java.time.temporal.WeekFields import java.util.Locale @@ -29,16 +32,15 @@ class FixedTimeBuckets( ) /** - * Test the given time against the buckets and return the appropriate string resource the time + * Test the given time against the buckets and return the appropriate string the time * bucket. If no bucket is appropriate, it will return null. */ - @StringRes - fun getBucketText(time: ZonedDateTime): Int? { + fun getBucketText(context: Context, time: ZonedDateTime): String? { return when { - time >= startOfToday -> R.string.BucketedThreadMedia_Today - time >= startOfYesterday -> R.string.BucketedThreadMedia_Yesterday - time >= startOfThisWeek -> R.string.attachmentsThisWeek - time >= startOfThisMonth -> R.string.attachmentsThisMonth + time >= startOfToday -> DateUtils.getLocalisedRelativeDayString(RelativeDay.TODAY) + time >= startOfYesterday -> DateUtils.getLocalisedRelativeDayString(RelativeDay.YESTERDAY) + time >= startOfThisWeek -> context.getString(R.string.attachmentsThisWeek) + time >= startOfThisMonth -> context.getString(R.string.attachmentsThisMonth) else -> null } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/media/MediaOverviewScreen.kt b/app/src/main/java/org/thoughtcrime/securesms/media/MediaOverviewScreen.kt index 79697252bdf..34ccc1c1c6a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/media/MediaOverviewScreen.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/media/MediaOverviewScreen.kt @@ -247,12 +247,7 @@ private fun DeleteConfirmationDialog( AlertDialog( onDismissRequest = onDismissRequest, title = context.resources.getQuantityString( - R.plurals.ConversationFragment_delete_selected_messages, numSelected - ), - text = context.resources.getQuantityString( - R.plurals.ConversationFragment_this_will_permanently_delete_all_n_selected_messages, - numSelected, - numSelected, + R.plurals.deleteMessage, numSelected ), buttons = listOf( DialogButtonModel(GetString(R.string.delete), color = LocalColors.current.danger, onClick = onAccepted), diff --git a/app/src/main/java/org/thoughtcrime/securesms/media/MediaOverviewViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/media/MediaOverviewViewModel.kt index 25ea26b1971..9eb97a06601 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/media/MediaOverviewViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/media/MediaOverviewViewModel.kt @@ -130,7 +130,7 @@ class MediaOverviewViewModel( .groupBy { record -> val time = ZonedDateTime.ofInstant(Instant.ofEpochMilli(record.date), ZoneId.of("UTC")) - timeBuckets.getBucketText(time)?.let(application::getString) + timeBuckets.getBucketText(application, time) ?: time.toLocalDate().withDayOfMonth(1) } .map { (bucket, records) -> diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/DateUtils.kt b/app/src/main/java/org/thoughtcrime/securesms/util/DateUtils.kt index 10d2fceb798..36c64f7fbd0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/DateUtils.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/util/DateUtils.kt @@ -52,9 +52,6 @@ object DateUtils : android.text.format.DateUtils() { return isToday(`when` + TimeUnit.DAYS.toMillis(1)) } - private fun convertDelta(millis: Long, to: TimeUnit): Int { - return to.convert(System.currentTimeMillis() - millis, TimeUnit.MILLISECONDS).toInt() - } // Method to get the String for a relative day in a locale-aware fashion public fun getLocalisedRelativeDayString(relativeDay: RelativeDay): String { @@ -76,10 +73,12 @@ object DateUtils : android.text.format.DateUtils() { set(Calendar.MILLISECOND, 0) } - return getRelativeTimeSpanString(comparisonTime.timeInMillis, + val temp = getRelativeTimeSpanString( + comparisonTime.timeInMillis, now.timeInMillis, DAY_IN_MILLIS, FORMAT_SHOW_DATE).toString() + return temp } fun getFormattedDateTime(time: Long, template: String, locale: Locale): String { @@ -142,30 +141,4 @@ object DateUtils : android.text.format.DateUtils() { private fun getLocalizedPattern(template: String, locale: Locale): String { return DateFormat.getBestDateTimePattern(locale, template) } - - /** - * e.g. 2020-09-04T19:17:51Z - * https://www.iso.org/iso-8601-date-and-time-format.html - * - * @return The timestamp if able to be parsed, otherwise -1. - */ - @SuppressLint("ObsoleteSdkInt") - @JvmStatic - public fun parseIso8601(date: String?): Long { - - if (date.isNullOrEmpty()) { return -1 } - - val format = if (Build.VERSION.SDK_INT >= 24) { - SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX", Locale.getDefault()) - } else { - SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.getDefault()) - } - - try { - return format.parse(date).time - } catch (e: ParseException) { - Log.w(TAG, "Failed to parse date.", e) - return -1 - } - } } \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/dynamiclanguage/LocaleParseHelper.kt b/app/src/main/java/org/thoughtcrime/securesms/util/dynamiclanguage/LocaleParseHelper.kt deleted file mode 100644 index 7e0b963aec5..00000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/util/dynamiclanguage/LocaleParseHelper.kt +++ /dev/null @@ -1,26 +0,0 @@ -package org.thoughtcrime.securesms.util.dynamiclanguage - -import android.content.res.Resources -import androidx.core.os.ConfigurationCompat -import network.loki.messenger.BuildConfig -import org.session.libsession.utilities.dynamiclanguage.LocaleParserHelperProtocol -import java.util.* - -class LocaleParseHelper: LocaleParserHelperProtocol { - - override fun appSupportsTheExactLocale(locale: Locale?): Boolean { - return if (locale == null) { - false - } else Arrays.asList(*BuildConfig.LANGUAGES).contains(locale.toString()) - } - - override fun findBestSystemLocale(): Locale { - val config = Resources.getSystem().configuration - - val firstMatch = ConfigurationCompat.getLocales(config) - .getFirstMatch(BuildConfig.LANGUAGES) - - return firstMatch ?: Locale.ENGLISH - - } -} \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4071b00f333..78554f9ebbc 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,24 +1,5 @@ - - - Today - Yesterday - - - - Delete selected message? - Delete selected messages? - - - This will permanently delete the selected message. - This will permanently delete all %1$d selected messages. - \ No newline at end of file diff --git a/app/src/test/java/org/thoughtcrime/securesms/l10n/LanguageResourcesTest.java b/app/src/test/java/org/thoughtcrime/securesms/l10n/LanguageResourcesTest.java deleted file mode 100644 index 9a8cdf92d97..00000000000 --- a/app/src/test/java/org/thoughtcrime/securesms/l10n/LanguageResourcesTest.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.thoughtcrime.securesms.l10n; - -import android.app.Application; -import android.content.res.Resources; - -import org.junit.Ignore; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; -import network.loki.messenger.BuildConfig; -import network.loki.messenger.R; - -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import androidx.test.core.app.ApplicationProvider; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -//FIXME AC: This test group is outdated. -@Ignore("This test group uses outdated instrumentation and needs a migration to modern tools.") -@RunWith(RobolectricTestRunner.class) -@Config(manifest = Config.NONE, application = Application.class) -public final class LanguageResourcesTest { - - @Test - public void language_entries_match_language_values_in_length() { - Resources resources = ApplicationProvider.getApplicationContext().getResources(); - String[] values = resources.getStringArray(R.array.language_values); - String[] entries = resources.getStringArray(R.array.language_entries); - assertEquals(values.length, entries.length); - } - - @Test - public void language_options_matches_available_resources() { - Set languageEntries = languageEntries(); - Set foundResources = buildConfigResources(); - if (!languageEntries.equals(foundResources)) { - assertSubset(foundResources, languageEntries, "Missing language_entries for resources"); - assertSubset(languageEntries, foundResources, "Missing resources for language_entries"); - fail("Unexpected"); - } - } - - private static Set languageEntries() { - Resources resources = ApplicationProvider.getApplicationContext().getResources(); - String[] values = resources.getStringArray(R.array.language_values); - - List tail = Arrays.asList(values).subList(1, values.length); - Set set = new HashSet<>(tail); - - assertEquals("First is not the default", "zz", values[0]); - assertEquals("List contains duplicates", tail.size(), set.size()); - return set; - } - - private static Set buildConfigResources() { - Set set = new HashSet<>(); - Collections.addAll(set, BuildConfig.LANGUAGES); - assertEquals("List contains duplicates", BuildConfig.LANGUAGES.length, set.size()); - return set; - } - - /** - * Fails if "a" is not a subset of "b", lists the additional values found in "a" - */ - private static void assertSubset(Set a, Set b, String message) { - Set delta = subtract(a, b); - if (!delta.isEmpty()) { - fail(message + ": " + String.join(", ", delta)); - } - } - - /** - * Set a - Set b - */ - private static Set subtract(Set a, Set b) { - Set set = new HashSet<>(a); - set.removeAll(b); - return set; - } -} diff --git a/app/src/test/java/org/thoughtcrime/securesms/util/dynamiclanguage/LanguageStringTest.java b/app/src/test/java/org/thoughtcrime/securesms/util/dynamiclanguage/LanguageStringTest.java deleted file mode 100644 index bda68cbae35..00000000000 --- a/app/src/test/java/org/thoughtcrime/securesms/util/dynamiclanguage/LanguageStringTest.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.thoughtcrime.securesms.util.dynamiclanguage; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.session.libsession.utilities.dynamiclanguage.LanguageString; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Locale; - -import static org.junit.Assert.assertEquals; - -@RunWith(Parameterized.class) -public final class LanguageStringTest { - - private final Locale expected; - private final String input; - - @Parameterized.Parameters - public static Collection data() { - return Arrays.asList(new Object[][]{ - - /* Language */ - { new Locale("en"), "en" }, - { new Locale("de"), "de" }, - { new Locale("fr"), "FR" }, - - /* Language and region */ - { new Locale("en", "US"), "en_US" }, - { new Locale("es", "US"), "es_US" }, - { new Locale("es", "MX"), "es_MX" }, - { new Locale("es", "MX"), "es_mx" }, - { new Locale("de", "DE"), "de_DE" }, - - /* Not parsable input */ - { null, null }, - { null, "" }, - { null, "zz" }, - { null, "zz_ZZ" }, - { null, "fr_ZZ" }, - { null, "zz_FR" }, - - }); - } - - public LanguageStringTest(Locale expected, String input) { - this.expected = expected; - this.input = input; - } - - @Test - public void parse() { - assertEquals(expected, LanguageString.parseLocale(input)); - } -} diff --git a/app/src/test/java/org/thoughtcrime/securesms/util/dynamiclanguage/LocaleParserTest.java b/app/src/test/java/org/thoughtcrime/securesms/util/dynamiclanguage/LocaleParserTest.java deleted file mode 100644 index 416b2bd7d59..00000000000 --- a/app/src/test/java/org/thoughtcrime/securesms/util/dynamiclanguage/LocaleParserTest.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.thoughtcrime.securesms.util.dynamiclanguage; - -import android.app.Application; - -import org.junit.Ignore; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; -import org.session.libsession.utilities.dynamiclanguage.LocaleParser; - -import network.loki.messenger.BuildConfig; - -import java.util.Arrays; -import java.util.List; -import java.util.Locale; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; - -//FIXME AC: This test group is outdated. -@Ignore("This test group uses outdated instrumentation and needs a migration to modern tools.") -@RunWith(RobolectricTestRunner.class) -@Config(manifest = Config.NONE, application = Application.class) -public final class LocaleParserTest { - - @Test - public void findBestMatchingLocaleForLanguage_all_build_config_languages_can_be_resolved() { - for (String lang : buildConfigLanguages()) { - Locale locale = LocaleParser.findBestMatchingLocaleForLanguage(lang); - assertEquals(lang, locale.toString()); - } - } - - @Test - @Config(qualifiers = "fr") - public void findBestMatchingLocaleForLanguage_a_non_build_config_language_defaults_to_device_value_which_is_supported_directly() { - String unsupportedLanguage = getUnsupportedLanguage(); - assertEquals(Locale.FRENCH, LocaleParser.findBestMatchingLocaleForLanguage(unsupportedLanguage)); - } - - @Test - @Config(qualifiers = "en-rCA") - public void findBestMatchingLocaleForLanguage_a_non_build_config_language_defaults_to_device_value_which_is_not_supported_directly() { - String unsupportedLanguage = getUnsupportedLanguage(); - assertEquals(Locale.CANADA, LocaleParser.findBestMatchingLocaleForLanguage(unsupportedLanguage)); - } - - private static String getUnsupportedLanguage() { - String unsupportedLanguage = "af"; - assertFalse("Language should be an unsupported one", buildConfigLanguages().contains(unsupportedLanguage)); - return unsupportedLanguage; - } - - private static List buildConfigLanguages() { - return Arrays.asList(BuildConfig.LANGUAGES); - } -} diff --git a/libsession/src/main/java/org/session/libsession/utilities/dynamiclanguage/DynamicLanguageActivityHelper.java b/libsession/src/main/java/org/session/libsession/utilities/dynamiclanguage/DynamicLanguageActivityHelper.java deleted file mode 100644 index 935b1394815..00000000000 --- a/libsession/src/main/java/org/session/libsession/utilities/dynamiclanguage/DynamicLanguageActivityHelper.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.session.libsession.utilities.dynamiclanguage; - -import android.app.Activity; - -import androidx.annotation.MainThread; -import androidx.core.os.ConfigurationCompat; - -import org.session.libsignal.utilities.Log; - -import java.util.Locale; - -public final class DynamicLanguageActivityHelper { - - private static final String TAG = DynamicLanguageActivityHelper.class.getSimpleName(); - - private static String reentryProtection; - - /** - * If the activity isn't in the specified language, it will restart the activity. - */ - @MainThread - public static void recreateIfNotInCorrectLanguage(Activity activity, String language) { - Locale currentActivityLocale = ConfigurationCompat.getLocales(activity.getResources().getConfiguration()).get(0); - Locale selectedLocale = LocaleParser.findBestMatchingLocaleForLanguage(language); - - if (currentActivityLocale.equals(selectedLocale)) { - reentryProtection = ""; - return; - } - - String reentryKey = activity.getClass().getName() + ":" + selectedLocale; - if (!reentryKey.equals(reentryProtection)) { - reentryProtection = reentryKey; - Log.d(TAG, String.format("Activity Locale %s, Selected locale %s, restarting", currentActivityLocale, selectedLocale)); - activity.recreate(); - } else { - Log.d(TAG, String.format("Skipping recreate as looks like looping, Activity Locale %s, Selected locale %s", currentActivityLocale, selectedLocale)); - } - } -} diff --git a/libsession/src/main/java/org/session/libsession/utilities/dynamiclanguage/DynamicLanguageContextWrapper.java b/libsession/src/main/java/org/session/libsession/utilities/dynamiclanguage/DynamicLanguageContextWrapper.java deleted file mode 100644 index 4c8193bb820..00000000000 --- a/libsession/src/main/java/org/session/libsession/utilities/dynamiclanguage/DynamicLanguageContextWrapper.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.session.libsession.utilities.dynamiclanguage; - -import android.content.Context; -import android.content.res.Configuration; -import android.content.res.Resources; - -import java.util.Locale; - -/** - * Updates a context with an alternative language. - */ -public final class DynamicLanguageContextWrapper { - - public static Context updateContext(Context context, String language) { - final Locale newLocale = LocaleParser.findBestMatchingLocaleForLanguage(language); - - Locale.setDefault(newLocale); - - final Resources resources = context.getResources(); - final Configuration config = resources.getConfiguration(); - final Configuration newConfig = copyWithNewLocale(config, newLocale); - - resources.updateConfiguration(newConfig, resources.getDisplayMetrics()); - - return context; - } - - private static Configuration copyWithNewLocale(Configuration config, Locale locale) { - final Configuration copy = new Configuration(config); - copy.setLocale(locale); - return copy; - } -} diff --git a/libsession/src/main/java/org/session/libsession/utilities/dynamiclanguage/LanguageString.java b/libsession/src/main/java/org/session/libsession/utilities/dynamiclanguage/LanguageString.java deleted file mode 100644 index 7db4244fb7a..00000000000 --- a/libsession/src/main/java/org/session/libsession/utilities/dynamiclanguage/LanguageString.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.session.libsession.utilities.dynamiclanguage; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.util.Locale; - -public final class LanguageString { - - private LanguageString() { } - - /** - * @param languageString String in format language_REGION, e.g. en_US - * @return Locale, or null if cannot parse - */ - @Nullable - public static Locale parseLocale(@Nullable String languageString) { - if (languageString == null || languageString.isEmpty()) { - return null; - } - - final Locale locale = createLocale(languageString); - - if (!isValid(locale)) { - return null; - } else { - return locale; - } - } - - private static Locale createLocale(@NonNull String languageString) { - final String language[] = languageString.split("_"); - if (language.length == 2) { - return new Locale(language[0], language[1]); - } else { - return new Locale(language[0]); - } - } - - private static boolean isValid(@NonNull Locale locale) { - try { - return locale.getISO3Language() != null && locale.getISO3Country() != null; - } catch (Exception ex) { - return false; - } - } -} diff --git a/libsession/src/main/java/org/session/libsession/utilities/dynamiclanguage/LocaleParser.kt b/libsession/src/main/java/org/session/libsession/utilities/dynamiclanguage/LocaleParser.kt deleted file mode 100644 index 6653903c972..00000000000 --- a/libsession/src/main/java/org/session/libsession/utilities/dynamiclanguage/LocaleParser.kt +++ /dev/null @@ -1,28 +0,0 @@ -package org.session.libsession.utilities.dynamiclanguage - -import java.util.* - -class LocaleParser(val helper: LocaleParserHelperProtocol) { - companion object { - lateinit var shared: LocaleParser - - fun configure(helper: LocaleParserHelperProtocol) { - if (Companion::shared.isInitialized) { return } - shared = LocaleParser(helper) - } - - /** - * Given a language, gets the best choice from the apps list of supported languages and the - * Systems set of languages. - */ - @JvmStatic - fun findBestMatchingLocaleForLanguage(language: String?): Locale? { - val locale = LanguageString.parseLocale(language) - return if (shared.helper.appSupportsTheExactLocale(locale)) { - locale - } else { - shared.helper.findBestSystemLocale() - } - } - } -} \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/utilities/dynamiclanguage/LocaleParserHelperProtocol.kt b/libsession/src/main/java/org/session/libsession/utilities/dynamiclanguage/LocaleParserHelperProtocol.kt deleted file mode 100644 index 8d13acf049e..00000000000 --- a/libsession/src/main/java/org/session/libsession/utilities/dynamiclanguage/LocaleParserHelperProtocol.kt +++ /dev/null @@ -1,8 +0,0 @@ -package org.session.libsession.utilities.dynamiclanguage - -import java.util.Locale - -interface LocaleParserHelperProtocol { - fun appSupportsTheExactLocale(locale: Locale?): Boolean - fun findBestSystemLocale(): Locale -} \ No newline at end of file diff --git a/libsession/src/main/res/values/strings.xml b/libsession/src/main/res/values/strings.xml index dd2ca01029b..b48e40da10e 100644 --- a/libsession/src/main/res/values/strings.xml +++ b/libsession/src/main/res/values/strings.xml @@ -146,7 +146,7 @@ Incoming call Missed Call Missed call from {name} - Voice and Video Calls require notifications to be enabled in your device system settings. + Voice and Video Calls require notifications to be enabled in your device system settings. Call Permissions Required You can enable the \"Voice and Video Calls\" permission in Privacy Settings. Reconnecting… @@ -436,7 +436,7 @@ Enter a group name Please enter a group name. Please enter a shorter group name. - Group name is now {group_name}. + Group name is now {group_name}. Group name updated. You have no messages from {group_name}. Send a message to start the conversation! You are the only admin in {group_name}.\n\nGroup members and settings cannot be changed without an admin. @@ -692,7 +692,7 @@ {app_name} needs microphone access to make calls and record audio messages. Allow access to microphone. {app_name} needs music and audio access in order to send files, music and audio. - Permission required + Permission Required {app_name} needs photo library access so you can send photos and videos, but it has been permanently denied. Tap Settings -> Permissions, and turn \"Photos and videos\" on. {app_name} needs storage access so you can send and save attachments. Tap Settings -> Permissions, and turn \"Storage\" on. {app_name} needs storage access to save attachments and media. @@ -814,7 +814,7 @@ Cannot Update {app_name} failed to update. Please go to {session_download_url} and install the new version manually, then contact our Help Center to let us know about this problem. A new version of {app_name} is available, tap to update - A new version of {app_name} is available. + A new version of {app_name} is available. Go to Release Notes {app_name} Update Version {version}