kopia lustrzana https://github.com/ryukoposting/Signal-Android
190 wiersze
7.1 KiB
Kotlin
190 wiersze
7.1 KiB
Kotlin
package org.thoughtcrime.securesms.avatar.picker
|
|
|
|
import android.content.Context
|
|
import android.net.Uri
|
|
import android.widget.Toast
|
|
import io.reactivex.rxjava3.core.Single
|
|
import org.signal.core.util.StreamUtil
|
|
import org.signal.core.util.ThreadUtil
|
|
import org.signal.core.util.concurrent.SignalExecutors
|
|
import org.signal.core.util.logging.Log
|
|
import org.thoughtcrime.securesms.R
|
|
import org.thoughtcrime.securesms.avatar.Avatar
|
|
import org.thoughtcrime.securesms.avatar.AvatarPickerStorage
|
|
import org.thoughtcrime.securesms.avatar.AvatarRenderer
|
|
import org.thoughtcrime.securesms.avatar.Avatars
|
|
import org.thoughtcrime.securesms.conversation.colors.AvatarColor
|
|
import org.thoughtcrime.securesms.database.DatabaseFactory
|
|
import org.thoughtcrime.securesms.groups.GroupId
|
|
import org.thoughtcrime.securesms.mediasend.Media
|
|
import org.thoughtcrime.securesms.profiles.AvatarHelper
|
|
import org.thoughtcrime.securesms.providers.BlobProvider
|
|
import org.thoughtcrime.securesms.recipients.Recipient
|
|
import org.thoughtcrime.securesms.util.NameUtil
|
|
import org.whispersystems.signalservice.api.util.StreamDetails
|
|
import java.io.IOException
|
|
|
|
private val TAG = Log.tag(AvatarPickerRepository::class.java)
|
|
|
|
class AvatarPickerRepository(context: Context) {
|
|
|
|
private val applicationContext = context.applicationContext
|
|
|
|
fun getAvatarForSelf(): Single<Avatar> = Single.fromCallable {
|
|
val details: StreamDetails? = AvatarHelper.getSelfProfileAvatarStream(applicationContext)
|
|
if (details != null) {
|
|
try {
|
|
val bytes = StreamUtil.readFully(details.stream)
|
|
Avatar.Photo(
|
|
BlobProvider.getInstance().forData(bytes).createForSingleSessionInMemory(),
|
|
details.length,
|
|
Avatar.DatabaseId.DoNotPersist
|
|
)
|
|
} catch (e: IOException) {
|
|
Log.w(TAG, "Failed to read avatar!")
|
|
getDefaultAvatarForSelf()
|
|
}
|
|
} else {
|
|
getDefaultAvatarForSelf()
|
|
}
|
|
}
|
|
|
|
fun getAvatarForGroup(groupId: GroupId): Single<Avatar> = Single.fromCallable {
|
|
val recipient = Recipient.externalGroupExact(applicationContext, groupId)
|
|
|
|
if (AvatarHelper.hasAvatar(applicationContext, recipient.id)) {
|
|
try {
|
|
val bytes = AvatarHelper.getAvatarBytes(applicationContext, recipient.id)
|
|
Avatar.Photo(
|
|
BlobProvider.getInstance().forData(bytes).createForSingleSessionInMemory(),
|
|
AvatarHelper.getAvatarLength(applicationContext, recipient.id),
|
|
Avatar.DatabaseId.DoNotPersist
|
|
)
|
|
} catch (e: IOException) {
|
|
Log.w(TAG, "Failed to read group avatar!")
|
|
getDefaultAvatarForGroup(recipient.avatarColor)
|
|
}
|
|
} else {
|
|
getDefaultAvatarForGroup(recipient.avatarColor)
|
|
}
|
|
}
|
|
|
|
fun getPersistedAvatarsForSelf(): Single<List<Avatar>> = Single.fromCallable {
|
|
DatabaseFactory.getAvatarPickerDatabase(applicationContext).getAvatarsForSelf()
|
|
}
|
|
|
|
fun getPersistedAvatarsForGroup(groupId: GroupId): Single<List<Avatar>> = Single.fromCallable {
|
|
DatabaseFactory.getAvatarPickerDatabase(applicationContext).getAvatarsForGroup(groupId)
|
|
}
|
|
|
|
fun getDefaultAvatarsForSelf(): Single<List<Avatar>> = Single.fromCallable {
|
|
Avatars.defaultAvatarsForSelf.entries.mapIndexed { index, entry ->
|
|
Avatar.Vector(entry.key, color = Avatars.colors[index % Avatars.colors.size], Avatar.DatabaseId.NotSet)
|
|
}
|
|
}
|
|
|
|
fun getDefaultAvatarsForGroup(): Single<List<Avatar>> = Single.fromCallable {
|
|
Avatars.defaultAvatarsForGroup.entries.mapIndexed { index, entry ->
|
|
Avatar.Vector(entry.key, color = Avatars.colors[index % Avatars.colors.size], Avatar.DatabaseId.NotSet)
|
|
}
|
|
}
|
|
|
|
fun writeMediaToMultiSessionStorage(media: Media, onMediaWrittenToMultiSessionStorage: (Uri) -> Unit) {
|
|
SignalExecutors.BOUNDED.execute {
|
|
onMediaWrittenToMultiSessionStorage(AvatarPickerStorage.save(applicationContext, media))
|
|
}
|
|
}
|
|
|
|
fun persistAvatarForSelf(avatar: Avatar, onPersisted: (Avatar) -> Unit) {
|
|
SignalExecutors.BOUNDED.execute {
|
|
val avatarDatabase = DatabaseFactory.getAvatarPickerDatabase(applicationContext)
|
|
val savedAvatar = avatarDatabase.saveAvatarForSelf(avatar)
|
|
avatarDatabase.markUsage(savedAvatar)
|
|
onPersisted(savedAvatar)
|
|
}
|
|
}
|
|
|
|
fun persistAvatarForGroup(avatar: Avatar, groupId: GroupId, onPersisted: (Avatar) -> Unit) {
|
|
SignalExecutors.BOUNDED.execute {
|
|
val avatarDatabase = DatabaseFactory.getAvatarPickerDatabase(applicationContext)
|
|
val savedAvatar = avatarDatabase.saveAvatarForGroup(avatar, groupId)
|
|
avatarDatabase.markUsage(savedAvatar)
|
|
onPersisted(savedAvatar)
|
|
}
|
|
}
|
|
|
|
fun persistAndCreateMediaForSelf(avatar: Avatar, onSaved: (Media) -> Unit) {
|
|
SignalExecutors.BOUNDED.execute {
|
|
if (avatar.databaseId !is Avatar.DatabaseId.DoNotPersist) {
|
|
persistAvatarForSelf(avatar) {
|
|
AvatarRenderer.renderAvatar(applicationContext, avatar, onSaved, this::handleRenderFailure)
|
|
}
|
|
} else {
|
|
AvatarRenderer.renderAvatar(applicationContext, avatar, onSaved, this::handleRenderFailure)
|
|
}
|
|
}
|
|
}
|
|
|
|
fun persistAndCreateMediaForGroup(avatar: Avatar, groupId: GroupId, onSaved: (Media) -> Unit) {
|
|
SignalExecutors.BOUNDED.execute {
|
|
if (avatar.databaseId !is Avatar.DatabaseId.DoNotPersist) {
|
|
persistAvatarForGroup(avatar, groupId) {
|
|
AvatarRenderer.renderAvatar(applicationContext, avatar, onSaved, this::handleRenderFailure)
|
|
}
|
|
} else {
|
|
AvatarRenderer.renderAvatar(applicationContext, avatar, onSaved, this::handleRenderFailure)
|
|
}
|
|
}
|
|
}
|
|
|
|
fun createMediaForNewGroup(avatar: Avatar, onSaved: (Media) -> Unit) {
|
|
SignalExecutors.BOUNDED.execute {
|
|
AvatarRenderer.renderAvatar(applicationContext, avatar, onSaved, this::handleRenderFailure)
|
|
}
|
|
}
|
|
|
|
fun handleRenderFailure(throwable: Throwable?) {
|
|
Log.w(TAG, "Failed to render avatar.", throwable)
|
|
ThreadUtil.postToMain {
|
|
Toast.makeText(applicationContext, R.string.AvatarPickerRepository__failed_to_save_avatar, Toast.LENGTH_SHORT).show()
|
|
}
|
|
}
|
|
|
|
fun getDefaultAvatarForSelf(): Avatar {
|
|
val initials = NameUtil.getAbbreviation(Recipient.self().getDisplayName(applicationContext))
|
|
|
|
return if (initials.isNullOrBlank()) {
|
|
Avatar.getDefaultForSelf()
|
|
} else {
|
|
Avatar.Text(initials, requireNotNull(Avatars.colorMap[Recipient.self().avatarColor.serialize()]), Avatar.DatabaseId.DoNotPersist)
|
|
}
|
|
}
|
|
|
|
fun getDefaultAvatarForGroup(groupId: GroupId): Avatar {
|
|
val recipient = Recipient.externalGroupExact(applicationContext, groupId)
|
|
|
|
return getDefaultAvatarForGroup(recipient.avatarColor)
|
|
}
|
|
|
|
fun getDefaultAvatarForGroup(color: AvatarColor?): Avatar {
|
|
val colorPair = Avatars.colorMap[color?.serialize()]
|
|
val defaultColor = Avatar.getDefaultForGroup()
|
|
|
|
return if (colorPair != null) {
|
|
defaultColor.copy(color = colorPair)
|
|
} else {
|
|
defaultColor
|
|
}
|
|
}
|
|
|
|
fun delete(avatar: Avatar, onDelete: () -> Unit) {
|
|
SignalExecutors.BOUNDED.execute {
|
|
if (avatar.databaseId is Avatar.DatabaseId.Saved) {
|
|
val avatarDatabase = DatabaseFactory.getAvatarPickerDatabase(applicationContext)
|
|
avatarDatabase.deleteAvatar(avatar)
|
|
}
|
|
onDelete()
|
|
}
|
|
}
|
|
}
|