Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1004,8 +1004,8 @@ class ComposeActivity :
)
Toast.makeText(this, errorMessage, Toast.LENGTH_SHORT).show()
} else {
EmojiDialogFragment(
viewModel.emoji.value, onEmojiClick = { isCustomEmoji, shortcode ->
EmojiDialogFragment.newInstance(
viewModel.emoji.value ?: emptyList(), onEmojiClick = { isCustomEmoji, shortcode ->
if (isCustomEmoji) {
replaceTextAtCaret(":$shortcode: ")
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -549,12 +549,11 @@ class SearchStatusesFragment :
if (!react) {
searchViewModel.emojiReact(react, emoji, statusId)
} else {
EmojiDialogFragment(
searchViewModel.instance.value?.emojiList,
EmojiDialogFragment.newInstance(
searchViewModel.instance.value?.emojiList ?: emptyList(),
onEmojiClick = { _, shortcode ->
searchViewModel.emojiReact(react, shortcode, statusId)
}
).show(parentFragmentManager, EmojiDialogFragment.DIALOG_TAG)
}).show(parentFragmentManager, EmojiDialogFragment.DIALOG_TAG)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1625,16 +1625,29 @@ public void onEmojiReact(final boolean react, @NonNull final String emoji, @NonN
.subscribe((newStatus) -> setEmojiReactForStatus(posAndNotification.first, newStatus),
(t) -> Timber.e(t, "Failed to react with " + emoji + " on status: " + statusId));
} else {
EmojiDialogFragment dialog = new EmojiDialogFragment(
instanceRepo.getInstanceInfoDb().getEmojiList(),
(isCustomEmoji, shortcode) -> {
timelineCases.getValue().react(shortcode, statusId, true)
.observeOn(AndroidSchedulers.mainThread()).as(autoDisposable(from(this)))
.subscribe((newStatus) -> setEmojiReactForStatus(posAndNotification.first, newStatus),
(t) -> Timber.e(t, "Failed to react with " + emoji + " on status: " + statusId));

return Unit.INSTANCE;
}
EmojiDialogFragment dialog = EmojiDialogFragment.Companion.newInstance(
(instanceRepo.getInstanceInfoDb().getEmojiList() !=
null) ? instanceRepo.getInstanceInfoDb()
.getEmojiList() : Collections.emptyList(),
(isCustomEmoji, shortcode) -> {
timelineCases.getValue()
.react(shortcode, statusId, true)
.observeOn(AndroidSchedulers.mainThread())
.as(autoDisposable(from(this)))
.subscribe(
(newStatus) -> setEmojiReactForStatus(
posAndNotification.first,
newStatus
),
(t) -> Timber.e(
t,
"Failed to react with " + emoji +
" on status: " + statusId
)
);

return Unit.INSTANCE;
}
);
dialog.show(getParentFragmentManager(), EmojiDialogFragment.DIALOG_TAG);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1770,16 +1770,29 @@ public void onEmojiReact(final boolean react, @NonNull final String emoji, @NonN
.subscribe((newStatus) -> setEmojiReactionForStatus(position, newStatus),
(t) -> Timber.e(t, "Failed to react with " + emoji + " on status: " + statusId));
} else {
EmojiDialogFragment dialog = new EmojiDialogFragment(
instanceRepo.getInstanceInfoDb().getEmojiList(),
(isCustomEmoji, shortcode) -> {
timelineCases.getValue().react(shortcode, statusId, true)
.observeOn(AndroidSchedulers.mainThread()).as(autoDisposable(from(this)))
.subscribe((newStatus) -> setEmojiReactionForStatus(position, newStatus),
(t) -> Timber.e(t, "Failed to react with " + emoji + " on status: " + statusId));

return Unit.INSTANCE;
}
EmojiDialogFragment dialog = EmojiDialogFragment.Companion.newInstance(
(instanceRepo.getInstanceInfoDb().getEmojiList() !=
null) ? instanceRepo.getInstanceInfoDb()
.getEmojiList() : Collections.emptyList(),
(isCustomEmoji, shortcode) -> {
timelineCases.getValue()
.react(shortcode, statusId, true)
.observeOn(AndroidSchedulers.mainThread())
.as(autoDisposable(from(this)))
.subscribe(
(newStatus) -> setEmojiReactionForStatus(
position,
newStatus
),
(t) -> Timber.e(
t,
"Failed to react with " + emoji +
" on status: " + statusId
)
);

return Unit.INSTANCE;
}
);
dialog.show(getParentFragmentManager(), EmojiDialogFragment.DIALOG_TAG);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import com.keylesspalace.tusky.view.emojireactions.EmojiDialogFragment;
import static com.uber.autodispose.AutoDispose.autoDisposable;
import static com.uber.autodispose.android.lifecycle.AndroidLifecycleScopeProvider.from;
import java.util.Collections;
import kotlin.Unit;
import static org.koin.java.KoinJavaComponent.inject;
import android.content.Context;
Expand Down Expand Up @@ -913,16 +914,29 @@ public void onEmojiReact(final boolean react, @NonNull final String emoji, @NonN
.subscribe((newStatus) -> setEmojiReactionForStatus(position, newStatus),
(t) -> Timber.e(t, "Failed to react with " + emoji + " on status: " + statusId));
} else {
EmojiDialogFragment dialog = new EmojiDialogFragment(
instanceRepo.getInstanceInfoDb().getEmojiList(),
(isCustomEmoji, shortcode) -> {
timelineCases.getValue().react(shortcode, statusId, true)
.observeOn(AndroidSchedulers.mainThread()).as(autoDisposable(from(this)))
.subscribe((newStatus) -> setEmojiReactionForStatus(position, newStatus),
(t) -> Timber.e(t, "Failed to react with " + emoji + " on status: " + statusId));

return Unit.INSTANCE;
}
EmojiDialogFragment dialog = EmojiDialogFragment.Companion.newInstance(
(instanceRepo.getInstanceInfoDb().getEmojiList() !=
null) ? instanceRepo.getInstanceInfoDb()
.getEmojiList() : Collections.emptyList(),
(isCustomEmoji, shortcode) -> {
timelineCases.getValue()
.react(shortcode, statusId, true)
.observeOn(AndroidSchedulers.mainThread())
.as(autoDisposable(from(this)))
.subscribe(
(newStatus) -> setEmojiReactionForStatus(
position,
newStatus
),
(t) -> Timber.e(
t,
"Failed to react with " + emoji +
" on status: " + statusId
)
);

return Unit.INSTANCE;
}
);
dialog.show(getParentFragmentManager(), EmojiDialogFragment.DIALOG_TAG);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.keylesspalace.tusky.view

import android.content.Context
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlin.math.max

class CustomGridLayoutManager(context: Context, columnWidth: Int) : GridLayoutManager(context, 1) {

private var columnWidth: Int = columnWidth
set(value) {
if (value > 0 && value != field) {
field = value
}
}

override fun onLayoutChildren(recycler: RecyclerView.Recycler, state: RecyclerView.State) {
val currentWidth = width - paddingRight - paddingLeft
if (columnWidth > 0 && currentWidth > 0) {
val newSpanCount = max(1, currentWidth / columnWidth)
if (spanCount != newSpanCount) {
spanCount = newSpanCount
}
}
super.onLayoutChildren(recycler, state)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.keylesspalace.tusky.view;

import static org.koin.java.KoinJavaComponent.inject;
import android.app.Dialog;
import android.content.Context;
import android.content.SharedPreferences;
Expand All @@ -8,14 +9,13 @@
import android.view.Window;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager2.widget.ViewPager2;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
import com.keylesspalace.tusky.R;
import com.keylesspalace.tusky.adapter.StickerAdapter;
import com.keylesspalace.tusky.adapter.UnicodeEmojiAdapter;
import com.keylesspalace.tusky.view.emojireactions.UnicodeEmojiAdapter;
import com.keylesspalace.tusky.entity.StickerPack;
import java.util.ArrayList;
import java.util.Arrays;
Expand All @@ -25,16 +25,19 @@

public class EmojiKeyboard extends LinearLayout {

private final SharedPreferences pref = (SharedPreferences) inject(SharedPreferences.class).getValue();
private final String RECENTS_DELIM = "; ";
private TabLayout tabs;
private ViewPager2 pager;
private TabLayoutMediator currentMediator;
private String preferenceKey;
private SharedPreferences pref;
private Set<String> recents;
private final String RECENTS_DELIM = "; ";
private int MAX_RECENTS_ITEMS = 50;
private RecyclerView.Adapter adapter;
public boolean isSticky = false; // TODO
public static final int UNICODE_MODE = 0;
public static final int CUSTOM_MODE = 1;
public static final int STICKER_MODE = 2;

public EmojiKeyboard(Context context) {
super(context);
Expand All @@ -54,15 +57,10 @@ public EmojiKeyboard(Context context, AttributeSet attrs, int defStyleAttr) {
void init(Context context) {
inflate(context, R.layout.item_emoji_picker, this);

pref = PreferenceManager.getDefaultSharedPreferences(context);
tabs = findViewById(R.id.picker_tabs);
pager = findViewById(R.id.picker_pager);
}

public static final int UNICODE_MODE = 0;
public static final int CUSTOM_MODE = 1;
public static final int STICKER_MODE = 2;

private void setupKeyboardWithAdapter(RecyclerView.Adapter adapter, String preferenceKey) {
this.preferenceKey = preferenceKey;
this.adapter = adapter;
Expand All @@ -77,11 +75,13 @@ private void setupKeyboardWithAdapter(RecyclerView.Adapter adapter, String prefe
currentMediator.detach();
}

currentMediator = new TabLayoutMediator(tabs, pager, (TabLayoutMediator.TabConfigurationStrategy)adapter);
currentMediator.attach();
currentMediator = new TabLayoutMediator(tabs, pager,
(tab, position) -> ((TabLayoutMediator.TabConfigurationStrategy) adapter).onConfigureTab(tab, position)
);
pager.post(() -> currentMediator.attach());
}

public void setupStickerKeyboard(OnEmojiSelectedListener listener, StickerPack packs[]) {
public void setupStickerKeyboard(OnEmojiSelectedListener listener, StickerPack[] packs) {
MAX_RECENTS_ITEMS = 20;
setupKeyboardWithAdapter(new StickerAdapter(packs, (_id, _emoji) -> {
this.appendToRecents(_emoji);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.keylesspalace.tusky.view.emojireactions

import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
Expand All @@ -21,14 +21,15 @@ import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject
import org.koin.androidx.viewmodel.ext.android.viewModel

class CustomEmojiPickerPage(
private val emojiList: List<Emoji>,
private val onEmojiClick: (String) -> Unit
) : Fragment() {
class CustomEmojiPickerPage : Fragment() {

private lateinit var binding: LayoutEmojiCustomBinding
private val preferences: SharedPreferences by inject()
private val customEmojiViewModel by viewModel<CustomEmojiPickerViewModel>()
private var globalLayoutListener: ViewTreeObserver.OnGlobalLayoutListener? = null
private var initialEmojis: List<Emoji>? = null
private lateinit var onEmojiClick: (String) -> Unit

private val adapter by lazy {
ListEmojiAdapter(
object : OnEmojiSelectedListener {
Expand All @@ -40,6 +41,26 @@ class CustomEmojiPickerPage(
)
}

companion object {
fun newInstance(
emojiList: List<Emoji>,
onEmojiClick: (String) -> Unit
): CustomEmojiPickerPage {
return CustomEmojiPickerPage().apply {
this.initialEmojis = emojiList
this.onEmojiClick = onEmojiClick
}
}
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
initialEmojis?.let { list ->
customEmojiViewModel.setEmojis(list)
initialEmojis = null
}
}

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
Expand All @@ -52,7 +73,10 @@ class CustomEmojiPickerPage(
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

binding.emojiGrid.layoutManager = GridLayoutManager(context, calculateSpanCount(requireContext()))
val layoutManager = GridLayoutManager(context, 1)
binding.emojiGrid.layoutManager = layoutManager

setupGridLayoutListener()

binding.searchBox.setOnClickListener {
binding.searchBox.requestFocus()
Expand All @@ -67,19 +91,35 @@ class CustomEmojiPickerPage(
customEmojiViewModel.emojis.collect { emojis ->
binding.emojiGrid.adapter = adapter
adapter.submitList(emojis)

binding.loadingOverlay.gone()
}
}
}
}

customEmojiViewModel.setEmojis(emojiList)
private fun setupGridLayoutListener() {
globalLayoutListener = ViewTreeObserver.OnGlobalLayoutListener {
if (!isAdded || context == null) {
return@OnGlobalLayoutListener
}

val totalWidth = binding.emojiGrid.width
if (totalWidth > 0) {
val itemWidthPx = (48 * resources.displayMetrics.density).toInt()
val spanCount = maxOf(1, totalWidth / itemWidthPx)
(binding.emojiGrid.layoutManager as? GridLayoutManager)?.spanCount = spanCount
}
}

binding.emojiGrid.viewTreeObserver.addOnGlobalLayoutListener(globalLayoutListener)
}

private fun calculateSpanCount(context: Context): Int {
val displayMetrics = context.resources.displayMetrics
val screenWidthPx = displayMetrics.widthPixels
val itemWidthPx = (40 * displayMetrics.density).toInt()
return maxOf(1, ((screenWidthPx / itemWidthPx) - 2))
override fun onDestroyView() {
globalLayoutListener?.let { listener ->
binding.emojiGrid.viewTreeObserver.removeOnGlobalLayoutListener(listener)
}
globalLayoutListener = null

super.onDestroyView()
}
}
Loading