mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-21 15:05:19 +00:00
Merge pull request #1660 from oxen-io/feature/strings-fixes
SES-2688 SES-2689
This commit is contained in:
commit
2ebd20c31e
@ -412,14 +412,9 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
|
||||
Permissions.with(this)
|
||||
.request(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
.maxSdkVersion(Build.VERSION_CODES.P)
|
||||
.withPermanentDenialDialog(Phrase.from(getApplicationContext(), R.string.permissionsStorageSaveDenied)
|
||||
.put(APP_NAME_KEY, getString(R.string.app_name))
|
||||
.format().toString())
|
||||
.withPermanentDenialDialog(getPermanentlyDeniedStorageText())
|
||||
.onAnyDenied(() -> {
|
||||
String txt = Phrase.from(getApplicationContext(), R.string.permissionsStorageSaveDenied)
|
||||
.put(APP_NAME_KEY, getString(R.string.app_name))
|
||||
.format().toString();
|
||||
Toast.makeText(this, txt, Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(this, getPermanentlyDeniedStorageText(), Toast.LENGTH_LONG).show();
|
||||
})
|
||||
.onAllGranted(() -> {
|
||||
SaveAttachmentTask saveTask = new SaveAttachmentTask(MediaPreviewActivity.this);
|
||||
@ -436,6 +431,12 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
|
||||
});
|
||||
}
|
||||
|
||||
private String getPermanentlyDeniedStorageText(){
|
||||
return Phrase.from(getApplicationContext(), R.string.permissionsStorageDeniedLegacy)
|
||||
.put(APP_NAME_KEY, getString(R.string.app_name))
|
||||
.format().toString();
|
||||
}
|
||||
|
||||
private void sendMediaSavedNotificationIfNeeded() {
|
||||
if (conversationRecipient.isGroupRecipient()) return;
|
||||
DataExtractionNotification message = new DataExtractionNotification(new DataExtractionNotification.Kind.MediaSaved(SnodeAPI.getNowWithOffset()));
|
||||
|
@ -26,14 +26,7 @@ fun showMuteDialog(
|
||||
context.getSubbedString(entry.stringRes, TIME_LARGE_KEY to largeTimeUnitString)
|
||||
}
|
||||
}.toTypedArray()) {
|
||||
// Note: We add the current timestamp to the mute duration to get the un-mute timestamp
|
||||
// that gets stored in the database via ConversationMenuHelper.mute().
|
||||
// Also: This is a kludge, but we ADD one second to the mute duration because otherwise by
|
||||
// the time the view for how long the conversation is muted for gets set then it's actually
|
||||
// less than the entire duration - so 1 hour becomes 59 minutes, 1 day becomes 23 hours etc.
|
||||
// As we really want to see the actual set time (1 hour / 1 day etc.) then we'll bump it by
|
||||
// 1 second which is neither here nor there in the grand scheme of things.
|
||||
onMuteDuration(Option.entries[it].getTime() + System.currentTimeMillis() + 1.seconds.inWholeMilliseconds)
|
||||
onMuteDuration(Option.entries[it].getTime())
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,5 +37,12 @@ private enum class Option(@StringRes val stringRes: Int, val getTime: () -> Long
|
||||
SEVEN_DAYS(R.string.notificationsMuteFor, duration = TimeUnit.DAYS.toMillis(7)),
|
||||
FOREVER(R.string.notificationsMute, getTime = { Long.MAX_VALUE } );
|
||||
|
||||
constructor(@StringRes stringRes: Int, duration: Long): this(stringRes, { duration } )
|
||||
// Note: We add the current timestamp to the mute duration to get the un-mute timestamp
|
||||
// that gets stored in the database via ConversationMenuHelper.mute().
|
||||
// Also: This is a kludge, but we ADD one second to the mute duration because otherwise by
|
||||
// the time the view for how long the conversation is muted for gets set then it's actually
|
||||
// less than the entire duration - so 1 hour becomes 59 minutes, 1 day becomes 23 hours etc.
|
||||
// As we really want to see the actual set time (1 hour / 1 day etc.) then we'll bump it by
|
||||
// 1 second which is neither here nor there in the grand scheme of things.
|
||||
constructor(@StringRes stringRes: Int, duration: Long): this(stringRes, { duration + System.currentTimeMillis() + 1.seconds.inWholeMilliseconds } )
|
||||
}
|
@ -125,9 +125,7 @@ class ConversationActionBarView @JvmOverloads constructor(
|
||||
settings += ConversationSetting(
|
||||
recipient.mutedUntil.takeUnless { it == Long.MAX_VALUE }
|
||||
?.let {
|
||||
val mutedDuration = (it - System.currentTimeMillis()).milliseconds
|
||||
val durationString = LocalisedTimeUtil.getDurationWithSingleLargestTimeUnit(context, mutedDuration)
|
||||
context.getSubbedString(R.string.notificationsMuteFor, TIME_LARGE_KEY to durationString)
|
||||
context.getString(R.string.notificationsHeaderMute)
|
||||
}
|
||||
?: context.getString(R.string.notificationsMuted),
|
||||
ConversationSettingType.NOTIFICATION,
|
||||
|
@ -2257,8 +2257,8 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
// that we've warned the user just _once_ that any attachments they save can be accessed by other apps.
|
||||
val haveWarned = TextSecurePreferences.getHaveWarnedUserAboutSavingAttachments(this)
|
||||
if (haveWarned) {
|
||||
// On Android versions below 30 we require the WRITE_EXTERNAL_STORAGE permission to save attachments.
|
||||
if (Build.VERSION.SDK_INT < 30) {
|
||||
// On Android versions below 29 we require the WRITE_EXTERNAL_STORAGE permission to save attachments.
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
|
||||
// Save the attachment(s) then bail if we already have permission to do so
|
||||
if (hasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
|
||||
saveAttachments(message)
|
||||
@ -2279,7 +2279,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
Permissions.with(this)
|
||||
.request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
.maxSdkVersion(Build.VERSION_CODES.P) // P is 28
|
||||
.withPermanentDenialDialog(Phrase.from(applicationContext, R.string.permissionsStorageSaveDenied)
|
||||
.withPermanentDenialDialog(Phrase.from(applicationContext, R.string.permissionsStorageDeniedLegacy)
|
||||
.put(APP_NAME_KEY, getString(R.string.app_name))
|
||||
.format().toString())
|
||||
.onAnyDenied {
|
||||
@ -2289,7 +2289,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
showSessionDialog {
|
||||
title(R.string.permissionsRequired)
|
||||
|
||||
val txt = Phrase.from(applicationContext, R.string.permissionsStorageSaveDenied)
|
||||
val txt = Phrase.from(applicationContext, R.string.permissionsStorageDeniedLegacy)
|
||||
.put(APP_NAME_KEY, getString(R.string.app_name))
|
||||
.format().toString()
|
||||
text(txt)
|
||||
|
@ -245,51 +245,58 @@ public class AttachmentManager {
|
||||
|
||||
public static void selectDocument(Activity activity, int requestCode) {
|
||||
Permissions.PermissionsBuilder builder = Permissions.with(activity);
|
||||
Context c = activity.getApplicationContext();
|
||||
|
||||
// The READ_EXTERNAL_STORAGE permission is deprecated (and will AUTO-FAIL if requested!) on
|
||||
// Android 13 and above (API 33 - 'Tiramisu') we must ask for READ_MEDIA_VIDEO/IMAGES/AUDIO instead.
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
builder = builder.request(Manifest.permission.READ_MEDIA_VIDEO)
|
||||
.request(Manifest.permission.READ_MEDIA_IMAGES)
|
||||
.request(Manifest.permission.READ_MEDIA_AUDIO);
|
||||
.request(Manifest.permission.READ_MEDIA_AUDIO)
|
||||
.withRationaleDialog(
|
||||
Phrase.from(c, R.string.permissionsStorageSend)
|
||||
.put(APP_NAME_KEY, c.getString(R.string.app_name)).format().toString()
|
||||
)
|
||||
.withPermanentDenialDialog(
|
||||
Phrase.from(c, R.string.permissionMusicAudioDenied)
|
||||
.put(APP_NAME_KEY, c.getString(R.string.app_name))
|
||||
.format().toString()
|
||||
);
|
||||
} else {
|
||||
builder = builder.request(Manifest.permission.READ_EXTERNAL_STORAGE);
|
||||
builder = builder.request(Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
.withPermanentDenialDialog(
|
||||
Phrase.from(c, R.string.permissionsStorageDeniedLegacy)
|
||||
.put(APP_NAME_KEY, c.getString(R.string.app_name))
|
||||
.format().toString()
|
||||
);
|
||||
}
|
||||
|
||||
Context c = activity.getApplicationContext();
|
||||
|
||||
String needStoragePermissionTxt = Phrase.from(c, R.string.permissionsStorageSend).put(APP_NAME_KEY, c.getString(R.string.app_name)).format().toString();
|
||||
|
||||
String storagePermissionDeniedTxt = Phrase.from(c, R.string.permissionsStorageSaveDenied)
|
||||
.put(APP_NAME_KEY, c.getString(R.string.app_name))
|
||||
.format().toString();
|
||||
|
||||
builder.withPermanentDenialDialog(storagePermissionDeniedTxt)
|
||||
.withRationaleDialog(needStoragePermissionTxt, R.drawable.ic_baseline_photo_library_24)
|
||||
.onAllGranted(() -> selectMediaType(activity, "*/*", null, requestCode)) // Note: We can use startActivityForResult w/ the ACTION_OPEN_DOCUMENT or ACTION_OPEN_DOCUMENT_TREE intent if we need to modernise this.
|
||||
builder.onAllGranted(() -> selectMediaType(activity, "*/*", null, requestCode)) // Note: We can use startActivityForResult w/ the ACTION_OPEN_DOCUMENT or ACTION_OPEN_DOCUMENT_TREE intent if we need to modernise this.
|
||||
.execute();
|
||||
}
|
||||
|
||||
public static void selectGallery(Activity activity, int requestCode, @NonNull Recipient recipient, @NonNull String body) {
|
||||
|
||||
Context c = activity.getApplicationContext();
|
||||
String needStoragePermissionTxt = Phrase.from(c, R.string.permissionsStorageSend)
|
||||
.put(APP_NAME_KEY, c.getString(R.string.app_name))
|
||||
.format().toString();
|
||||
String cameraPermissionDeniedTxt = Phrase.from(c, R.string.cameraGrantAccessDenied)
|
||||
.put(APP_NAME_KEY, c.getString(R.string.app_name))
|
||||
.format().toString();
|
||||
|
||||
Permissions.PermissionsBuilder builder = Permissions.with(activity);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
builder = builder.request(Manifest.permission.READ_MEDIA_VIDEO)
|
||||
.request(Manifest.permission.READ_MEDIA_IMAGES);
|
||||
.request(Manifest.permission.READ_MEDIA_IMAGES)
|
||||
.withPermanentDenialDialog(
|
||||
Phrase.from(c, R.string.permissionsStorageDenied)
|
||||
.put(APP_NAME_KEY, c.getString(R.string.app_name))
|
||||
.format().toString()
|
||||
);
|
||||
} else {
|
||||
builder = builder.request(Manifest.permission.READ_EXTERNAL_STORAGE);
|
||||
builder = builder.request(Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
.withPermanentDenialDialog(
|
||||
Phrase.from(c, R.string.permissionsStorageDeniedLegacy)
|
||||
.put(APP_NAME_KEY, c.getString(R.string.app_name))
|
||||
.format().toString()
|
||||
);
|
||||
}
|
||||
builder.withPermanentDenialDialog(cameraPermissionDeniedTxt)
|
||||
.withRationaleDialog(needStoragePermissionTxt, R.drawable.ic_baseline_photo_library_24)
|
||||
.onAllGranted(() -> activity.startActivityForResult(MediaSendActivity.buildGalleryIntent(activity, recipient, body), requestCode))
|
||||
builder.onAllGranted(() -> activity.startActivityForResult(MediaSendActivity.buildGalleryIntent(activity, recipient, body), requestCode))
|
||||
.execute();
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package org.thoughtcrime.securesms.debugmenu
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
@ -19,6 +20,8 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalClipboardManager
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import network.loki.messenger.BuildConfig
|
||||
import network.loki.messenger.R
|
||||
@ -45,7 +48,7 @@ fun DebugMenu(
|
||||
sendCommand: (DebugMenuViewModel.Commands) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
onClose: () -> Unit
|
||||
){
|
||||
) {
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
|
||||
Scaffold(
|
||||
@ -56,7 +59,7 @@ fun DebugMenu(
|
||||
) { contentPadding ->
|
||||
// display a snackbar when required
|
||||
LaunchedEffect(uiState.snackMessage) {
|
||||
if(!uiState.snackMessage.isNullOrEmpty()){
|
||||
if (!uiState.snackMessage.isNullOrEmpty()) {
|
||||
snackbarHostState.showSnackbar(uiState.snackMessage)
|
||||
}
|
||||
}
|
||||
@ -102,13 +105,22 @@ fun DebugMenu(
|
||||
.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
// Info pane
|
||||
DebugCell("App Info") {
|
||||
val clipboardManager = LocalClipboardManager.current
|
||||
val appVersion = "${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE} - ${
|
||||
BuildConfig.GIT_HASH.take(
|
||||
6
|
||||
)
|
||||
})"
|
||||
|
||||
DebugCell(
|
||||
modifier = Modifier.clickable {
|
||||
// clicking the cell copies the version number to the clipboard
|
||||
clipboardManager.setText(AnnotatedString(appVersion))
|
||||
},
|
||||
title = "App Info"
|
||||
) {
|
||||
Text(
|
||||
text = "Version: ${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE} - ${
|
||||
BuildConfig.GIT_HASH.take(
|
||||
6
|
||||
)
|
||||
})",
|
||||
text = "Version: $appVersion",
|
||||
style = LocalType.current.base
|
||||
)
|
||||
}
|
||||
@ -155,7 +167,7 @@ fun ColumnScope.DebugCell(
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun PreviewDebugMenu(){
|
||||
fun PreviewDebugMenu() {
|
||||
PreviewTheme {
|
||||
DebugMenu(
|
||||
uiState = DebugMenuViewModel.UIState(
|
||||
|
@ -547,6 +547,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
|
||||
} else {
|
||||
showMuteDialog(this) { until ->
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
Log.d("", "**** until: $until")
|
||||
recipientDatabase.setMuted(thread.recipient, until)
|
||||
withContext(Dispatchers.Main) {
|
||||
binding.recyclerView.adapter!!.notifyDataSetChanged()
|
||||
|
@ -73,7 +73,7 @@ public class Permissions {
|
||||
return this;
|
||||
}
|
||||
|
||||
public PermissionsBuilder withRationaleDialog(@NonNull String message, @NonNull @DrawableRes int... headers) {
|
||||
public PermissionsBuilder withRationaleDialog(@NonNull String message, @DrawableRes int... headers) {
|
||||
this.rationalDialogHeader = headers;
|
||||
this.rationaleDialogMessage = message;
|
||||
return this;
|
||||
@ -143,7 +143,7 @@ public class Permissions {
|
||||
|
||||
if (!isInTargetSDKRange || permissionObject.hasAll(requestedPermissions)) {
|
||||
executePreGrantedPermissionsRequest(request);
|
||||
} else if (rationaleDialogMessage != null && rationalDialogHeader != null) {
|
||||
} else if (rationaleDialogMessage != null) {
|
||||
executePermissionsRequestWithRationale(request);
|
||||
} else {
|
||||
executePermissionsRequest(request);
|
||||
|
@ -4,6 +4,7 @@ import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.util.TypedValue
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
@ -25,34 +26,44 @@ object RationaleDialog {
|
||||
onNegative: Runnable,
|
||||
@DrawableRes vararg drawables: Int
|
||||
): AlertDialog {
|
||||
val view = LayoutInflater.from(context).inflate(R.layout.permissions_rationale_dialog, null)
|
||||
.apply { clipToOutline = true }
|
||||
val header = view.findViewById<ViewGroup>(R.id.header_container)
|
||||
view.findViewById<TextView>(R.id.message).text = message
|
||||
var customView: View? = null
|
||||
if (!drawables.isEmpty()) {
|
||||
customView = LayoutInflater.from(context).inflate(R.layout.permissions_rationale_dialog, null)
|
||||
.apply { clipToOutline = true }
|
||||
val header = customView.findViewById<ViewGroup>(R.id.header_container)
|
||||
|
||||
fun addIcon(id: Int) {
|
||||
ImageView(context).apply {
|
||||
setImageDrawable(ResourcesCompat.getDrawable(context.resources, id, context.theme))
|
||||
layoutParams = LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)
|
||||
}.also(header::addView)
|
||||
customView.findViewById<TextView>(R.id.message).text = message
|
||||
|
||||
fun addIcon(id: Int) {
|
||||
ImageView(context).apply {
|
||||
setImageDrawable(ResourcesCompat.getDrawable(context.resources, id, context.theme))
|
||||
layoutParams = LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)
|
||||
}.also(header::addView)
|
||||
}
|
||||
|
||||
fun addPlus() {
|
||||
TextView(context).apply {
|
||||
text = "+"
|
||||
setTextSize(TypedValue.COMPLEX_UNIT_SP, 40f)
|
||||
setTextColor(Color.WHITE)
|
||||
layoutParams = LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply {
|
||||
ViewUtil.dpToPx(context, 20).let { setMargins(it, 0, it, 0) }
|
||||
}
|
||||
}.also(header::addView)
|
||||
}
|
||||
|
||||
drawables.firstOrNull()?.let(::addIcon)
|
||||
drawables.drop(1).forEach { addPlus(); addIcon(it) }
|
||||
}
|
||||
|
||||
fun addPlus() {
|
||||
TextView(context).apply {
|
||||
text = "+"
|
||||
setTextSize(TypedValue.COMPLEX_UNIT_SP, 40f)
|
||||
setTextColor(Color.WHITE)
|
||||
layoutParams = LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply {
|
||||
ViewUtil.dpToPx(context, 20).let { setMargins(it, 0, it, 0) }
|
||||
}
|
||||
}.also(header::addView)
|
||||
}
|
||||
|
||||
drawables.firstOrNull()?.let(::addIcon)
|
||||
drawables.drop(1).forEach { addPlus(); addIcon(it) }
|
||||
|
||||
return context.showSessionDialog {
|
||||
view(view)
|
||||
// show the generic title when there are no icons
|
||||
if(customView != null){
|
||||
view(customView)
|
||||
} else {
|
||||
title(R.string.permissionsRequired)
|
||||
text(message)
|
||||
}
|
||||
button(R.string.theContinue) { onPositive.run() }
|
||||
button(R.string.notNow) { onNegative.run() }
|
||||
}
|
||||
|
@ -98,10 +98,10 @@ class HelpSettingsFragment: CorrectedPreferenceFragment() {
|
||||
Permissions.with(this)
|
||||
.request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
.maxSdkVersion(Build.VERSION_CODES.P)
|
||||
.withPermanentDenialDialog(requireContext().getSubbedString(R.string.permissionsStorageSaveDenied, APP_NAME_KEY to getString(R.string.app_name)))
|
||||
.withPermanentDenialDialog(requireContext().getSubbedString(R.string.permissionsStorageDeniedLegacy, APP_NAME_KEY to getString(R.string.app_name)))
|
||||
.onAnyDenied {
|
||||
val c = requireContext()
|
||||
val txt = c.getSubbedString(R.string.permissionsStorageSaveDenied, APP_NAME_KEY to getString(R.string.app_name))
|
||||
val txt = c.getSubbedString(R.string.permissionsStorageDeniedLegacy, APP_NAME_KEY to getString(R.string.app_name))
|
||||
Toast.makeText(c, txt, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
.onAllGranted {
|
||||
|
@ -63,7 +63,6 @@ import kotlinx.coroutines.launch
|
||||
import network.loki.messenger.R
|
||||
import org.session.libsession.utilities.StringSubstitutionConstants.APP_NAME_KEY
|
||||
import org.session.libsignal.utilities.Log
|
||||
import org.thoughtcrime.securesms.mediasend.MediaSendActivity
|
||||
import org.thoughtcrime.securesms.permissions.Permissions
|
||||
import org.thoughtcrime.securesms.ui.AlertDialog
|
||||
import org.thoughtcrime.securesms.ui.DialogButtonModel
|
||||
|
Loading…
Reference in New Issue
Block a user