257 lines
8.3 KiB
Java
257 lines
8.3 KiB
Java
package org.thoughtcrime.securesms.stickers;
|
|
|
|
import androidx.lifecycle.ViewModelProviders;
|
|
import android.content.Context;
|
|
import android.graphics.drawable.Drawable;
|
|
import android.net.Uri;
|
|
import androidx.annotation.NonNull;
|
|
import androidx.annotation.Nullable;
|
|
import androidx.fragment.app.Fragment;
|
|
import androidx.fragment.app.FragmentManager;
|
|
import androidx.fragment.app.FragmentStatePagerAdapter;
|
|
import androidx.appcompat.app.AppCompatActivity;
|
|
import android.widget.ImageView;
|
|
|
|
import org.thoughtcrime.securesms.R;
|
|
import org.thoughtcrime.securesms.components.emoji.MediaKeyboardProvider;
|
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
|
import org.thoughtcrime.securesms.database.model.StickerPackRecord;
|
|
import org.thoughtcrime.securesms.database.model.StickerRecord;
|
|
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader;
|
|
import org.thoughtcrime.securesms.mms.GlideRequests;
|
|
import org.thoughtcrime.securesms.stickers.StickerKeyboardPageFragment.EventListener;
|
|
import org.thoughtcrime.securesms.stickers.StickerKeyboardRepository.PackListResult;
|
|
import org.thoughtcrime.securesms.util.ResUtil;
|
|
import org.thoughtcrime.securesms.util.ThemeUtil;
|
|
import org.thoughtcrime.securesms.util.Throttler;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
/**
|
|
* A provider to select stickers in the {@link org.thoughtcrime.securesms.components.emoji.MediaKeyboard}.
|
|
*/
|
|
public final class StickerKeyboardProvider implements MediaKeyboardProvider,
|
|
MediaKeyboardProvider.AddObserver,
|
|
StickerKeyboardPageFragment.EventListener
|
|
{
|
|
|
|
private final Context context;
|
|
private final StickerEventListener eventListener;
|
|
private final StickerPagerAdapter pagerAdapter;
|
|
private final Throttler stickerThrottler;
|
|
|
|
private Controller controller;
|
|
private Presenter presenter;
|
|
private boolean isSoloProvider;
|
|
private StickerKeyboardViewModel viewModel;
|
|
|
|
public StickerKeyboardProvider(@NonNull AppCompatActivity activity,
|
|
@NonNull StickerEventListener eventListener)
|
|
{
|
|
this.context = activity;
|
|
this.eventListener = eventListener;
|
|
this.pagerAdapter = new StickerPagerAdapter(activity.getSupportFragmentManager(), this);
|
|
this.stickerThrottler = new Throttler(100);
|
|
|
|
initViewModel(activity);
|
|
}
|
|
|
|
@Override
|
|
public int getProviderIconView(boolean selected) {
|
|
if (selected) {
|
|
return ThemeUtil.isDarkTheme(context) ? R.layout.sticker_keyboard_icon_dark_selected : R.layout.sticker_keyboard_icon_light_selected;
|
|
} else {
|
|
return ThemeUtil.isDarkTheme(context) ? R.layout.sticker_keyboard_icon_dark : R.layout.sticker_keyboard_icon_light;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void requestPresentation(@NonNull Presenter presenter, boolean isSoloProvider) {
|
|
this.presenter = presenter;
|
|
this.isSoloProvider = isSoloProvider;
|
|
|
|
PackListResult result = viewModel.getPacks().getValue();
|
|
|
|
if (result != null) {
|
|
present(presenter, result, true);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setController(@Nullable Controller controller) {
|
|
this.controller = controller;
|
|
}
|
|
|
|
@Override
|
|
public void onAddClicked() {
|
|
eventListener.onStickerManagementClicked();
|
|
}
|
|
|
|
@Override
|
|
public void onStickerSelected(@NonNull StickerRecord sticker) {
|
|
stickerThrottler.publish(() -> eventListener.onStickerSelected(sticker));
|
|
}
|
|
|
|
@Override
|
|
public void onStickerPopupStarted() {
|
|
if (controller != null) {
|
|
controller.setViewPagerEnabled(false);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onStickerPopupEnded() {
|
|
if (controller != null) {
|
|
controller.setViewPagerEnabled(true);
|
|
}
|
|
}
|
|
|
|
private void initViewModel(@NonNull AppCompatActivity activity) {
|
|
StickerKeyboardRepository repository = new StickerKeyboardRepository(DatabaseFactory.getStickerDatabase(activity));
|
|
viewModel = ViewModelProviders.of(activity, new StickerKeyboardViewModel.Factory(activity.getApplication(), repository)).get(StickerKeyboardViewModel.class);
|
|
|
|
viewModel.getPacks().observe(activity, result -> {
|
|
if (result == null) return;
|
|
|
|
int previousCount = pagerAdapter.getCount();
|
|
|
|
pagerAdapter.setPacks(result.getPacks());
|
|
|
|
if (presenter != null) {
|
|
present(presenter, result, previousCount != pagerAdapter.getCount());
|
|
}
|
|
});
|
|
}
|
|
|
|
private void present(@NonNull Presenter presenter, @NonNull PackListResult result, boolean calculateStartingIndex) {
|
|
if (result.getPacks().isEmpty() && presenter.isVisible()) {
|
|
context.startActivity(StickerManagementActivity.getIntent(context));
|
|
presenter.requestDismissal();
|
|
return;
|
|
}
|
|
|
|
int startingIndex = presenter.getCurrentPosition();
|
|
|
|
if (calculateStartingIndex) {
|
|
startingIndex = !result.hasRecents() && result.getPacks().size() > 0 ? 1 : 0;
|
|
}
|
|
|
|
presenter.present(this, pagerAdapter, new IconProvider(context, result.getPacks()), null, this, null, startingIndex);
|
|
|
|
if (isSoloProvider && result.getPacks().isEmpty()) {
|
|
context.startActivity(StickerManagementActivity.getIntent(context));
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(@Nullable Object obj) {
|
|
return obj instanceof StickerKeyboardProvider;
|
|
}
|
|
|
|
private static class StickerPagerAdapter extends FragmentStatePagerAdapter {
|
|
|
|
private final List<StickerPackRecord> packs;
|
|
private final Map<String, Integer> itemPositions;
|
|
private final EventListener eventListener;
|
|
|
|
public StickerPagerAdapter(@NonNull FragmentManager fm, @NonNull EventListener eventListener) {
|
|
super(fm);
|
|
this.eventListener = eventListener;
|
|
this.packs = new ArrayList<>();
|
|
this.itemPositions = new HashMap<>();
|
|
}
|
|
|
|
@Override
|
|
public int getItemPosition(@NonNull Object object) {
|
|
String packId = ((StickerKeyboardPageFragment) object).getPackId();
|
|
|
|
if (itemPositions.containsKey(packId)) {
|
|
//noinspection ConstantConditions
|
|
return itemPositions.get(packId);
|
|
}
|
|
|
|
return POSITION_NONE;
|
|
}
|
|
|
|
@Override
|
|
public Fragment getItem(int i) {
|
|
StickerKeyboardPageFragment fragment;
|
|
|
|
if (i == 0) {
|
|
fragment = StickerKeyboardPageFragment.newInstance(StickerKeyboardPageFragment.RECENT_PACK_ID);
|
|
} else {
|
|
StickerPackRecord pack = packs.get(i - 1);
|
|
fragment = StickerKeyboardPageFragment.newInstance(pack.getPackId());
|
|
}
|
|
|
|
fragment.setEventListener(eventListener);
|
|
|
|
return fragment;
|
|
}
|
|
|
|
@Override
|
|
public int getCount() {
|
|
return packs.isEmpty() ? 0 : packs.size() + 1;
|
|
}
|
|
|
|
void setPacks(@NonNull List<StickerPackRecord> packs) {
|
|
itemPositions.clear();
|
|
|
|
if (areListsEqual(this.packs, packs)) {
|
|
itemPositions.put(StickerKeyboardPageFragment.RECENT_PACK_ID, 0);
|
|
for (int i = 0; i < packs.size(); i++) {
|
|
itemPositions.put(packs.get(i).getPackId(), i + 1);
|
|
}
|
|
}
|
|
|
|
this.packs.clear();
|
|
this.packs.addAll(packs);
|
|
|
|
notifyDataSetChanged();
|
|
}
|
|
|
|
boolean areListsEqual(@NonNull List<StickerPackRecord> a, @NonNull List<StickerPackRecord> b) {
|
|
if (a.size() != b.size()) return false;
|
|
|
|
for (int i = 0; i < a.size(); i++) {
|
|
if (!a.get(i).equals(b.get(i))) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
private static class IconProvider implements TabIconProvider {
|
|
|
|
private final Context context;
|
|
private final List<StickerPackRecord> packs;
|
|
|
|
private IconProvider(@NonNull Context context, List<StickerPackRecord> packs) {
|
|
this.context = context;
|
|
this.packs = packs;
|
|
}
|
|
|
|
@Override
|
|
public void loadCategoryTabIcon(@NonNull GlideRequests glideRequests, @NonNull ImageView imageView, int index) {
|
|
if (index == 0) {
|
|
Drawable icon = ResUtil.getDrawable(context, R.attr.emoji_category_recent);
|
|
imageView.setImageDrawable(icon);
|
|
} else {
|
|
Uri uri = packs.get(index - 1).getCover().getUri();
|
|
|
|
glideRequests.load(new DecryptableStreamUriLoader.DecryptableUri(uri))
|
|
.into(imageView);
|
|
}
|
|
}
|
|
}
|
|
|
|
public interface StickerEventListener {
|
|
void onStickerSelected(@NonNull StickerRecord sticker);
|
|
void onStickerManagementClicked();
|
|
}
|
|
}
|