package org.tm.archive.wallpaper; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.Transformations; import androidx.lifecycle.ViewModel; import androidx.lifecycle.ViewModelProvider; import com.annimon.stream.Stream; import org.tm.archive.conversation.colors.AvatarColor; import org.tm.archive.conversation.colors.ChatColors; import org.tm.archive.keyvalue.SignalStore; import org.tm.archive.recipients.LiveRecipient; import org.tm.archive.recipients.Recipient; import org.tm.archive.recipients.RecipientForeverObserver; import org.tm.archive.recipients.RecipientId; import org.tm.archive.util.DefaultValueLiveData; import org.tm.archive.util.adapter.mapping.MappingModel; import org.tm.archive.util.livedata.LiveDataUtil; import java.util.List; import java.util.Objects; import java.util.Optional; public class ChatWallpaperViewModel extends ViewModel { private final ChatWallpaperRepository repository = new ChatWallpaperRepository(); private final MutableLiveData> wallpaper = new MutableLiveData<>(); private final MutableLiveData> builtins = new MutableLiveData<>(); private final MutableLiveData dimInDarkTheme = new MutableLiveData<>(); private final MutableLiveData enableWallpaperControls = new MutableLiveData<>(); private final MutableLiveData chatColors = new MutableLiveData<>(); private final RecipientId recipientId; private final LiveRecipient liveRecipient; private final RecipientForeverObserver recipientObserver = r -> refreshChatColors(); private final LiveData wallpaperPreviewPortrait; private ChatWallpaperViewModel(@Nullable RecipientId recipientId) { this.recipientId = recipientId; ChatWallpaper currentWallpaper = repository.getCurrentWallpaper(recipientId); dimInDarkTheme.setValue(currentWallpaper == null || currentWallpaper.getDimLevelForDarkTheme() > 0f); enableWallpaperControls.setValue(hasClearableWallpaper()); wallpaper.setValue(Optional.ofNullable(currentWallpaper)); if (recipientId != null) { liveRecipient = Recipient.live(recipientId); liveRecipient.observeForever(recipientObserver); wallpaperPreviewPortrait = Transformations.map(liveRecipient.getLiveData(), recipient -> { if (recipient.getContactPhoto() != null) { return new WallpaperPreviewPortrait.ContactPhoto(recipient); } else { return new WallpaperPreviewPortrait.SolidColor(recipient.getAvatarColor()); } }); } else { liveRecipient = null; wallpaperPreviewPortrait = new DefaultValueLiveData<>(new WallpaperPreviewPortrait.SolidColor(AvatarColor.A100)); } } @Override protected void onCleared() { if (liveRecipient != null) { liveRecipient.removeForeverObserver(recipientObserver); } } void refreshWallpaper() { repository.getAllWallpaper(builtins::postValue); } void refreshChatColors() { chatColors.postValue(repository.getCurrentChatColors(recipientId)); } void setDimInDarkTheme(boolean shouldDimInDarkTheme) { dimInDarkTheme.setValue(shouldDimInDarkTheme); Optional wallpaper = this.wallpaper.getValue(); if (wallpaper.isPresent()) { repository.setDimInDarkTheme(recipientId, shouldDimInDarkTheme); } } void setWallpaper(@Nullable ChatWallpaper chatWallpaper) { wallpaper.setValue(Optional.ofNullable(chatWallpaper)); } void saveWallpaperSelection() { Optional wallpaper = this.wallpaper.getValue(); boolean dimInDarkTheme = this.dimInDarkTheme.getValue(); if (!wallpaper.isPresent()) { repository.saveWallpaper(recipientId, null, this::refreshChatColors); if (recipientId != null) { ChatWallpaper globalWallpaper = SignalStore.wallpaper().getWallpaper(); this.wallpaper.setValue(Optional.ofNullable(globalWallpaper)); this.dimInDarkTheme.setValue(globalWallpaper == null || globalWallpaper.getDimLevelForDarkTheme() > 0); } enableWallpaperControls.setValue(false); return; } else { enableWallpaperControls.setValue(true); } Optional updated = wallpaper.map(paper -> ChatWallpaperFactory.updateWithDimming(paper, dimInDarkTheme ? ChatWallpaper.FIXED_DIM_LEVEL_FOR_DARK_THEME : 0f)); if (updated.isPresent()) { repository.saveWallpaper(recipientId, updated.get(), this::refreshChatColors); } } void resetAllWallpaper() { repository.resetAllWallpaper(this::refreshChatColors); } @Nullable RecipientId getRecipientId() { return recipientId; } @NonNull LiveData> getCurrentWallpaper() { return wallpaper; } @NonNull LiveData getCurrentChatColors() { return chatColors; } @NonNull LiveData getWallpaperPreviewPortrait() { return wallpaperPreviewPortrait; } @NonNull LiveData>> getWallpapers() { return LiveDataUtil.combineLatest(builtins, dimInDarkTheme, (wallpapers, dimInDarkMode) -> Stream.of(wallpapers) .map(paper -> ChatWallpaperFactory.updateWithDimming(paper, dimInDarkMode ? ChatWallpaper.FIXED_DIM_LEVEL_FOR_DARK_THEME : 0f)) .>map(ChatWallpaperSelectionMappingModel::new).toList() ); } @NonNull LiveData getDimInDarkTheme() { return dimInDarkTheme; } @NonNull LiveData getEnableWallpaperControls() { return enableWallpaperControls; } boolean isGlobal() { return recipientId == null; } void clearChatColor() { repository.clearChatColor(recipientId, this::refreshChatColors); } private boolean hasClearableWallpaper() { return (isGlobal() && SignalStore.wallpaper().hasWallpaperSet()) || (recipientId != null && Recipient.live(recipientId).get().hasOwnWallpaper()); } public void resetAllChatColors() { repository.resetAllChatColors(this::refreshChatColors); } public static class Factory implements ViewModelProvider.Factory { private final RecipientId recipientId; public Factory(@Nullable RecipientId recipientId) { this.recipientId = recipientId; } @Override public @NonNull T create(@NonNull Class modelClass) { return Objects.requireNonNull(modelClass.cast(new ChatWallpaperViewModel(recipientId))); } } }