Skip to content

Commit

Permalink
Fix dialog strings and refresh state for UP
Browse files Browse the repository at this point in the history
  • Loading branch information
valldrac committed Nov 29, 2024
1 parent 2a2b2cc commit 3d26e4d
Show file tree
Hide file tree
Showing 7 changed files with 37 additions and 118 deletions.
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
package im.molly.unifiedpush.components.settings.app.notifications

import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
Expand Down Expand Up @@ -48,7 +45,7 @@ fun MollySocketQrScanScreen(
) {
when (qrScanResult) {
QrScanResult.InvalidData -> {
QrScanResultDialog(message = stringResource(R.string.MollySocketLink_the_qr_code_was_invalid), onDismiss = onQrResultHandled)
QrScanResultDialog(message = stringResource(R.string.UsernameLinkSettings_qr_result_invalid), onDismiss = onQrResultHandled)
}

QrScanResult.NetworkError -> {
Expand Down Expand Up @@ -97,7 +94,7 @@ fun MollySocketQrScanScreen(
},
hasPermission = hasCameraPermission,
onRequestPermissions = onOpenCameraClicked,
qrHeaderLabelString = ""
qrHeaderLabelString = stringResource(R.string.MollySocketLink_scan_the_qr_code)
)
FloatingActionButton(
shape = CircleShape,
Expand All @@ -114,20 +111,6 @@ fun MollySocketQrScanScreen(
)
}
}

Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center
) {
Text(
text = stringResource(R.string.UsernameLinkSettings_qr_scan_description),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ class UnifiedPushSettingsFragment : DSLSettingsFragment(R.string.NotificationDel
private val qrScanLauncher: ActivityResultLauncher<Unit> =
registerForActivityResult(MollySocketQrScannerActivity.Contract()) { mollySocket ->
if (mollySocket != null) {
viewModel.initializeMollySocket(mollySocket)
viewModel.refresh()
viewModel.setMollySocket(mollySocket)
}
}

Expand All @@ -43,7 +42,7 @@ class UnifiedPushSettingsFragment : DSLSettingsFragment(R.string.NotificationDel

EventBus.getDefault().registerForLifecycle(subscriber = this, lifecycleOwner = viewLifecycleOwner)

viewModel.checkMollySocketFromStoredUrl()
viewModel.updateRegistration()
}

@Subscribe(threadMode = ThreadMode.MAIN)
Expand All @@ -58,19 +57,20 @@ class UnifiedPushSettingsFragment : DSLSettingsFragment(R.string.NotificationDel
summary = DSLSettingsText.from(getStatusSummary(state)),
)

textPref(
title = DSLSettingsText.from(R.string.UnifiedPushSettingsFragment__mollysocket_server_title),
clickPref(
title = DSLSettingsText.from(R.string.UnifiedPushSettingsFragment__mollysocket_server),
summary = DSLSettingsText.from(
if (state.airGapped) {
getString(R.string.UnifiedPushSettingsFragment__mollysocket_server_sumarry_air_gapped)
getString(R.string.UnifiedPushSettingsFragment__mollysocket_server_air_gapped)
} else {
state.mollySocketUrl ?: "Error"
}
)
),
onClick = {
qrScanLauncher.launch()
},
)

dividerPref()

if (state.distributors.isEmpty()) {
textPref(
title = DSLSettingsText.from(R.string.UnifiedPushSettingsFragment__distributor_app),
Expand All @@ -87,6 +87,8 @@ class UnifiedPushSettingsFragment : DSLSettingsFragment(R.string.NotificationDel
)
}

dividerPref()

if (state.airGapped) {
val parameters = getServerParameters(state) ?: ""

Expand Down Expand Up @@ -120,13 +122,6 @@ class UnifiedPushSettingsFragment : DSLSettingsFragment(R.string.NotificationDel
},
)
}
clickPref(
title = DSLSettingsText.from(getString(R.string.UnifiedPushSettingsFragment__change_mollysocket_configuration_title)),
summary = DSLSettingsText.from(getString(R.string.UnifiedPushSettingsFragment__change_mollysocket_configuration_summary)),
onClick = {
qrScanLauncher.launch()
},
)
}
}

Expand All @@ -142,6 +137,7 @@ class UnifiedPushSettingsFragment : DSLSettingsFragment(R.string.NotificationDel
return when {
state.distributors.isEmpty() -> R.string.UnifiedPushSettingsFragment__status_summary_no_distributor
state.selected == -1 -> R.string.UnifiedPushSettingsFragment__status_summary_distributor_not_selected
state.selectedNotAck -> R.string.UnifiedPushSettingsFragment__status_summary_missing_endpoint
state.endpoint == null -> R.string.UnifiedPushSettingsFragment__status_summary_missing_endpoint
state.mollySocketUrl == null && !state.airGapped -> R.string.UnifiedPushSettingsFragment__status_summary_mollysocket_url_missing
state.device == null -> R.string.UnifiedPushSettingsFragment__status_summary_linked_device_error
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ data class UnifiedPushSettingsState(
val registrationStatus: RegistrationStatus,
val distributors: List<Distributor>,
val selected: Int,
val selectedNotAck: Boolean,
val endpoint: String?,
val mollySocketUrl: String?,
val serverUnreachable: Boolean?,
)
Original file line number Diff line number Diff line change
Expand Up @@ -7,49 +7,33 @@ import android.widget.Toast
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import im.molly.unifiedpush.MollySocketRepository
import im.molly.unifiedpush.model.MollySocket
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import org.signal.core.util.ThreadUtil
import org.signal.core.util.concurrent.SignalExecutors
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.jobs.UnifiedPushRefreshJob
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.util.concurrent.SerialMonoLifoExecutor
import org.thoughtcrime.securesms.util.livedata.Store
import org.unifiedpush.android.connector.UnifiedPush

class UnifiedPushSettingsViewModel(private val application: Application) : ViewModel() {

private val store = Store(getState())
private val executor = SerialMonoLifoExecutor(SignalExecutors.UNBOUNDED)

private var serverUnreachable: Boolean? = null

val state: LiveData<UnifiedPushSettingsState> = store.stateLiveData

fun refresh() {
store.update { getState() }
}

fun initializeMollySocket(mollySocket: MollySocket) {
SignalStore.unifiedpush.apply {
airGapped = mollySocket is MollySocket.AirGapped
mollySocketUrl = (mollySocket as? MollySocket.WebServer)?.url
mollySocketVapid = mollySocket.vapid
}
}

private fun refreshAndUpdateRegistration(pingOnRegister: Boolean = false) {
refresh()
fun updateRegistration(pingOnRegister: Boolean = false) {
AppDependencies.jobManager.add(UnifiedPushRefreshJob(pingOnRegister))
}

private fun getState(): UnifiedPushSettingsState {
val distributorIds = UnifiedPush.getDistributors(application)
val saved = UnifiedPush.getSavedDistributor(application)
val ack = saved != null && UnifiedPush.getAckDistributor(application) == saved

val selected = distributorIds.indexOfFirst { it == saved }

Expand Down Expand Up @@ -82,75 +66,33 @@ class UnifiedPushSettingsViewModel(private val application: Application) : ViewM
registrationStatus = SignalStore.unifiedpush.registrationStatus,
distributors = distributors,
selected = selected,
selectedNotAck = !ack,
endpoint = SignalStore.unifiedpush.endpoint,
mollySocketUrl = mollySocketUrl,
serverUnreachable = serverUnreachable,
)
}

fun setUnifiedPushAirGapped(airGapped: Boolean) {
SignalStore.unifiedpush.lastReceivedTime = 0
SignalStore.unifiedpush.airGapped = airGapped
refreshAndUpdateRegistration()
}

fun setUnifiedPushDistributor(distributor: String) {
SignalStore.unifiedpush.endpoint = null
UnifiedPush.saveDistributor(application, distributor)
refreshAndUpdateRegistration()
}

fun setMollySocketUrl(url: String?): Boolean {
SignalStore.unifiedpush.lastReceivedTime = 0

val normalizedUrl = if (url?.lastOrNull() != '/') "$url/" else url ?: ""
val httpUrl = normalizedUrl.toHttpUrlOrNull()

return if (httpUrl != null) {
SignalStore.unifiedpush.mollySocketUrl = normalizedUrl
checkMollySocketServer(normalizedUrl)
true
} else {
SignalStore.unifiedpush.mollySocketUrl = null
serverUnreachable = null
false
}.also {
refresh()
}
}

fun checkMollySocketFromStoredUrl() {
checkMollySocketServer(SignalStore.unifiedpush.mollySocketUrl ?: return)
}

private fun checkMollySocketServer(url: String) {
executor.enqueue {
val found = runCatching {
MollySocketRepository.discoverMollySocketServer(url.toHttpUrl())
}.getOrElse { false }

// Update server reachability status
serverUnreachable = !found
refreshAndUpdateRegistration()

if (!found) {
showServerNotFoundToast()
}
}
refresh()
updateRegistration()
}

private fun showServerNotFoundToast() {
ThreadUtil.runOnMain {
Toast.makeText(
application,
R.string.UnifiedPushSettingsViewModel__mollysocket_server_not_found,
Toast.LENGTH_LONG
).show()
fun setMollySocket(mollySocket: MollySocket) {
SignalStore.unifiedpush.apply {
airGapped = mollySocket is MollySocket.AirGapped
lastReceivedTime = 0
mollySocketUrl = (mollySocket as? MollySocket.WebServer)?.url
mollySocketVapid = mollySocket.vapid
}
refresh()
updateRegistration()
}

fun pingMollySocket() {
refreshAndUpdateRegistration(pingOnRegister = true)
refresh()
updateRegistration(pingOnRegister = true)
}

class Factory(private val application: Application) : ViewModelProvider.Factory {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -428,8 +428,8 @@ class NotificationsSettingsFragment : DSLSettingsFragment(R.string.preferences__
if (method != previousMethod) {
MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.NotificationsSettingsFragment__mollysocket_server)
.setMessage(R.string.NotificationsSettingsFragment__to_use_unifiedpush_you_need_access_to_a_running_mollysocket)
.setPositiveButton(R.string.RegistrationActivity_i_understand) { _, _ ->
.setMessage(R.string.NotificationsSettingsFragment__to_use_unifiedpush_you_need_access_to_a_mollysocket_server)
.setPositiveButton(R.string.AddLinkDeviceFragment__scan_qr_code) { _, _ ->
qrScanLauncher.launch()
}
.setNegativeButton(R.string.RegistrationActivity_cancel, null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ class NotificationsSettingsViewModel(private val sharedPreferences: SharedPrefer
fun initializeMollySocket(mollySocket: MollySocket) {
SignalStore.unifiedpush.apply {
airGapped = mollySocket is MollySocket.AirGapped
lastReceivedTime = 0
mollySocketUrl = (mollySocket as? MollySocket.WebServer)?.url
mollySocketVapid = mollySocket.vapid
}
Expand Down
11 changes: 4 additions & 7 deletions app/src/main/res/values/strings2.xml
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@
<string name="NotificationsSettingsFragment__select_your_preferred_service_for_push_notifications">Select your preferred service for push notifications. If unavailable, the app will automatically use WebSocket to ensure notifications are delivered.</string>
<string name="NotificationsSettingsFragment__delivery_service">Delivery service</string>
<string name="NotificationsSettingsFragment__configure_unifiedpush">Configure UnifiedPush</string>
<string name="NotificationsSettingsFragment__to_use_unifiedpush_you_need_access_to_a_running_mollysocket">To use UnifiedPush, you need access to a running MollySocket server to link your Signal account.</string>
<string name="NotificationsSettingsFragment__to_use_unifiedpush_you_need_access_to_a_mollysocket_server">To use UnifiedPush, you need access to a MollySocket server to link your Signal account.\n\nStart by scanning the QR code provided by your server.</string>
<string name="NotificationsSettingsFragment__mollysocket_server">MollySocket server</string>
<string name="NotificationsSettingsFragment__not_selected">Not selected</string>
<string name="UnifiedPushSettingsFragment__none_available">None available</string>
Expand All @@ -154,7 +154,6 @@
<string name="UnifiedPushSettingsFragment__status_summary_forbidden_endpoint">The endpoint is forbidden by the server</string>
<string name="UnifiedPushSettingsFragment__status_summary_no_distributor">No UnifiedPush distributor installed</string>
<string name="UnifiedPushSettingsFragment__status_summary_distributor_not_selected">No distributor app selected</string>
<string name="UnifiedPushSettingsViewModel__mollysocket_server_not_found">"MollySocket server not found. Please check the URL and try again."</string>
<string name="UnifiedPushNotificationBuilder__mollysocket_device_limit_hit">You\'ve reached the limit of %d linked devices. To link your MollySocket server, please remove a device first.</string>
<string name="UnifiedPushNotificationBuilder__endpoint_changed_air_gapped">Your UnifiedPush endpoint has changed. You must update your connection on MollySocket.</string>
<string name="UnifiedPushNotificationBuilder__mollysocket_forbidden_password">Your registration on MollySocket is no longer valid. Please remove the linked device and try registering again.</string>
Expand All @@ -166,12 +165,10 @@
<string name="NotificationDeliveryMethod__fcm" translatable="false">FCM (Google Play Services)</string>
<string name="NotificationDeliveryMethod__websocket" translatable="false">WebSocket</string>
<string name="IncomingMessageObserver_websocket_service">WebSocket Service</string>
<string name="MollySocketLink_scan_the_qr_code">"Scan the QR code displayed on your MollySocket server's homepage or in the console.</string>
<string name="MollySocketLink_try_scanning_another_image_containing_a_mollysocket_qr_code">Try scanning another image containing a MollySocket QR code.</string>
<string name="MollySocketLink_the_qr_code_was_invalid">The QR code was invalid</string>
<string name="MollySocketLink_mollysocket_server_not_found_at_s">MollySocket server not found at \'%s\'</string>
<string name="MollySocketLink_experienced_a_network_error_please_try_again">Experienced a network error. Please try again.</string>
<string name="UnifiedPushSettingsFragment__change_mollysocket_configuration_title">Scan MollySocket QR Code</string>
<string name="UnifiedPushSettingsFragment__change_mollysocket_configuration_summary">Tap to scan and select a new MollySocket server</string>
<string name="UnifiedPushSettingsFragment__mollysocket_server_title">MollySocket server</string>
<string name="UnifiedPushSettingsFragment__mollysocket_server_sumarry_air_gapped">Air gapped</string>
<string name="UnifiedPushSettingsFragment__mollysocket_server">MollySocket server</string>
<string name="UnifiedPushSettingsFragment__mollysocket_server_air_gapped">Air gapped</string>
</resources>

0 comments on commit 3d26e4d

Please sign in to comment.