Improve wallpaper settings screen, conversation rendering.

Co-authored-by: Greyson Parrelli <greyson@signal.org>
This commit is contained in:
Alex Hart
2021-01-19 21:54:10 -05:00
committed by Greyson Parrelli
parent 6bcb0de43d
commit b5712f4bd1
63 changed files with 1100 additions and 307 deletions

View File

@@ -12,20 +12,31 @@ import java.util.List;
public interface ChatWallpaper extends Parcelable {
List<ChatWallpaper> BUILTINS = Arrays.asList(GradientChatWallpaper.SOLID_1,
GradientChatWallpaper.SOLID_2,
GradientChatWallpaper.SOLID_3,
GradientChatWallpaper.SOLID_4,
GradientChatWallpaper.SOLID_5,
GradientChatWallpaper.SOLID_6,
GradientChatWallpaper.SOLID_7,
GradientChatWallpaper.SOLID_8,
GradientChatWallpaper.SOLID_9,
GradientChatWallpaper.SOLID_10,
GradientChatWallpaper.SOLID_11,
GradientChatWallpaper.SOLID_12,
float FIXED_DIM_LEVEL_FOR_DARK_THEME = 0.2f;
List<ChatWallpaper> BUILTINS = Arrays.asList(SingleColorChatWallpaper.SOLID_1,
SingleColorChatWallpaper.SOLID_2,
SingleColorChatWallpaper.SOLID_3,
SingleColorChatWallpaper.SOLID_4,
SingleColorChatWallpaper.SOLID_5,
SingleColorChatWallpaper.SOLID_6,
SingleColorChatWallpaper.SOLID_7,
SingleColorChatWallpaper.SOLID_8,
SingleColorChatWallpaper.SOLID_9,
SingleColorChatWallpaper.SOLID_10,
SingleColorChatWallpaper.SOLID_11,
SingleColorChatWallpaper.SOLID_12,
GradientChatWallpaper.GRADIENT_1,
GradientChatWallpaper.GRADIENT_2);
GradientChatWallpaper.GRADIENT_2,
GradientChatWallpaper.GRADIENT_3,
GradientChatWallpaper.GRADIENT_4,
GradientChatWallpaper.GRADIENT_5,
GradientChatWallpaper.GRADIENT_6,
GradientChatWallpaper.GRADIENT_7,
GradientChatWallpaper.GRADIENT_8,
GradientChatWallpaper.GRADIENT_9);
float getDimLevelForDarkTheme();
void loadInto(@NonNull ImageView imageView);

View File

@@ -14,6 +14,7 @@ import androidx.navigation.Navigation;
import org.thoughtcrime.securesms.PassphraseRequiredActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.ActivityTransitionUtil;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.util.DynamicTheme;
@@ -23,11 +24,11 @@ public final class ChatWallpaperActivity extends PassphraseRequiredActivity {
private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme();
public static @NonNull Intent getIntent(@NonNull Context context) {
return getIntent(context, null);
public static @NonNull Intent createIntent(@NonNull Context context) {
return createIntent(context, null);
}
public static @NonNull Intent getIntent(@NonNull Context context, @Nullable RecipientId recipientId) {
public static @NonNull Intent createIntent(@NonNull Context context, @Nullable RecipientId recipientId) {
Intent intent = new Intent(context, ChatWallpaperActivity.class);
intent.putExtra(EXTRA_RECIPIENT_ID, recipientId);
return intent;
@@ -35,8 +36,7 @@ public final class ChatWallpaperActivity extends PassphraseRequiredActivity {
@Override
protected void onCreate(Bundle savedInstanceState, boolean ready) {
ChatWallpaperViewModel.Factory factory = new ChatWallpaperViewModel.Factory(getIntent(this).getParcelableExtra(EXTRA_RECIPIENT_ID));
ChatWallpaperViewModel.Factory factory = new ChatWallpaperViewModel.Factory(getIntent().getParcelableExtra(EXTRA_RECIPIENT_ID));
ViewModelProviders.of(this, factory).get(ChatWallpaperViewModel.class);
dynamicTheme.onCreate(this);
@@ -47,6 +47,7 @@ public final class ChatWallpaperActivity extends PassphraseRequiredActivity {
toolbar.setNavigationOnClickListener(unused -> {
if (!Navigation.findNavController(this, R.id.nav_host_fragment).popBackStack()) {
finish();
ActivityTransitionUtil.setSlideOutTransition(this);
}
});
@@ -58,6 +59,12 @@ public final class ChatWallpaperActivity extends PassphraseRequiredActivity {
}
}
@Override
public void onBackPressed() {
super.onBackPressed();
ActivityTransitionUtil.setSlideOutTransition(this);
}
@Override
protected void onResume() {
super.onResume();

View File

@@ -0,0 +1,22 @@
package org.thoughtcrime.securesms.wallpaper;
import android.view.View;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.util.ThemeUtil;
public final class ChatWallpaperDimLevelUtil {
private ChatWallpaperDimLevelUtil() {
}
public static void applyDimLevelForNightMode(@NonNull View dimmer, @NonNull ChatWallpaper chatWallpaper) {
if (ThemeUtil.isDarkTheme(dimmer.getContext())) {
dimmer.setAlpha(chatWallpaper.getDimLevelForDarkTheme());
dimmer.setVisibility(View.VISIBLE);
} else {
dimmer.setVisibility(View.GONE);
}
}
}

View File

@@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.wallpaper;
import android.net.Uri;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.database.model.databaseprotos.Wallpaper;
@@ -9,25 +10,37 @@ import org.thoughtcrime.securesms.database.model.databaseprotos.Wallpaper;
/**
* Converts persisted models of wallpaper into usable {@link ChatWallpaper} instances.
*/
public class ChatWallpaperFactory {
public final class ChatWallpaperFactory {
private ChatWallpaperFactory() {}
public static @NonNull ChatWallpaper create(@NonNull Wallpaper model) {
if (model.hasSingleColor()) {
return new GradientChatWallpaper(model.getSingleColor().getColor());
return buildForSingleColor(model.getSingleColor(), model.getDimLevelInDarkTheme());
} else if (model.hasLinearGradient()) {
return buildForLinearGradinent(model.getLinearGradient());
return buildForLinearGradinent(model.getLinearGradient(), model.getDimLevelInDarkTheme());
} else if (model.hasFile()) {
return buildForFile(model.getFile());
return buildForFile(model.getFile(), model.getDimLevelInDarkTheme());
} else {
throw new IllegalArgumentException();
}
}
public static @NonNull ChatWallpaper create(@NonNull Uri uri) {
return new UriChatWallpaper(uri);
public static @NonNull ChatWallpaper updateWithDimming(@NonNull ChatWallpaper wallpaper, float dimLevelInDarkTheme) {
Wallpaper model = wallpaper.serialize();
return create(model.toBuilder().setDimLevelInDarkTheme(dimLevelInDarkTheme).build());
}
private static @NonNull ChatWallpaper buildForLinearGradinent(@NonNull Wallpaper.LinearGradient gradient) {
public static @NonNull ChatWallpaper create(@NonNull Uri uri) {
return new UriChatWallpaper(uri, 0f);
}
private static @NonNull ChatWallpaper buildForSingleColor(@NonNull Wallpaper.SingleColor singleColor, float dimLevelInDarkTheme) {
return new SingleColorChatWallpaper(singleColor.getColor(), dimLevelInDarkTheme);
}
private static @NonNull ChatWallpaper buildForLinearGradinent(@NonNull Wallpaper.LinearGradient gradient, float dimLevelInDarkTheme) {
int[] colors = new int[gradient.getColorsCount()];
for (int i = 0; i < colors.length; i++) {
colors[i] = gradient.getColors(i);
@@ -38,11 +51,11 @@ public class ChatWallpaperFactory {
positions[i] = gradient.getPositions(i);
}
return new GradientChatWallpaper(gradient.getRotation(), colors, positions);
return new GradientChatWallpaper(gradient.getRotation(), colors, positions, dimLevelInDarkTheme);
}
private static @NonNull ChatWallpaper buildForFile(@NonNull Wallpaper.File file) {
private static @NonNull ChatWallpaper buildForFile(@NonNull Wallpaper.File file, float dimLevelInDarkTheme) {
Uri uri = Uri.parse(file.getUri());
return new UriChatWallpaper(uri);
return new UriChatWallpaper(uri, dimLevelInDarkTheme);
}
}

View File

@@ -8,12 +8,14 @@ import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.SwitchCompat;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProviders;
import androidx.navigation.Navigation;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.ThemeUtil;
public class ChatWallpaperFragment extends Fragment {
@Override
@@ -26,18 +28,48 @@ public class ChatWallpaperFragment extends Fragment {
ChatWallpaperViewModel viewModel = ViewModelProviders.of(requireActivity()).get(ChatWallpaperViewModel.class);
ImageView chatWallpaperPreview = view.findViewById(R.id.chat_wallpaper_preview_background);
View setWallpaper = view.findViewById(R.id.chat_wallpaper_set_wallpaper);
viewModel.setWallpaper(GradientChatWallpaper.GRADIENT_1);
SwitchCompat dimInNightMode = view.findViewById(R.id.chat_wallpaper_dark_theme_dims_wallpaper);
View chatWallpaperDim = view.findViewById(R.id.chat_wallpaper_dim);
View clearWallpaper = view.findViewById(R.id.chat_wallpaper_clear_wallpaper);
View resetAllWallpaper = view.findViewById(R.id.chat_wallpaper_reset_all_wallpapers);
viewModel.getCurrentWallpaper().observe(getViewLifecycleOwner(), wallpaper -> {
if (wallpaper.isPresent()) {
wallpaper.get().loadInto(chatWallpaperPreview);
} else {
chatWallpaperPreview.setImageDrawable(null);
chatWallpaperPreview.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.signal_background_primary));
}
dimInNightMode.setEnabled(wallpaper.isPresent());
});
viewModel.getDimInDarkTheme().observe(getViewLifecycleOwner(), shouldDimInNightMode -> {
if (shouldDimInNightMode != dimInNightMode.isChecked()) {
dimInNightMode.setChecked(shouldDimInNightMode);
}
chatWallpaperDim.setAlpha(ChatWallpaper.FIXED_DIM_LEVEL_FOR_DARK_THEME);
chatWallpaperDim.setVisibility(shouldDimInNightMode && ThemeUtil.isDarkTheme(requireContext()) ? View.VISIBLE : View.GONE);
});
setWallpaper.setOnClickListener(unused -> Navigation.findNavController(view)
.navigate(R.id.action_chatWallpaperFragment_to_chatWallpaperSelectionFragment));
clearWallpaper.setOnClickListener(unused -> {
viewModel.setWallpaper(null);
viewModel.setDimInDarkTheme(false);
viewModel.saveWallpaperSelection();
});
resetAllWallpaper.setVisibility(viewModel.isGlobal() ? View.VISIBLE : View.GONE);
resetAllWallpaper.setOnClickListener(unused -> {
viewModel.setWallpaper(null);
viewModel.setDimInDarkTheme(false);
viewModel.resetAllWallpaper();
});
dimInNightMode.setOnCheckedChangeListener((buttonView, isChecked) -> viewModel.setDimInDarkTheme(isChecked));
}
}

View File

@@ -8,30 +8,33 @@ import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.Toolbar;
import androidx.lifecycle.ViewModelProviders;
import androidx.viewpager2.widget.ViewPager2;
import com.annimon.stream.Stream;
import org.thoughtcrime.securesms.PassphraseRequiredActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.ActivityTransitionUtil;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.FullscreenHelper;
import org.thoughtcrime.securesms.util.MappingModel;
import java.util.Collections;
public class ChatWallpaperPreviewActivity extends PassphraseRequiredActivity {
private static final String EXTRA_CHAT_WALLPAPER = "extra.chat.wallpaper";
private static final String EXTRA_RECIPIENT_ID = "extra.recipient.id";
public static final String EXTRA_CHAT_WALLPAPER = "extra.chat.wallpaper";
private static final String EXTRA_DIM_IN_DARK_MODE = "extra.dim.in.dark.mode";
private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme();
public static @NonNull Intent create(@NonNull Context context, @NonNull ChatWallpaper selection, @Nullable RecipientId recipientId) {
public static @NonNull Intent create(@NonNull Context context, @NonNull ChatWallpaper selection, boolean dimInDarkMode) {
Intent intent = new Intent(context, ChatWallpaperPreviewActivity.class);
intent.putExtra(EXTRA_CHAT_WALLPAPER, selection);
intent.putExtra(EXTRA_RECIPIENT_ID, recipientId);
intent.putExtra(EXTRA_DIM_IN_DARK_MODE, dimInDarkMode);
return intent;
}
@@ -42,32 +45,43 @@ public class ChatWallpaperPreviewActivity extends PassphraseRequiredActivity {
setContentView(R.layout.chat_wallpaper_preview_activity);
ViewPager2 viewPager = findViewById(R.id.preview_pager);
ChatWallpaperPreviewAdapter adapter = new ChatWallpaperPreviewAdapter();
View submit = findViewById(R.id.preview_set_wallpaper);
ChatWallpaperViewModel.Factory factory = new ChatWallpaperViewModel.Factory(getIntent().getParcelableExtra(EXTRA_RECIPIENT_ID));
ChatWallpaperViewModel viewModel = ViewModelProviders.of(this, factory).get(ChatWallpaperViewModel.class);
ChatWallpaper selected = getIntent().getParcelableExtra(EXTRA_CHAT_WALLPAPER);
Toolbar toolbar = findViewById(R.id.toolbar);
ViewPager2 viewPager = findViewById(R.id.preview_pager);
ChatWallpaperPreviewAdapter adapter = new ChatWallpaperPreviewAdapter();
View submit = findViewById(R.id.preview_set_wallpaper);
ChatWallpaperRepository repository = new ChatWallpaperRepository();
ChatWallpaper selected = getIntent().getParcelableExtra(EXTRA_CHAT_WALLPAPER);
boolean dim = getIntent().getBooleanExtra(EXTRA_DIM_IN_DARK_MODE, false);
Toolbar toolbar = findViewById(R.id.toolbar);
toolbar.setNavigationOnClickListener(unused -> finish());
toolbar.setNavigationOnClickListener(unused -> {
finish();
ActivityTransitionUtil.setSlideOutTransition(this);
});
viewPager.setAdapter(adapter);
adapter.submitList(Collections.singletonList(new ChatWallpaperSelectionMappingModel(selected)));
viewModel.getWallpapers().observe(this, adapter::submitList);
repository.getAllWallpaper(wallpapers -> adapter.submitList(Stream.of(wallpapers)
.map(wallpaper -> ChatWallpaperFactory.updateWithDimming(wallpaper, dim ? 1f : 0f))
.<MappingModel<?>>map(ChatWallpaperSelectionMappingModel::new)
.toList()));
submit.setOnClickListener(unused -> {
ChatWallpaperSelectionMappingModel model = (ChatWallpaperSelectionMappingModel) adapter.getCurrentList().get(viewPager.getCurrentItem());
viewModel.saveWallpaperSelection(model.getWallpaper());
setResult(RESULT_OK);
setResult(RESULT_OK, new Intent().putExtra(EXTRA_CHAT_WALLPAPER, model.getWallpaper()));
finish();
});
new FullscreenHelper(this).showSystemUI();
}
@Override
public void onBackPressed() {
super.onBackPressed();
ActivityTransitionUtil.setSlideOutTransition(this);
}
@Override
protected void onResume() {
super.onResume();

View File

@@ -1,14 +1,64 @@
package org.thoughtcrime.securesms.wallpaper;
import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.util.Consumer;
import org.signal.core.util.concurrent.SignalExecutors;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.concurrent.SerialExecutor;
import org.whispersystems.libsignal.util.guava.Optional;
import java.util.List;
import java.util.concurrent.Executor;
class ChatWallpaperRepository {
private static final Executor EXECUTOR = new SerialExecutor(SignalExecutors.BOUNDED);
@MainThread
@Nullable ChatWallpaper getCurrentWallpaper(@Nullable RecipientId recipientId) {
if (recipientId != null) {
return Recipient.resolved(recipientId).getWallpaper();
} else {
return SignalStore.wallpaper().getWallpaper();
}
}
void getAllWallpaper(@NonNull Consumer<List<ChatWallpaper>> consumer) {
consumer.accept(ChatWallpaper.BUILTINS);
}
void saveWallpaper(@Nullable RecipientId recipientId, @Nullable ChatWallpaper chatWallpaper) {
if (recipientId != null) {
//noinspection CodeBlock2Expr
EXECUTOR.execute(() -> {
DatabaseFactory.getRecipientDatabase(ApplicationDependencies.getApplication()).setWallpaper(recipientId, chatWallpaper);
});
} else {
SignalStore.wallpaper().setWallpaper(ApplicationDependencies.getApplication(), chatWallpaper);
}
}
void resetAllWallpaper() {
SignalStore.wallpaper().setWallpaper(ApplicationDependencies.getApplication(), null);
EXECUTOR.execute(() -> {
DatabaseFactory.getRecipientDatabase(ApplicationDependencies.getApplication()).resetAllWallpaper();
});
}
void setDimInDarkTheme(@NonNull RecipientId recipientId, boolean dimInDarkTheme) {
if (recipientId != null) {
EXECUTOR.execute(() -> {
DatabaseFactory.getRecipientDatabase(ApplicationDependencies.getApplication()).setDimWallpaperInDarkTheme(recipientId, dimInDarkTheme);
});
} else {
SignalStore.wallpaper().setDimInDarkTheme(dimInDarkTheme);
}
}
}

View File

@@ -19,6 +19,7 @@ import com.google.android.flexbox.FlexboxLayoutManager;
import com.google.android.flexbox.JustifyContent;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.ActivityTransitionUtil;
public class ChatWallpaperSelectionFragment extends Fragment {
@@ -45,7 +46,8 @@ public class ChatWallpaperSelectionFragment extends Fragment {
@SuppressWarnings("CodeBlock2Expr")
ChatWallpaperSelectionAdapter adapter = new ChatWallpaperSelectionAdapter(chatWallpaper -> {
startActivityForResult(ChatWallpaperPreviewActivity.create(requireActivity(), chatWallpaper, viewModel.getRecipientId()), PREVIEW);
startActivityForResult(ChatWallpaperPreviewActivity.create(requireActivity(), chatWallpaper, viewModel.getDimInDarkTheme().getValue()), PREVIEW);
ActivityTransitionUtil.setSlideInTransition(requireActivity());
});
flexboxLayoutManager.setJustifyContent(JustifyContent.SPACE_AROUND);
@@ -63,9 +65,15 @@ public class ChatWallpaperSelectionFragment extends Fragment {
if (uri == null || uri == Uri.EMPTY) {
throw new AssertionError("Should never have an empty uri.");
} else {
startActivityForResult(ChatWallpaperPreviewActivity.create(requireActivity(), new UriChatWallpaper(uri), viewModel.getRecipientId()), PREVIEW);
ChatWallpaper wallpaper = ChatWallpaperFactory.create(uri);
viewModel.setWallpaper(wallpaper);
viewModel.saveWallpaperSelection();
Navigation.findNavController(requireView()).popBackStack();
}
} else if (requestCode == PREVIEW && resultCode == Activity.RESULT_OK) {
} else if (requestCode == PREVIEW && resultCode == Activity.RESULT_OK && data != null) {
ChatWallpaper chatWallpaper = data.getParcelableExtra(ChatWallpaperPreviewActivity.EXTRA_CHAT_WALLPAPER);
viewModel.setWallpaper(chatWallpaper);
viewModel.saveWallpaperSelection();
Navigation.findNavController(requireView()).popBackStack();
} else {
super.onActivityResult(requestCode, resultCode, data);

View File

@@ -11,15 +11,18 @@ import androidx.recyclerview.widget.RecyclerView;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.MappingAdapter;
import org.thoughtcrime.securesms.util.MappingViewHolder;
import org.thoughtcrime.securesms.util.ThemeUtil;
class ChatWallpaperViewHolder extends MappingViewHolder<ChatWallpaperSelectionMappingModel> {
private final ImageView preview;
private final View dimmer;
private final EventListener eventListener;
public ChatWallpaperViewHolder(@NonNull View itemView, @Nullable EventListener eventListener) {
super(itemView);
this.preview = itemView.findViewById(R.id.chat_wallpaper_preview);
this.dimmer = itemView.findViewById(R.id.chat_wallpaper_dim);
this.eventListener = eventListener;
}
@@ -27,6 +30,8 @@ class ChatWallpaperViewHolder extends MappingViewHolder<ChatWallpaperSelectionMa
public void bind(@NonNull ChatWallpaperSelectionMappingModel model) {
model.loadInto(preview);
ChatWallpaperDimLevelUtil.applyDimLevelForNightMode(dimmer, model.getWallpaper());
if (eventListener != null) {
preview.setOnClickListener(unused -> {
if (getAdapterPosition() != RecyclerView.NO_POSITION) {

View File

@@ -4,7 +4,6 @@ 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;
@@ -12,6 +11,7 @@ import com.annimon.stream.Stream;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.MappingModel;
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
import org.whispersystems.libsignal.util.guava.Optional;
import java.util.List;
@@ -19,23 +19,52 @@ import java.util.Objects;
public class ChatWallpaperViewModel extends ViewModel {
private final ChatWallpaperRepository repository = new ChatWallpaperRepository();
private final MutableLiveData<Optional<ChatWallpaper>> wallpaper = new MutableLiveData<>();
private final MutableLiveData<List<ChatWallpaper>> builtins = new MutableLiveData<>();
private final ChatWallpaperRepository repository = new ChatWallpaperRepository();
private final MutableLiveData<Optional<ChatWallpaper>> wallpaper = new MutableLiveData<>();
private final MutableLiveData<List<ChatWallpaper>> builtins = new MutableLiveData<>();
private final MutableLiveData<Boolean> dimInDarkTheme = new MutableLiveData<>();
private final RecipientId recipientId;
private ChatWallpaperViewModel(@Nullable RecipientId recipientId) {
this.recipientId = recipientId;
ChatWallpaper currentWallpaper = repository.getCurrentWallpaper(recipientId);
dimInDarkTheme.setValue(currentWallpaper != null && currentWallpaper.getDimLevelForDarkTheme() > 0f);
wallpaper.setValue(Optional.fromNullable(currentWallpaper));
repository.getAllWallpaper(builtins::postValue);
}
void setDimInDarkTheme(boolean shouldDimInDarkTheme) {
dimInDarkTheme.setValue(shouldDimInDarkTheme);
Optional<ChatWallpaper> wallpaper = this.wallpaper.getValue();
if (wallpaper.isPresent()) {
repository.setDimInDarkTheme(recipientId, shouldDimInDarkTheme);
}
}
void setWallpaper(@Nullable ChatWallpaper chatWallpaper) {
wallpaper.setValue(Optional.fromNullable(chatWallpaper));
}
void saveWallpaperSelection(@NonNull ChatWallpaper selected) {
// TODO
void saveWallpaperSelection() {
Optional<ChatWallpaper> wallpaper = this.wallpaper.getValue();
boolean dimInDarkTheme = this.dimInDarkTheme.getValue();
if (!wallpaper.isPresent()) {
repository.saveWallpaper(recipientId, null);
return;
}
Optional<ChatWallpaper> updated = wallpaper.transform(paper -> ChatWallpaperFactory.updateWithDimming(paper, dimInDarkTheme ? ChatWallpaper.FIXED_DIM_LEVEL_FOR_DARK_THEME : 0f));
if (updated.isPresent()) {
repository.saveWallpaper(recipientId, updated.get());
}
}
void resetAllWallpaper() {
repository.resetAllWallpaper();
}
public @Nullable RecipientId getRecipientId() {
@@ -47,8 +76,19 @@ public class ChatWallpaperViewModel extends ViewModel {
}
LiveData<List<MappingModel<?>>> getWallpapers() {
return Transformations.map(Transformations.distinctUntilChanged(builtins),
wallpapers -> Stream.of(wallpapers).<MappingModel<?>>map(ChatWallpaperSelectionMappingModel::new).toList());
return LiveDataUtil.combineLatest(builtins, dimInDarkTheme, (wallpapers, dimInDarkMode) ->
Stream.of(wallpapers)
.map(paper -> ChatWallpaperFactory.updateWithDimming(paper, dimInDarkMode ? 1f : 0f))
.<MappingModel<?>>map(ChatWallpaperSelectionMappingModel::new).toList()
);
}
LiveData<Boolean> getDimInDarkTheme() {
return dimInDarkTheme;
}
boolean isGlobal() {
return recipientId == null;
}
public static class Factory implements ViewModelProvider.Factory {

View File

@@ -23,43 +23,61 @@ import java.util.Objects;
final class GradientChatWallpaper implements ChatWallpaper, Parcelable {
public static final GradientChatWallpaper SOLID_1 = new GradientChatWallpaper(0xFFE26983);
public static final GradientChatWallpaper SOLID_2 = new GradientChatWallpaper(0xFFDF9171);
public static final GradientChatWallpaper SOLID_3 = new GradientChatWallpaper(0xFF9E9887);
public static final GradientChatWallpaper SOLID_4 = new GradientChatWallpaper(0xFF89AE8F);
public static final GradientChatWallpaper SOLID_5 = new GradientChatWallpaper(0xFF32C7E2);
public static final GradientChatWallpaper SOLID_6 = new GradientChatWallpaper(0xFF7C99B6);
public static final GradientChatWallpaper SOLID_7 = new GradientChatWallpaper(0xFFC988E7);
public static final GradientChatWallpaper SOLID_8 = new GradientChatWallpaper(0xFFE297C3);
public static final GradientChatWallpaper SOLID_9 = new GradientChatWallpaper(0xFFA2A2AA);
public static final GradientChatWallpaper SOLID_10 = new GradientChatWallpaper(0xFF146148);
public static final GradientChatWallpaper SOLID_11 = new GradientChatWallpaper(0xFF403B91);
public static final GradientChatWallpaper SOLID_12 = new GradientChatWallpaper(0xFF624249);
public static final GradientChatWallpaper GRADIENT_1 = new GradientChatWallpaper(167.96f,
new int[] { 0xFFF3DC47, 0xFFF3DA47, 0xFFF2D546, 0xFFF2CC46, 0xFFF1C146, 0xFFEFB445, 0xFFEEA544, 0xFFEC9644, 0xFFEB8743, 0xFFE97743, 0xFFE86942, 0xFFE65C41, 0xFFE55041, 0xFFE54841, 0xFFE44240, 0xFFE44040 },
new float[] { 0.0f, 0.0807f, 0.1554f, 0.225f, 0.2904f, 0.3526f, 0.4125f, 0.471f, 0.529f, 0.5875f, 0.6474f, 0.7096f, 0.775f, 0.8446f, 0.9193f, 1f });
public static final GradientChatWallpaper GRADIENT_2 = new GradientChatWallpaper(180f,
new int[] { 0xFF16161D, 0xFF17171E, 0xFF1A1A22, 0xFF1F1F28, 0xFF26262F, 0xFF2D2D38, 0xFF353542, 0xFF3E3E4C, 0xFF474757, 0xFF4F4F61, 0xFF57576B, 0xFF5F5F74, 0xFF65657C, 0xFF6A6A82, 0xFF6D6D85, 0xFF6E6E87 },
new float[] { 0.0000f, 0.0807f, 0.1554f, 0.2250f, 0.2904f, 0.3526f, 0.4125f, 0.4710f, 0.5290f, 0.5875f, 0.6474f, 0.7096f, 0.7750f, 0.8446f, 0.9193f, 1.0000f });
public static final ChatWallpaper GRADIENT_1 = new GradientChatWallpaper(167.96f,
new int[] { 0xFFF3DC47, 0xFFF3DA47, 0xFFF2D546, 0xFFF2CC46, 0xFFF1C146, 0xFFEFB445, 0xFFEEA544, 0xFFEC9644, 0xFFEB8743, 0xFFE97743, 0xFFE86942, 0xFFE65C41, 0xFFE55041, 0xFFE54841, 0xFFE44240, 0xFFE44040 },
new float[] { 0.0f, 0.0807f, 0.1554f, 0.225f, 0.2904f, 0.3526f, 0.4125f, 0.471f, 0.529f, 0.5875f, 0.6474f, 0.7096f, 0.775f, 0.8446f, 0.9193f, 1f },
0f);
public static final ChatWallpaper GRADIENT_2 = new GradientChatWallpaper(180f,
new int[] { 0xFF16161D, 0xFF17171E, 0xFF1A1A22, 0xFF1F1F28, 0xFF26262F, 0xFF2D2D38, 0xFF353542, 0xFF3E3E4C, 0xFF474757, 0xFF4F4F61, 0xFF57576B, 0xFF5F5F74, 0xFF65657C, 0xFF6A6A82, 0xFF6D6D85, 0xFF6E6E87 },
new float[] { 0.0000f, 0.0807f, 0.1554f, 0.2250f, 0.2904f, 0.3526f, 0.4125f, 0.4710f, 0.5290f, 0.5875f, 0.6474f, 0.7096f, 0.7750f, 0.8446f, 0.9193f, 1.0000f },
0f);
public static final ChatWallpaper GRADIENT_3 = new GradientChatWallpaper(192.04f,
new int[] { 0xFFF53844, 0xFFF33845, 0xFFEC3848, 0xFFE2384C, 0xFFD63851, 0xFFC73857, 0xFFB6385E, 0xFFA43866, 0xFF93376D, 0xFF813775, 0xFF70377C, 0xFF613782, 0xFF553787, 0xFF4B378B, 0xFF44378E, 0xFF42378F },
new float[] { 0.0000f, 0.0075f, 0.0292f, 0.0637f, 0.1097f, 0.1659f, 0.2310f, 0.3037f, 0.3827f, 0.4666f, 0.5541f, 0.6439f, 0.7347f, 0.8252f, 0.9141f, 1.0000f },
0f);
public static final ChatWallpaper GRADIENT_4 = new GradientChatWallpaper(180f,
new int[] { 0xFF0093E9, 0xFF0294E9, 0xFF0696E7, 0xFF0D99E5, 0xFF169EE3, 0xFF21A3E0, 0xFF2DA8DD, 0xFF3AAEDA, 0xFF46B5D6, 0xFF53BBD3, 0xFF5FC0D0, 0xFF6AC5CD, 0xFF73CACB, 0xFF7ACDC9, 0xFF7ECFC7, 0xFF80D0C7 },
new float[] { 0.0000f, 0.0807f, 0.1554f, 0.2250f, 0.2904f, 0.3526f, 0.4125f, 0.4710f, 0.5290f, 0.5875f, 0.6474f, 0.7096f, 0.7750f, 0.8446f, 0.9193f, 1.0000f },
0f);
public static final ChatWallpaper GRADIENT_5 = new GradientChatWallpaper(192.04f,
new int[] { 0xFFF04CE6, 0xFFEE4BE6, 0xFFE54AE5, 0xFFD949E5, 0xFFC946E4, 0xFFB644E3, 0xFFA141E3, 0xFF8B3FE2, 0xFF743CE1, 0xFF5E39E0, 0xFF4936DF, 0xFF3634DE, 0xFF2632DD, 0xFF1930DD, 0xFF112FDD, 0xFF0E2FDD },
new float[] { 0.0000f, 0.0807f, 0.1554f, 0.2250f, 0.2904f, 0.3526f, 0.4125f, 0.4710f, 0.5290f, 0.5875f, 0.6474f, 0.7096f, 0.7750f, 0.8446f, 0.9193f, 1.0000f },
0f);
public static final ChatWallpaper GRADIENT_6 = new GradientChatWallpaper(180f,
new int[] { 0xFF65CDAC, 0xFF64CDAB, 0xFF60CBA8, 0xFF5BC8A3, 0xFF55C49D, 0xFF4DC096, 0xFF45BB8F, 0xFF3CB687, 0xFF33B17F, 0xFF2AAC76, 0xFF21A76F, 0xFF1AA268, 0xFF139F62, 0xFF0E9C5E, 0xFF0B9A5B, 0xFF0A995A },
new float[] { 0.0000f, 0.0807f, 0.1554f, 0.2250f, 0.2904f, 0.3526f, 0.4125f, 0.4710f, 0.5290f, 0.5875f, 0.6474f, 0.7096f, 0.7750f, 0.8446f, 0.9193f, 1.0000f },
0f);
public static final ChatWallpaper GRADIENT_7 = new GradientChatWallpaper(180f,
new int[] { 0xFFD8E1FA, 0xFFD8E0F9, 0xFFD8DEF7, 0xFFD8DBF3, 0xFFD8D6EE, 0xFFD7D1E8, 0xFFD7CCE2, 0xFFD7C6DB, 0xFFD7BFD4, 0xFFD7B9CD, 0xFFD6B4C7, 0xFFD6AFC1, 0xFFD6AABC, 0xFFD6A7B8, 0xFFD6A5B6, 0xFFD6A4B5 },
new float[] { 0.0000f, 0.0807f, 0.1554f, 0.2250f, 0.2904f, 0.3526f, 0.4125f, 0.4710f, 0.5290f, 0.5875f, 0.6474f, 0.7096f, 0.7750f, 0.8446f, 0.9193f, 1.0000f },
0f);
public static final ChatWallpaper GRADIENT_8 = new GradientChatWallpaper(180f,
new int[] { 0xFFD8EBFD, 0xFFD7EAFD, 0xFFD5E9FD, 0xFFD2E7FD, 0xFFCDE5FD, 0xFFC8E3FD, 0xFFC3E0FD, 0xFFBDDDFC, 0xFFB7DAFC, 0xFFB2D7FC, 0xFFACD4FC, 0xFFA7D1FC, 0xFFA3CFFB, 0xFFA0CDFB, 0xFF9ECCFB, 0xFF9DCCFB },
new float[] { 0.0000f, 0.0807f, 0.1554f, 0.2250f, 0.2904f, 0.3526f, 0.4125f, 0.4710f, 0.5290f, 0.5875f, 0.6474f, 0.7096f, 0.7750f, 0.8446f, 0.9193f, 1.0000f },
0f);
public static final ChatWallpaper GRADIENT_9 = new GradientChatWallpaper(192.04f,
new int[] { 0xFFFFE5C2, 0xFFFFE4C1, 0xFFFFE2BF, 0xFFFFDFBD, 0xFFFEDBB9, 0xFFFED6B5, 0xFFFED1B1, 0xFFFDCCAC, 0xFFFDC6A8, 0xFFFDC0A3, 0xFFFCBB9F, 0xFFFCB69B, 0xFFFCB297, 0xFFFCAF95, 0xFFFCAD93, 0xFFFCAC92 },
new float[] { 0.0000f, 0.0807f, 0.1554f, 0.2250f, 0.2904f, 0.3526f, 0.4125f, 0.4710f, 0.5290f, 0.5875f, 0.6474f, 0.7096f, 0.7750f, 0.8446f, 0.9193f, 1.0000f },
0f);
private final float degrees;
private final int[] colors;
private final float[] positions;
private final float dimLevelInDarkTheme;
GradientChatWallpaper(int color) {
this(0f, new int[]{color, color}, null);
}
GradientChatWallpaper(float degrees, int[] colors, float[] positions) {
this.degrees = degrees;
this.colors = colors;
this.positions = positions;
GradientChatWallpaper(float degrees, int[] colors, float[] positions, float dimLevelInDarkTheme) {
this.degrees = degrees;
this.colors = colors;
this.positions = positions;
this.dimLevelInDarkTheme = dimLevelInDarkTheme;
}
private GradientChatWallpaper(Parcel in) {
degrees = in.readFloat();
colors = in.createIntArray();
positions = in.createFloatArray();
degrees = in.readFloat();
colors = in.createIntArray();
positions = in.createFloatArray();
dimLevelInDarkTheme = in.readFloat();
}
@Override
@@ -67,6 +85,7 @@ final class GradientChatWallpaper implements ChatWallpaper, Parcelable {
dest.writeFloat(degrees);
dest.writeIntArray(colors);
dest.writeFloatArray(positions);
dest.writeFloat(dimLevelInDarkTheme);
}
@Override
@@ -78,6 +97,11 @@ final class GradientChatWallpaper implements ChatWallpaper, Parcelable {
return new RotatableGradientDrawable(degrees, colors, positions);
}
@Override
public float getDimLevelForDarkTheme() {
return dimLevelInDarkTheme;
}
@Override
public void loadInto(@NonNull ImageView imageView) {
imageView.setImageDrawable(buildDrawable());
@@ -99,6 +123,7 @@ final class GradientChatWallpaper implements ChatWallpaper, Parcelable {
return Wallpaper.newBuilder()
.setLinearGradient(builder)
.setDimLevelInDarkTheme(dimLevelInDarkTheme)
.build();
}
@@ -109,12 +134,13 @@ final class GradientChatWallpaper implements ChatWallpaper, Parcelable {
GradientChatWallpaper that = (GradientChatWallpaper) o;
return Float.compare(that.degrees, degrees) == 0 &&
Arrays.equals(colors, that.colors) &&
Arrays.equals(positions, that.positions);
Arrays.equals(positions, that.positions) &&
Float.compare(that.dimLevelInDarkTheme, dimLevelInDarkTheme) == 0;
}
@Override
public int hashCode() {
int result = Objects.hash(degrees);
int result = Objects.hash(degrees, dimLevelInDarkTheme);
result = 31 * result + Arrays.hashCode(colors);
result = 31 * result + Arrays.hashCode(positions);
return result;

View File

@@ -0,0 +1,100 @@
package org.thoughtcrime.securesms.wallpaper;
import android.graphics.drawable.ColorDrawable;
import android.os.Parcel;
import android.os.Parcelable;
import android.widget.ImageView;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.database.model.databaseprotos.Wallpaper;
import java.util.Objects;
final class SingleColorChatWallpaper implements ChatWallpaper, Parcelable {
public static final ChatWallpaper SOLID_1 = new SingleColorChatWallpaper(0xFFE26983, 0f);
public static final ChatWallpaper SOLID_2 = new SingleColorChatWallpaper(0xFFDF9171, 0f);
public static final ChatWallpaper SOLID_3 = new SingleColorChatWallpaper(0xFF9E9887, 0f);
public static final ChatWallpaper SOLID_4 = new SingleColorChatWallpaper(0xFF89AE8F, 0f);
public static final ChatWallpaper SOLID_5 = new SingleColorChatWallpaper(0xFF32C7E2, 0f);
public static final ChatWallpaper SOLID_6 = new SingleColorChatWallpaper(0xFF7C99B6, 0f);
public static final ChatWallpaper SOLID_7 = new SingleColorChatWallpaper(0xFFC988E7, 0f);
public static final ChatWallpaper SOLID_8 = new SingleColorChatWallpaper(0xFFE297C3, 0f);
public static final ChatWallpaper SOLID_9 = new SingleColorChatWallpaper(0xFFA2A2AA, 0f);
public static final ChatWallpaper SOLID_10 = new SingleColorChatWallpaper(0xFF146148, 0f);
public static final ChatWallpaper SOLID_11 = new SingleColorChatWallpaper(0xFF403B91, 0f);
public static final ChatWallpaper SOLID_12 = new SingleColorChatWallpaper(0xFF624249, 0f);
private final @ColorInt int color;
private final float dimLevelInDarkTheme;
SingleColorChatWallpaper(@ColorInt int color, float dimLevelInDarkTheme) {
this.color = color;
this.dimLevelInDarkTheme = dimLevelInDarkTheme;
}
private SingleColorChatWallpaper(Parcel in) {
color = in.readInt();
dimLevelInDarkTheme = in.readFloat();
}
@Override
public float getDimLevelForDarkTheme() {
return dimLevelInDarkTheme;
}
@Override
public void loadInto(@NonNull ImageView imageView) {
imageView.setImageDrawable(new ColorDrawable(color));
}
@Override
public @NonNull Wallpaper serialize() {
Wallpaper.SingleColor.Builder builder = Wallpaper.SingleColor.newBuilder();
builder.setColor(color);
return Wallpaper.newBuilder()
.setSingleColor(builder)
.setDimLevelInDarkTheme(dimLevelInDarkTheme)
.build();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(color);
dest.writeFloat(dimLevelInDarkTheme);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SingleColorChatWallpaper that = (SingleColorChatWallpaper) o;
return color == that.color && Float.compare(dimLevelInDarkTheme, that.dimLevelInDarkTheme) == 0;
}
@Override
public int hashCode() {
return Objects.hash(color, dimLevelInDarkTheme);
}
public static final Creator<SingleColorChatWallpaper> CREATOR = new Creator<SingleColorChatWallpaper>() {
@Override
public SingleColorChatWallpaper createFromParcel(Parcel in) {
return new SingleColorChatWallpaper(in);
}
@Override
public SingleColorChatWallpaper[] newArray(int size) {
return new SingleColorChatWallpaper[size];
}
};
}

View File

@@ -10,12 +10,21 @@ import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.database.model.databaseprotos.Wallpaper;
import org.thoughtcrime.securesms.mms.GlideApp;
import java.util.Objects;
final class UriChatWallpaper implements ChatWallpaper, Parcelable {
private final Uri uri;
private final Uri uri;
private final float dimLevelInDarkTheme;
public UriChatWallpaper(@NonNull Uri uri) {
this.uri = uri;
public UriChatWallpaper(@NonNull Uri uri, float dimLevelInDarkTheme) {
this.uri = uri;
this.dimLevelInDarkTheme = dimLevelInDarkTheme;
}
@Override
public float getDimLevelForDarkTheme() {
return dimLevelInDarkTheme;
}
@Override
@@ -29,6 +38,7 @@ final class UriChatWallpaper implements ChatWallpaper, Parcelable {
public @NonNull Wallpaper serialize() {
return Wallpaper.newBuilder()
.setFile(Wallpaper.File.newBuilder().setUri(uri.toString()))
.setDimLevelInDarkTheme(dimLevelInDarkTheme)
.build();
}
@@ -40,12 +50,27 @@ final class UriChatWallpaper implements ChatWallpaper, Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(uri.toString());
dest.writeFloat(dimLevelInDarkTheme);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UriChatWallpaper that = (UriChatWallpaper) o;
return Float.compare(that.dimLevelInDarkTheme, dimLevelInDarkTheme) == 0 &&
uri.equals(that.uri);
}
@Override
public int hashCode() {
return Objects.hash(uri, dimLevelInDarkTheme);
}
public static final Creator<UriChatWallpaper> CREATOR = new Creator<UriChatWallpaper>() {
@Override
public UriChatWallpaper createFromParcel(Parcel in) {
return new UriChatWallpaper(Uri.parse(in.readString()));
return new UriChatWallpaper(Uri.parse(in.readString()), in.readFloat());
}
@Override

View File

@@ -74,7 +74,7 @@ public final class WallpaperStorage {
*/
@WorkerThread
public static void onWallpaperDeselected(@NonNull Context context, @NonNull Uri uri) {
Uri globalUri = SignalStore.wallpaper().getCurrentWallpaperUri();
Uri globalUri = SignalStore.wallpaper().getWallpaperUri();
if (Objects.equals(uri, globalUri)) {
return;
}