diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/CorrectedPreferenceFragment.java b/app/src/main/java/org/thoughtcrime/securesms/preferences/CorrectedPreferenceFragment.java deleted file mode 100644 index 931d5e43aa..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/preferences/CorrectedPreferenceFragment.java +++ /dev/null @@ -1,174 +0,0 @@ -package org.thoughtcrime.securesms.preferences; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.graphics.Typeface; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.core.content.ContextCompat; -import androidx.core.view.ViewCompat; -import androidx.preference.Preference; -import androidx.preference.PreferenceCategory; -import androidx.preference.PreferenceFragmentCompat; -import androidx.preference.PreferenceGroupAdapter; -import androidx.preference.PreferenceScreen; -import androidx.preference.PreferenceViewHolder; -import androidx.recyclerview.widget.RecyclerView; -import org.thoughtcrime.securesms.conversation.v2.ViewUtil; -import org.thoughtcrime.securesms.util.ViewUtilitiesKt; -import network.loki.messenger.R; - -public abstract class CorrectedPreferenceFragment extends PreferenceFragmentCompat { - - public static final int SINGLE_TYPE = 21; - public static final int TOP_TYPE = 22; - public static final int MIDDLE_TYPE = 23; - public static final int BOTTOM_TYPE = 24; - public static final int CATEGORY_TYPE = 25; - - public int horizontalPadding; - public int verticalPadding; - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - horizontalPadding = ViewUtil.dpToPx(requireContext(), 36); - verticalPadding = ViewUtil.dpToPx(requireContext(), 8); - } - - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - - RecyclerView lv = getListView(); - if (lv != null) { - lv.setPadding(0, 0, 0, 0); - ViewUtilitiesKt.applyCommonWindowInsetsOnViews(lv); - } - - setDivider(null); - } - - @Override - public void onDisplayPreferenceDialog(Preference preference) { - if (preference != null) super.onDisplayPreferenceDialog(preference); - } - - @Override - @SuppressLint("RestrictedApi") - protected RecyclerView.Adapter onCreateAdapter(PreferenceScreen preferenceScreen) { - return new PreferenceGroupAdapter(preferenceScreen) { - - @NonNull - @Override - public PreferenceViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - PreferenceViewHolder viewHolder = super.onCreateViewHolder(parent, viewType); - return viewHolder; - } - - private int getPreferenceType(int position) { - Preference preference = getItem(position); - if (preference instanceof PreferenceCategory) { - return CATEGORY_TYPE; - } - boolean isStart = isTop(position); - boolean isEnd = isBottom(position); - if (isStart && isEnd) { - // always show full - return SINGLE_TYPE; - } else { - if (isStart) { - return TOP_TYPE; - } else if (isEnd) { - return BOTTOM_TYPE; - } else { - return MIDDLE_TYPE; - } - } - } - - private boolean isTop(int position) { - if (position == 0) { - return true; - } - Preference previous = getItem(position - 1); - return previous instanceof PreferenceCategory; - } - - private boolean isBottom(int position) { - int size = getItemCount(); - if (position == size - 1) { - // last one - return true; - } - Preference next = getItem(position + 1); - return next instanceof PreferenceCategory; - } - - public Drawable getBackground(Context context, int position) { - int viewType = getPreferenceType(position); - Drawable background; - switch (viewType) { - case SINGLE_TYPE: - background = ContextCompat.getDrawable(context, R.drawable.preference_single); - break; - case TOP_TYPE: - background = ContextCompat.getDrawable(context, R.drawable.preference_top); - break; - case MIDDLE_TYPE: - background = ContextCompat.getDrawable(context, R.drawable.preference_middle); - break; - case BOTTOM_TYPE: - background = ContextCompat.getDrawable(context, R.drawable.preference_bottom); - break; - default: - background = null; - break; - } - return background; - } - - @Override - public void onBindViewHolder(PreferenceViewHolder holder, int position) { - super.onBindViewHolder(holder, position); - Preference preference = getItem(position); - if (preference instanceof PreferenceCategory) { - ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) holder.itemView.getLayoutParams(); - layoutParams.topMargin = 0; - layoutParams.bottomMargin = 0; - holder.itemView.setLayoutParams(layoutParams); - setZeroPaddingToLayoutChildren(holder.itemView); - } else { - View iconFrame = holder.itemView.findViewById(R.id.icon_frame); - if (iconFrame != null) { - iconFrame.setVisibility(preference.getIcon() == null ? View.GONE : View.VISIBLE); - } - Drawable background = getBackground(holder.itemView.getContext(), position); - holder.itemView.setBackground(background); - TextView titleView = holder.itemView.findViewById(android.R.id.title); - if (titleView != null) { - ((TextView) titleView).setTypeface(Typeface.defaultFromStyle(Typeface.BOLD)); - } - boolean isTop = isTop(position); - boolean isBottom = isBottom(position); - holder.itemView.setPadding(horizontalPadding, isTop ? verticalPadding : 0, horizontalPadding, isBottom ? verticalPadding : 0); - } - } - }; - } - - private void setZeroPaddingToLayoutChildren(View view) { - if (!(view instanceof ViewGroup)) return; - - ViewGroup viewGroup = (ViewGroup) view; - for (int i = 0; i < viewGroup.getChildCount(); i++) { - setZeroPaddingToLayoutChildren(viewGroup.getChildAt(i)); - ViewCompat.setPaddingRelative(viewGroup, 0, viewGroup.getPaddingTop(), ViewCompat.getPaddingEnd(viewGroup), viewGroup.getPaddingBottom()); - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/HelpSettingsActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/preferences/HelpSettingsActivity.kt index 8bdcf79c86..e84aab2f6c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/preferences/HelpSettingsActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/HelpSettingsActivity.kt @@ -1,202 +1,33 @@ package org.thoughtcrime.securesms.preferences -import android.Manifest -import android.content.Intent -import android.net.Uri -import android.os.Build -import android.os.Bundle -import android.view.Gravity -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.FrameLayout -import android.widget.ProgressBar -import android.widget.TextView -import android.widget.Toast -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue -import androidx.compose.ui.platform.ComposeView -import androidx.compose.ui.platform.ViewCompositionStrategy -import androidx.compose.ui.res.stringResource -import androidx.core.view.isInvisible -import androidx.preference.Preference -import com.squareup.phrase.Phrase +import androidx.activity.viewModels +import androidx.compose.runtime.Composable import dagger.hilt.android.AndroidEntryPoint -import network.loki.messenger.R -import org.session.libsession.utilities.StringSubstitutionConstants.APP_NAME_KEY -import org.session.libsignal.utilities.Log -import org.thoughtcrime.securesms.ScreenLockActionBarActivity +import org.thoughtcrime.securesms.FullComposeScreenLockActivity import org.thoughtcrime.securesms.permissions.Permissions -import org.thoughtcrime.securesms.ui.AlertDialog -import org.thoughtcrime.securesms.ui.DialogButtonData -import org.thoughtcrime.securesms.ui.GetString -import org.thoughtcrime.securesms.ui.components.ExportLogsDialog -import org.thoughtcrime.securesms.ui.components.LogExporter -import org.thoughtcrime.securesms.ui.getSubbedCharSequence -import org.thoughtcrime.securesms.ui.getSubbedString -import org.thoughtcrime.securesms.ui.openUrl -import org.thoughtcrime.securesms.ui.setThemedContent -import javax.inject.Inject +import org.thoughtcrime.securesms.preferences.compose.HelpSettingsScreen +import org.thoughtcrime.securesms.preferences.compose.HelpSettingsViewModel @AndroidEntryPoint -class HelpSettingsActivity: ScreenLockActionBarActivity() { +class HelpSettingsActivity: FullComposeScreenLockActivity() { - override val applyDefaultWindowInsets: Boolean - get() = false + @Composable + override fun ComposeContent() { + val viewModel: HelpSettingsViewModel by viewModels() - override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) { - super.onCreate(savedInstanceState, ready) - setContentView(R.layout.activity_fragment_wrapper) - supportFragmentManager.beginTransaction() - .replace(R.id.fragmentContainer, HelpSettingsFragment()) - .commit() - } -} - -@AndroidEntryPoint -class HelpSettingsFragment: CorrectedPreferenceFragment() { - - companion object { - private const val EXPORT_LOGS = "export_logs" - private const val TRANSLATE = "translate_session" - private const val FEEDBACK = "feedback" - private const val FAQ = "faq" - private const val SUPPORT = "support" - private const val CROWDIN_URL = "https://getsession.org/translate" - private const val FEEDBACK_URL = "https://getsession.org/survey" - private const val FAQ_URL = "https://getsession.org/faq" - private const val SUPPORT_URL = "https://sessionapp.zendesk.com/hc/en-us" - } - - private var composeView: ComposeView? = null - - private var showExportLogDialog by mutableStateOf(false) - - @Inject - lateinit var exporter: LogExporter - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - // We will wrap the existing screen in a framelayout in order to add custom compose content - val preferenceView = super.onCreateView(inflater, container, savedInstanceState) - - val wrapper = FrameLayout(requireContext()).apply { - layoutParams = ViewGroup.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT - ) - } - - wrapper.addView( - preferenceView, - FrameLayout.LayoutParams( - FrameLayout.LayoutParams.MATCH_PARENT, - FrameLayout.LayoutParams.MATCH_PARENT - ) - ) - - composeView = ComposeView(requireContext()) - wrapper.addView( - composeView, - FrameLayout.LayoutParams( - FrameLayout.LayoutParams.MATCH_PARENT, - FrameLayout.LayoutParams.WRAP_CONTENT, - Gravity.TOP - ) + HelpSettingsScreen( + viewModel = viewModel, + onBackPressed = this::finish ) - - return wrapper } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - //set up compose content - composeView?.apply { - setViewCompositionStrategy( - ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed - ) - setThemedContent { - if(showExportLogDialog) { - ExportLogsDialog( - logExporter = exporter, - onDismissRequest = { - showExportLogDialog = false - } - ) - } - } - } - } - - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - addPreferencesFromResource(R.xml.preferences_help) - - // String sub the summary text of the `export_logs` element in preferences_help.xml - val exportPref = preferenceScreen.findPreference(EXPORT_LOGS) - exportPref?.summary = context?.getSubbedCharSequence(R.string.helpReportABugExportLogsDescription, APP_NAME_KEY to getString(R.string.app_name)) - - // String sub the summary text of the `translate_session` element in preferences_help.xml - val translatePref = preferenceScreen.findPreference(TRANSLATE) - translatePref?.title = context?.getSubbedCharSequence(R.string.helpHelpUsTranslateSession, APP_NAME_KEY to getString(R.string.app_name)) - } - - override fun onPreferenceTreeClick(preference: Preference): Boolean { - return when (preference.key) { - EXPORT_LOGS -> { - shareLogs() - true - } - TRANSLATE -> { - requireContext().openUrl(CROWDIN_URL) - true - } - FEEDBACK -> { - requireContext().openUrl(FEEDBACK_URL) - true - } - FAQ -> { - requireContext().openUrl(FAQ_URL) - true - } - SUPPORT -> { - requireContext().openUrl(SUPPORT_URL) - true - } - else -> super.onPreferenceTreeClick(preference) - } - } - - private fun updateExportButtonAndProgressBarUI(exportJobRunning: Boolean) { - this.activity?.runOnUiThread(Runnable { - // Change export logs button text - val exportLogsButton = this.activity?.findViewById(R.id.export_logs_button) as TextView? - if (exportLogsButton == null) { Log.w("Loki", "Could not find export logs button view.") } - exportLogsButton?.text = if (exportJobRunning) getString(R.string.cancel) else getString(R.string.helpReportABugExportLogs) - - // Show progress bar - val exportProgressBar = this.activity?.findViewById(R.id.export_progress_bar) as ProgressBar? - exportProgressBar?.isInvisible = !exportJobRunning - }) + override fun onRequestPermissionsResult( + requestCode: Int, + permissions: Array, + grantResults: IntArray + ) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults) } +} - private fun shareLogs() { - Permissions.with(this) - .request(Manifest.permission.WRITE_EXTERNAL_STORAGE) - .maxSdkVersion(Build.VERSION_CODES.P) - .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.permissionsStorageDeniedLegacy, APP_NAME_KEY to getString(R.string.app_name)) - Toast.makeText(c, txt, Toast.LENGTH_LONG).show() - } - .onAllGranted { - showExportLogDialog = true - } - .execute() - } -} \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/compose/HelpSettingsScreen.kt b/app/src/main/java/org/thoughtcrime/securesms/preferences/compose/HelpSettingsScreen.kt new file mode 100644 index 0000000000..97ae78cd59 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/compose/HelpSettingsScreen.kt @@ -0,0 +1,211 @@ +package org.thoughtcrime.securesms.preferences.compose + +import android.Manifest +import android.os.Build +import android.widget.Toast +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import com.squareup.phrase.Phrase +import network.loki.messenger.R +import org.session.libsession.utilities.StringSubstitutionConstants.APP_NAME_KEY +import org.thoughtcrime.securesms.permissions.Permissions +import org.thoughtcrime.securesms.ui.ActionRowItem +import org.thoughtcrime.securesms.ui.CategoryCell +import org.thoughtcrime.securesms.ui.GetString +import org.thoughtcrime.securesms.ui.IconActionRowItem +import org.thoughtcrime.securesms.ui.components.ExportLogsDialog +import org.thoughtcrime.securesms.ui.components.LogExporter +import org.thoughtcrime.securesms.ui.components.SlimFillButtonRect +import org.thoughtcrime.securesms.ui.components.annotatedStringResource +import org.thoughtcrime.securesms.ui.findActivity +import org.thoughtcrime.securesms.ui.getSubbedString +import org.thoughtcrime.securesms.ui.openUrl +import org.thoughtcrime.securesms.ui.theme.LocalDimensions + +private const val CROWDIN_URL = "https://getsession.org/translate" +private const val FEEDBACK_URL = "https://getsession.org/survey" +private const val FAQ_URL = "https://getsession.org/faq" +private const val SUPPORT_URL = "https://sessionapp.zendesk.com/hc/en-us" + +@Composable +fun HelpSettingsScreen( + viewModel: HelpSettingsViewModel, + onBackPressed: () -> Unit +) { + val context = LocalContext.current + + LaunchedEffect(Unit) { + viewModel.uiEvents.collect { event -> + when (event) { + HelpSettingsViewModel.HelpSettingsEvent.HandleExportLogs -> { + // Ask for permissions first + Permissions.with(context.findActivity()) + .request(Manifest.permission.WRITE_EXTERNAL_STORAGE) + .maxSdkVersion(Build.VERSION_CODES.P) + .withPermanentDenialDialog( + context.getSubbedString( + R.string.permissionsStorageDeniedLegacy, + APP_NAME_KEY to context.applicationContext.getString(R.string.app_name) + ) + ) + .onAnyDenied { + val txt = context.getSubbedString( + R.string.permissionsStorageDeniedLegacy, + APP_NAME_KEY to context.applicationContext.getString(R.string.app_name) + ) + Toast.makeText(context, txt, Toast.LENGTH_LONG).show() + } + .onAllGranted { + // show dialog + viewModel.onCommand(HelpSettingsViewModel.Commands.ShowExportDialog) + } + .execute() + } + + is HelpSettingsViewModel.HelpSettingsEvent.HandleUrl -> { + context.openUrl(event.urlString) + } + } + } + } + + val uiState = viewModel.uiState.collectAsState().value + + HelpSettings( + uiState = uiState, + sendCommand = viewModel::onCommand, + exporter = viewModel.exporter, + onBackPressed = onBackPressed + ) +} + +@Composable +fun HelpSettings( + uiState: HelpSettingsViewModel.UIState, + sendCommand: (HelpSettingsViewModel.Commands) -> Unit, + exporter: LogExporter, + onBackPressed: () -> Unit +) { + + val context = LocalContext.current + + BasePreferenceScreens( + onBack = onBackPressed, + title = GetString(R.string.sessionHelp).string() + ) { + item { + CategoryCell( + modifier = Modifier, + ) { + ActionRowItem( + modifier = Modifier.fillMaxWidth(), + title = annotatedStringResource(R.string.helpReportABug), + subtitle = annotatedStringResource( + Phrase.from(context, R.string.helpReportABugExportLogsDescription) + .put(APP_NAME_KEY, stringResource(R.string.app_name)) + .format() + ), + qaTag = R.string.qa_help_settings_export, + onClick = { sendCommand(HelpSettingsViewModel.Commands.ExportLogs) }, + endContent = { + SlimFillButtonRect( + text = stringResource(R.string.helpReportABugExportLogs), + onClick = { sendCommand(HelpSettingsViewModel.Commands.ExportLogs) } + ) + } + ) + } + + Spacer(modifier = Modifier.height(LocalDimensions.current.smallSpacing)) + } + + item { + CategoryCell( + modifier = Modifier, + ) { + IconActionRowItem( + modifier = Modifier.fillMaxWidth(), + title = annotatedStringResource( + Phrase.from(context, R.string.helpHelpUsTranslateSession) + .put(APP_NAME_KEY, stringResource(R.string.app_name)) + .format() + ), + icon = R.drawable.ic_square_arrow_up_right, + iconSize = LocalDimensions.current.iconSmall, + qaTag = R.string.qa_help_settings_translate, + onClick = { sendCommand(HelpSettingsViewModel.Commands.OpenUrl(CROWDIN_URL)) } + ) + } + + Spacer(modifier = Modifier.height(LocalDimensions.current.smallSpacing)) + } + + item { + CategoryCell( + modifier = Modifier, + ) { + IconActionRowItem( + modifier = Modifier.fillMaxWidth(), + title = annotatedStringResource(R.string.helpWedLoveYourFeedback), + icon = R.drawable.ic_square_arrow_up_right, + iconSize = LocalDimensions.current.iconSmall, + qaTag = R.string.qa_help_settings_feedback, + onClick = { sendCommand(HelpSettingsViewModel.Commands.OpenUrl(FEEDBACK_URL)) } + ) + } + + Spacer(modifier = Modifier.height(LocalDimensions.current.smallSpacing)) + } + + item { + CategoryCell( + modifier = Modifier, + ) { + IconActionRowItem( + modifier = Modifier.fillMaxWidth(), + title = annotatedStringResource(R.string.helpFAQ), + icon = R.drawable.ic_square_arrow_up_right, + iconSize = LocalDimensions.current.iconSmall, + qaTag = R.string.qa_help_settings_faq, + onClick = { sendCommand(HelpSettingsViewModel.Commands.OpenUrl(FAQ_URL)) } + ) + } + + Spacer(modifier = Modifier.height(LocalDimensions.current.smallSpacing)) + } + + + item { + CategoryCell( + modifier = Modifier, + ) { + IconActionRowItem( + modifier = Modifier.fillMaxWidth(), + title = annotatedStringResource(R.string.helpSupport), + icon = R.drawable.ic_square_arrow_up_right, + iconSize = LocalDimensions.current.iconSmall, + qaTag = R.string.qa_help_settings_support, + onClick = { sendCommand(HelpSettingsViewModel.Commands.OpenUrl(SUPPORT_URL)) } + ) + } + + Spacer(modifier = Modifier.height(LocalDimensions.current.smallSpacing)) + } + } + + if (uiState.showExportDialog) { + ExportLogsDialog( + logExporter = exporter, + onDismissRequest = { + sendCommand(HelpSettingsViewModel.Commands.HideExportDialog) + } + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/compose/HelpSettingsViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/preferences/compose/HelpSettingsViewModel.kt new file mode 100644 index 0000000000..e9e17dd639 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/compose/HelpSettingsViewModel.kt @@ -0,0 +1,66 @@ +package org.thoughtcrime.securesms.preferences.compose + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import org.thoughtcrime.securesms.ui.components.LogExporter +import javax.inject.Inject + +@HiltViewModel +class HelpSettingsViewModel @Inject constructor( + val exporter: LogExporter +) : ViewModel() { + private val _uiEvents = MutableSharedFlow() + val uiEvents get() = _uiEvents + + private val _uiState = MutableStateFlow(UIState()) + val uiState: StateFlow = _uiState + + fun onCommand(command: Commands) { + when (command) { + is Commands.OpenUrl -> { + viewModelScope.launch { + _uiEvents.emit(HelpSettingsEvent.HandleUrl(command.urlString)) + } + } + + is Commands.ExportLogs -> { + viewModelScope.launch { + //Check for storage permissions first + _uiEvents.emit(HelpSettingsEvent.HandleExportLogs) + } + } + + Commands.ShowExportDialog -> { + _uiState.update { it.copy(showExportDialog = true) } + } + + Commands.HideExportDialog -> { + _uiState.update { it.copy(showExportDialog = false) } + } + } + } + + data class UIState( + val showExportDialog: Boolean = false + ) + + sealed interface Commands { + data object ExportLogs : Commands + data class OpenUrl(val urlString: String) : Commands + + data object ShowExportDialog : Commands + + data object HideExportDialog : Commands + } + + sealed interface HelpSettingsEvent { + data object HandleExportLogs : HelpSettingsEvent + data class HandleUrl(val urlString: String) : HelpSettingsEvent + } +} \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/compose/NotificationsPreferenceScreen.kt b/app/src/main/java/org/thoughtcrime/securesms/preferences/compose/NotificationsPreferenceScreen.kt index e8c954d6cd..4d42790759 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/preferences/compose/NotificationsPreferenceScreen.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/compose/NotificationsPreferenceScreen.kt @@ -72,7 +72,7 @@ fun NotificationsPreferenceScreen( } LaunchedEffect(Unit) { - viewModel.events.collect { event -> + viewModel.uiEvents.collect { event -> when (event) { is NavigateToActivity -> { context.startActivity(event.intent) diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/compose/NotificationsPreferenceViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/preferences/compose/NotificationsPreferenceViewModel.kt index 014083e6d0..6b3850a009 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/preferences/compose/NotificationsPreferenceViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/compose/NotificationsPreferenceViewModel.kt @@ -35,8 +35,8 @@ class NotificationsPreferenceViewModel @Inject constructor( private val _uiState = MutableStateFlow(UIState()) val uiState: StateFlow = _uiState - private val mutableEvents = MutableSharedFlow() - val events get() = mutableEvents + private val _uiEvents = MutableSharedFlow() + val uiEvents get() = _uiEvents val privacyOptions: List by lazy { val labels = application.resources.getStringArray(R.array.pref_notification_privacy_entries) @@ -136,7 +136,7 @@ class NotificationsPreferenceViewModel @Inject constructor( _uiState.update { it.copy(showWhitelistDisableDialog = true) } } else { viewModelScope.launch { - mutableEvents.emit( + _uiEvents.emit( NotificationPreferenceEvent.NavigateToSystemBgWhitelist ) } @@ -159,7 +159,7 @@ class NotificationsPreferenceViewModel @Inject constructor( intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, current) viewModelScope.launch { - mutableEvents.emit( + _uiEvents.emit( NotificationPreferenceEvent.StartRingtoneActivityForResult( intent ) @@ -189,13 +189,13 @@ class NotificationsPreferenceViewModel @Inject constructor( Commands.OpenSystemBgWhitelist -> { viewModelScope.launch { - mutableEvents.emit(NotificationPreferenceEvent.NavigateToSystemBgWhitelist) + _uiEvents.emit(NotificationPreferenceEvent.NavigateToSystemBgWhitelist) } } Commands.OpenBatteryOptimizationSettings -> { viewModelScope.launch { - mutableEvents.emit(NotificationPreferenceEvent.NavigateToBatteryOptimizationSettings) + _uiEvents.emit(NotificationPreferenceEvent.NavigateToBatteryOptimizationSettings) } } @@ -208,7 +208,7 @@ class NotificationsPreferenceViewModel @Inject constructor( intent.putExtra(Settings.EXTRA_APP_PACKAGE, application.packageName) viewModelScope.launch { - mutableEvents.emit(NotificationPreferenceEvent.NavigateToActivity(intent)) + _uiEvents.emit(NotificationPreferenceEvent.NavigateToActivity(intent)) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/compose/PrivacySettingsPreferenceScreen.kt b/app/src/main/java/org/thoughtcrime/securesms/preferences/compose/PrivacySettingsPreferenceScreen.kt index f3346c192a..bf0e8fa4a6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/preferences/compose/PrivacySettingsPreferenceScreen.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/compose/PrivacySettingsPreferenceScreen.kt @@ -55,7 +55,7 @@ fun PrivacySettingsPreferenceScreen( } LaunchedEffect(Unit) { - viewModel.events.collect { event -> + viewModel.uiEvents.collect { event -> when (event) { is OpenAppNotificationSettings -> { Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS) diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/compose/PrivacySettingsPreferenceViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/preferences/compose/PrivacySettingsPreferenceViewModel.kt index 9b515086ff..da63239f2f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/preferences/compose/PrivacySettingsPreferenceViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/compose/PrivacySettingsPreferenceViewModel.kt @@ -43,11 +43,11 @@ class PrivacySettingsPreferenceViewModel @Inject constructor( private val keyguardSecure = MutableStateFlow(true) - private val mutableEvents = MutableSharedFlow( + private val _uiEvents = MutableSharedFlow( replay = 1, extraBufferCapacity = 1 ) - val events get() = mutableEvents + val uiEvents get() = _uiEvents private val _uiState = MutableStateFlow(UIState()) val uiState: StateFlow = _uiState @@ -162,7 +162,7 @@ class PrivacySettingsPreferenceViewModel @Inject constructor( val index = prefItemsOrder.indexOf(keyToScroll) if (index >= 0) { delay(500L) // slight delay to make the transition less jarring - mutableEvents.tryEmit( + _uiEvents.tryEmit( PrivacySettingsPreferenceEvent.ScrollToIndex(index) ) } @@ -201,7 +201,7 @@ class PrivacySettingsPreferenceViewModel @Inject constructor( if (!uiState.value.screenLockEnabled) return prefs.setScreenLockEnabled(command.isEnabled) viewModelScope.launch { - mutableEvents.emit(PrivacySettingsPreferenceEvent.StartLockToggledService) + _uiEvents.emit(PrivacySettingsPreferenceEvent.StartLockToggledService) } } @@ -234,13 +234,13 @@ class PrivacySettingsPreferenceViewModel @Inject constructor( Commands.AskMicPermission -> { // Ask for permission viewModelScope.launch { - mutableEvents.emit(PrivacySettingsPreferenceEvent.AskMicrophonePermission) + _uiEvents.emit(PrivacySettingsPreferenceEvent.AskMicrophonePermission) } } Commands.NavigateToAppNotificationsSettings -> { viewModelScope.launch { - mutableEvents.emit(PrivacySettingsPreferenceEvent.OpenAppNotificationSettings) + _uiEvents.emit(PrivacySettingsPreferenceEvent.OpenAppNotificationSettings) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/ui/components/ExportLogsDialog.kt b/app/src/main/java/org/thoughtcrime/securesms/ui/components/ExportLogsDialog.kt index 7148c1e19d..f316caa18f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ui/components/ExportLogsDialog.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/ui/components/ExportLogsDialog.kt @@ -13,6 +13,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.retain.retain import androidx.compose.runtime.setValue import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource @@ -50,8 +51,7 @@ fun ExportLogsDialog( val context = LocalContext.current val scope = rememberCoroutineScope() - //todo use retain once in the dev branch - var exportingLogs by remember { mutableStateOf(false) } + var exportingLogs by retain { mutableStateOf(false) } if(exportingLogs){ LoadingDialog() diff --git a/app/src/main/res/layout/activity_fragment_wrapper.xml b/app/src/main/res/layout/activity_fragment_wrapper.xml deleted file mode 100644 index 216b135045..0000000000 --- a/app/src/main/res/layout/activity_fragment_wrapper.xml +++ /dev/null @@ -1,6 +0,0 @@ - - \ No newline at end of file diff --git a/app/src/main/res/xml/preferences_help.xml b/app/src/main/res/xml/preferences_help.xml deleted file mode 100644 index a05855c476..0000000000 --- a/app/src/main/res/xml/preferences_help.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/content-descriptions/src/main/res/values/strings.xml b/content-descriptions/src/main/res/values/strings.xml index 7f99d89f54..ae5b09f3bb 100644 --- a/content-descriptions/src/main/res/values/strings.xml +++ b/content-descriptions/src/main/res/values/strings.xml @@ -307,6 +307,14 @@ preferences-dialog-option-enable preferences-dialog-option-cancel + + preferences-option-export + preferences-option-translate + preferences-option-feedback + preferences-option-help + preferences-option-faq + + Navigate back Close Dialog