SES-2651 - New avatar picker
Updated the avatar picker to match the designs. Had to rewrite it in Compose and moved the logic to the VM. We could moev the whole settings page to compose in another step now that we have the VM set up.pull/1659/head
parent
c6333384da
commit
c0bf015049
@ -1,45 +1,111 @@
|
||||
package org.session.libsession.utilities
|
||||
|
||||
import android.content.Context
|
||||
import nl.komponents.kovenant.Promise
|
||||
import nl.komponents.kovenant.deferred
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import okio.Buffer
|
||||
import org.session.libsession.avatars.AvatarHelper
|
||||
import org.session.libsession.messaging.file_server.FileServerApi
|
||||
import org.session.libsignal.streams.ProfileCipherOutputStream
|
||||
import org.session.libsignal.utilities.ProfileAvatarData
|
||||
import org.session.libsession.utilities.Address.Companion.fromSerialized
|
||||
import org.session.libsession.utilities.TextSecurePreferences.Companion.getLastProfilePictureUpload
|
||||
import org.session.libsession.utilities.TextSecurePreferences.Companion.getLocalNumber
|
||||
import org.session.libsession.utilities.TextSecurePreferences.Companion.getProfileKey
|
||||
import org.session.libsession.utilities.TextSecurePreferences.Companion.setLastProfilePictureUpload
|
||||
import org.session.libsignal.streams.DigestingRequestBody
|
||||
import org.session.libsignal.streams.ProfileCipherOutputStream
|
||||
import org.session.libsignal.streams.ProfileCipherOutputStreamFactory
|
||||
import org.session.libsignal.utilities.Log
|
||||
import org.session.libsignal.utilities.ProfileAvatarData
|
||||
import org.session.libsignal.utilities.ThreadUtils.queue
|
||||
import org.session.libsignal.utilities.retryIfNeeded
|
||||
import org.session.libsignal.utilities.ThreadUtils
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.util.*
|
||||
|
||||
object ProfilePictureUtilities {
|
||||
|
||||
fun upload(profilePicture: ByteArray, encodedProfileKey: String, context: Context): Promise<Unit, Exception> {
|
||||
val deferred = deferred<Unit, Exception>()
|
||||
ThreadUtils.queue {
|
||||
val inputStream = ByteArrayInputStream(profilePicture)
|
||||
val outputStream = ProfileCipherOutputStream.getCiphertextLength(profilePicture.size.toLong())
|
||||
val profileKey = ProfileKeyUtil.getProfileKeyFromEncodedString(encodedProfileKey)
|
||||
val pad = ProfileAvatarData(inputStream, outputStream, "image/jpeg", ProfileCipherOutputStreamFactory(profileKey))
|
||||
val drb = DigestingRequestBody(pad.data, pad.outputStreamFactory, pad.contentType, pad.dataLength, null)
|
||||
val b = Buffer()
|
||||
drb.writeTo(b)
|
||||
val data = b.readByteArray()
|
||||
var id: Long = 0
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
fun resubmitProfilePictureIfNeeded(context: Context) {
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
// Files expire on the file server after a while, so we simply re-upload the user's profile picture
|
||||
// at a certain interval to ensure it's always available.
|
||||
val userPublicKey = getLocalNumber(context) ?: return@launch
|
||||
val now = Date().time
|
||||
val lastProfilePictureUpload = getLastProfilePictureUpload(context)
|
||||
if (now - lastProfilePictureUpload <= 14 * 24 * 60 * 60 * 1000) return@launch
|
||||
|
||||
// Don't generate a new profile key here; we do that when the user changes their profile picture
|
||||
Log.d("Loki-Avatar", "Uploading Avatar Started")
|
||||
val encodedProfileKey =
|
||||
getProfileKey(context)
|
||||
try {
|
||||
id = retryIfNeeded(4) {
|
||||
FileServerApi.upload(data)
|
||||
}.get()
|
||||
// Read the file into a byte array
|
||||
val inputStream = AvatarHelper.getInputStreamFor(
|
||||
context,
|
||||
fromSerialized(userPublicKey)
|
||||
)
|
||||
val baos = ByteArrayOutputStream()
|
||||
var count: Int
|
||||
val buffer = ByteArray(1024)
|
||||
while ((inputStream.read(buffer, 0, buffer.size)
|
||||
.also { count = it }) != -1
|
||||
) {
|
||||
baos.write(buffer, 0, count)
|
||||
}
|
||||
baos.flush()
|
||||
val profilePicture = baos.toByteArray()
|
||||
// Re-upload it
|
||||
upload(
|
||||
profilePicture,
|
||||
encodedProfileKey!!,
|
||||
context
|
||||
)
|
||||
|
||||
// Update the last profile picture upload date
|
||||
setLastProfilePictureUpload(
|
||||
context,
|
||||
Date().time
|
||||
)
|
||||
|
||||
Log.d("Loki-Avatar", "Uploading Avatar Finished")
|
||||
} catch (e: Exception) {
|
||||
deferred.reject(e)
|
||||
Log.e("Loki-Avatar", "Uploading avatar failed.")
|
||||
}
|
||||
TextSecurePreferences.setLastProfilePictureUpload(context, Date().time)
|
||||
val url = "${FileServerApi.server}/file/$id"
|
||||
TextSecurePreferences.setProfilePictureURL(context, url)
|
||||
deferred.resolve(Unit)
|
||||
}
|
||||
return deferred.promise
|
||||
}
|
||||
|
||||
suspend fun upload(profilePicture: ByteArray, encodedProfileKey: String, context: Context) {
|
||||
val inputStream = ByteArrayInputStream(profilePicture)
|
||||
val outputStream =
|
||||
ProfileCipherOutputStream.getCiphertextLength(profilePicture.size.toLong())
|
||||
val profileKey = ProfileKeyUtil.getProfileKeyFromEncodedString(encodedProfileKey)
|
||||
val pad = ProfileAvatarData(
|
||||
inputStream,
|
||||
outputStream,
|
||||
"image/jpeg",
|
||||
ProfileCipherOutputStreamFactory(profileKey)
|
||||
)
|
||||
val drb = DigestingRequestBody(
|
||||
pad.data,
|
||||
pad.outputStreamFactory,
|
||||
pad.contentType,
|
||||
pad.dataLength,
|
||||
null
|
||||
)
|
||||
val b = Buffer()
|
||||
drb.writeTo(b)
|
||||
val data = b.readByteArray()
|
||||
var id: Long = 0
|
||||
|
||||
// this can throw an error
|
||||
id = retryIfNeeded(4) {
|
||||
FileServerApi.upload(data)
|
||||
}.get()
|
||||
|
||||
TextSecurePreferences.setLastProfilePictureUpload(context, Date().time)
|
||||
val url = "${FileServerApi.server}/file/$id"
|
||||
TextSecurePreferences.setProfilePictureURL(context, url)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue