mirror of
https://github.com/oxen-io/session-android.git
synced 2025-02-19 20:38:27 +00:00
SES2397 - Fix display name change fail feedback (#1544)
* Added check to not update display name if offline or should config sync fail * Addressed PR feedback * WIP * Addressed PR feedback * Adjusted phrasing of log statement --------- Co-authored-by: alansley <aclansley@gmail.com>
This commit is contained in:
parent
1ca62629f6
commit
8a7f321ee0
@ -17,6 +17,7 @@ import org.session.libsession.messaging.contacts.Contact
|
||||
import org.session.libsession.utilities.Address
|
||||
import org.session.libsession.utilities.GroupUtil
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.session.libsignal.utilities.Log
|
||||
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
|
||||
import org.thoughtcrime.securesms.mms.GlideApp
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests
|
||||
@ -24,6 +25,8 @@ import org.thoughtcrime.securesms.mms.GlideRequests
|
||||
class ProfilePictureView @JvmOverloads constructor(
|
||||
context: Context, attrs: AttributeSet? = null
|
||||
) : RelativeLayout(context, attrs) {
|
||||
private val TAG = "ProfilePictureView"
|
||||
|
||||
private val binding = ViewProfilePictureBinding.inflate(LayoutInflater.from(context), this)
|
||||
private val glide: GlideRequests = GlideApp.with(this)
|
||||
var publicKey: String? = null
|
||||
@ -85,7 +88,7 @@ class ProfilePictureView @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
fun update() {
|
||||
val publicKey = publicKey ?: return
|
||||
val publicKey = publicKey ?: return Log.w(TAG, "Could not find public key to update profile picture")
|
||||
val additionalPublicKey = additionalPublicKey
|
||||
if (additionalPublicKey != null) {
|
||||
setProfilePictureIfNeeded(binding.doubleModeImageView1, publicKey, displayName)
|
||||
|
@ -56,6 +56,7 @@ import org.thoughtcrime.securesms.showSessionDialog
|
||||
import org.thoughtcrime.securesms.util.BitmapDecodingException
|
||||
import org.thoughtcrime.securesms.util.BitmapUtil
|
||||
import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities
|
||||
import org.thoughtcrime.securesms.util.NetworkUtils
|
||||
import org.thoughtcrime.securesms.util.disableClipping
|
||||
import org.thoughtcrime.securesms.util.push
|
||||
import org.thoughtcrime.securesms.util.show
|
||||
@ -179,7 +180,7 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
try {
|
||||
val profilePictureToBeUploaded = BitmapUtil.createScaledBytes(this@SettingsActivity, AvatarSelection.getResultUri(data), ProfileMediaConstraints()).bitmap
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
updateProfile(true, profilePictureToBeUploaded)
|
||||
updateProfilePicture(profilePictureToBeUploaded)
|
||||
}
|
||||
} catch (e: BitmapDecodingException) {
|
||||
e.printStackTrace()
|
||||
@ -228,56 +229,59 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateProfile(
|
||||
isUpdatingProfilePicture: Boolean,
|
||||
profilePicture: ByteArray? = null,
|
||||
displayName: String? = null
|
||||
) {
|
||||
private fun updateDisplayName(displayName: String): Boolean {
|
||||
binding.loader.isVisible = true
|
||||
|
||||
if (displayName != null) {
|
||||
TextSecurePreferences.setProfileName(this, displayName)
|
||||
configFactory.user?.setName(displayName)
|
||||
}
|
||||
// We'll assume we fail & flip the flag on success
|
||||
var updateWasSuccessful = false
|
||||
|
||||
// Bail if we're not updating the profile picture in any way
|
||||
if (!isUpdatingProfilePicture) return
|
||||
|
||||
val encodedProfileKey = ProfileKeyUtil.generateEncodedProfileKey(this)
|
||||
|
||||
val uploadProfilePicturePromise: Promise<*, Exception>
|
||||
var removingProfilePic = false
|
||||
|
||||
// Adding a new profile picture?
|
||||
if (profilePicture != null) {
|
||||
uploadProfilePicturePromise = ProfilePictureUtilities.upload(profilePicture, encodedProfileKey, this)
|
||||
val haveNetworkConnection = NetworkUtils.haveValidNetworkConnection(this@SettingsActivity);
|
||||
if (!haveNetworkConnection) {
|
||||
Log.w(TAG, "Cannot update display name - no network connection.")
|
||||
} else {
|
||||
// If not then we must be removing the existing one.
|
||||
// Note: To get a promise that will resolve / sync correctly we overwrite the existing profile picture with
|
||||
// a 0 byte image.
|
||||
removingProfilePic = true
|
||||
val emptyByteArray = ByteArray(0)
|
||||
uploadProfilePicturePromise = ProfilePictureUtilities.upload(emptyByteArray, encodedProfileKey, this)
|
||||
// if we have a network connection then attempt to update the display name
|
||||
TextSecurePreferences.setProfileName(this, displayName)
|
||||
val user = configFactory.user
|
||||
if (user == null) {
|
||||
Log.w(TAG, "Cannot update display name - missing user details from configFactory.")
|
||||
} else {
|
||||
user.setName(displayName)
|
||||
binding.btnGroupNameDisplay.text = displayName
|
||||
updateWasSuccessful = true
|
||||
}
|
||||
}
|
||||
|
||||
// If the upload picture promise succeeded then we hit this successUi block
|
||||
uploadProfilePicturePromise.successUi {
|
||||
// Inform the user if we failed to update the display name
|
||||
if (!updateWasSuccessful) {
|
||||
Toast.makeText(this@SettingsActivity, R.string.profileErrorUpdate, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
// If we successfully removed the profile picture on the network then we can clear the
|
||||
// local data - otherwise it's weird to fail the online section but it _looks_ like it
|
||||
// worked because we cleared the local image (also it denies them the chance to retry
|
||||
// removal if we do it locally, and may result in them having a visible profile picture
|
||||
// everywhere EXCEPT on their own device!).
|
||||
if (removingProfilePic) {
|
||||
binding.loader.isVisible = false
|
||||
return updateWasSuccessful
|
||||
}
|
||||
|
||||
// Helper method used by updateProfilePicture and removeProfilePicture to sync it online
|
||||
private fun syncProfilePicture(profilePicture: ByteArray, onFail: () -> Unit) {
|
||||
binding.loader.isVisible = true
|
||||
|
||||
// Grab the profile key and kick of the promise to update the profile picture
|
||||
val encodedProfileKey = ProfileKeyUtil.generateEncodedProfileKey(this)
|
||||
val updateProfilePicturePromise = ProfilePictureUtilities.upload(profilePicture, encodedProfileKey, this)
|
||||
|
||||
// If the online portion of the update succeeded then update the local state
|
||||
updateProfilePicturePromise.successUi {
|
||||
|
||||
// When removing the profile picture the supplied ByteArray is empty so we'll clear the local data
|
||||
if (profilePicture.isEmpty()) {
|
||||
MessagingModuleConfiguration.shared.storage.clearUserPic()
|
||||
}
|
||||
|
||||
val userConfig = configFactory.user
|
||||
AvatarHelper.setAvatar(this, Address.fromSerialized(TextSecurePreferences.getLocalNumber(this)!!), profilePicture)
|
||||
TextSecurePreferences.setProfileAvatarId(this, profilePicture?.let { SecureRandom().nextInt() } ?: 0 )
|
||||
TextSecurePreferences.setProfileAvatarId(this, profilePicture.let { SecureRandom().nextInt() } )
|
||||
ProfileKeyUtil.setEncodedProfileKey(this, encodedProfileKey)
|
||||
|
||||
// new config
|
||||
// Attempt to grab the details we require to update the profile picture
|
||||
val url = TextSecurePreferences.getProfilePictureURL(this)
|
||||
val profileKey = ProfileKeyUtil.getProfileKey(this)
|
||||
|
||||
@ -291,30 +295,52 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
}
|
||||
|
||||
ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(this@SettingsActivity)
|
||||
|
||||
// Update our visuals
|
||||
binding.profilePictureView.recycle()
|
||||
binding.profilePictureView.update()
|
||||
}
|
||||
|
||||
// Or if the promise failed to upload the new profile picture then we hit this failUi block
|
||||
uploadProfilePicturePromise.failUi {
|
||||
if (removingProfilePic) {
|
||||
Log.e(TAG, "Failed to remove profile picture")
|
||||
Toast.makeText(this@SettingsActivity, R.string.profileDisplayPictureRemoveError, Toast.LENGTH_LONG).show()
|
||||
} else {
|
||||
Log.e(TAG, "Failed to upload profile picture")
|
||||
Toast.makeText(this@SettingsActivity, R.string.profileErrorUpdate, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
// If the sync failed then inform the user
|
||||
updateProfilePicturePromise.failUi { onFail() }
|
||||
|
||||
// Finally, remove the loader animation after we've waited for the attempt to succeed or fail
|
||||
updateProfilePicturePromise.alwaysUi { binding.loader.isVisible = false }
|
||||
}
|
||||
|
||||
private fun updateProfilePicture(profilePicture: ByteArray) {
|
||||
|
||||
val haveNetworkConnection = NetworkUtils.haveValidNetworkConnection(this@SettingsActivity);
|
||||
if (!haveNetworkConnection) {
|
||||
Log.w(TAG, "Cannot update profile picture - no network connection.")
|
||||
Toast.makeText(this@SettingsActivity, R.string.profileErrorUpdate, Toast.LENGTH_LONG).show()
|
||||
return
|
||||
}
|
||||
|
||||
// Finally, regardless of whether the promise succeeded or failed, we always hit this `alwaysUi` block
|
||||
uploadProfilePicturePromise.alwaysUi {
|
||||
if (displayName != null) {
|
||||
binding.btnGroupNameDisplay.text = displayName
|
||||
}
|
||||
if (isUpdatingProfilePicture) {
|
||||
binding.profilePictureView.recycle() // Clear the cached image before updating
|
||||
binding.profilePictureView.update()
|
||||
}
|
||||
binding.loader.isVisible = false
|
||||
val onFail: () -> Unit = {
|
||||
Log.e(TAG, "Sync failed when uploading profile picture.")
|
||||
Toast.makeText(this@SettingsActivity, R.string.profileErrorUpdate, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
syncProfilePicture(profilePicture, onFail)
|
||||
}
|
||||
|
||||
private fun removeProfilePicture() {
|
||||
|
||||
val haveNetworkConnection = NetworkUtils.haveValidNetworkConnection(this@SettingsActivity);
|
||||
if (!haveNetworkConnection) {
|
||||
Log.w(TAG, "Cannot remove profile picture - no network connection.")
|
||||
Toast.makeText(this@SettingsActivity, R.string.profileDisplayPictureRemoveError, Toast.LENGTH_LONG).show()
|
||||
return
|
||||
}
|
||||
|
||||
val onFail: () -> Unit = {
|
||||
Log.e(TAG, "Sync failed when removing profile picture.")
|
||||
Toast.makeText(this@SettingsActivity, R.string.profileDisplayPictureRemoveError, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
val emptyProfilePicture = ByteArray(0)
|
||||
syncProfilePicture(emptyProfilePicture, onFail)
|
||||
}
|
||||
// endregion
|
||||
|
||||
@ -333,8 +359,7 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
Toast.makeText(this, R.string.activity_settings_display_name_too_long_error, Toast.LENGTH_SHORT).show()
|
||||
return false
|
||||
}
|
||||
updateProfile(false, displayName = displayName)
|
||||
return true
|
||||
return updateDisplayName(displayName)
|
||||
}
|
||||
|
||||
private fun showQRCode() {
|
||||
@ -348,7 +373,7 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
view(R.layout.dialog_change_avatar)
|
||||
button(R.string.activity_settings_upload) { startAvatarSelection() }
|
||||
if (TextSecurePreferences.getProfileAvatarId(context) != 0) {
|
||||
button(R.string.activity_settings_remove) { removeAvatar() }
|
||||
button(R.string.activity_settings_remove) { removeProfilePicture() }
|
||||
}
|
||||
cancelButton()
|
||||
}.apply {
|
||||
@ -366,10 +391,6 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeAvatar() {
|
||||
updateProfile(true)
|
||||
}
|
||||
|
||||
private fun startAvatarSelection() {
|
||||
// Ask for an optional camera permission.
|
||||
Permissions.with(this)
|
||||
|
Loading…
x
Reference in New Issue
Block a user