From 9d3abf7d99c88e69b438347b6c501e796a710e73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20B=C3=A9raud?= <adrien.beraud@savoirfairelinux.com> Date: Fri, 22 Jan 2021 16:56:45 -0500 Subject: [PATCH] conversation: add emoji preference Change-Id: Ie47a58d18a81754bf5a7dca0771bd4293ee2d3fa --- .../ring/client/ContactDetailsActivity.java | 27 +++++- .../ring/client/EmojiChooserBottomSheet.java | 97 +++++++++++++++++++ .../ring/fragments/ConversationFragment.java | 11 ++- .../conversation/TvConversationFragment.java | 5 + .../main/res/layout/item_contact_action.xml | 88 ++++++++--------- .../app/src/main/res/layout/item_emoji.xml | 10 ++ .../app/src/main/res/values/arrays.xml | 13 +++ .../conversation/ConversationPresenter.java | 8 ++ .../ring/conversation/ConversationView.java | 1 + .../main/java/cx/ring/model/Conversation.java | 9 ++ 10 files changed, 221 insertions(+), 48 deletions(-) create mode 100644 ring-android/app/src/main/java/cx/ring/client/EmojiChooserBottomSheet.java create mode 100644 ring-android/app/src/main/res/layout/item_emoji.xml diff --git a/ring-android/app/src/main/java/cx/ring/client/ContactDetailsActivity.java b/ring-android/app/src/main/java/cx/ring/client/ContactDetailsActivity.java index ca63edba7..402cb1aec 100644 --- a/ring-android/app/src/main/java/cx/ring/client/ContactDetailsActivity.java +++ b/ring-android/app/src/main/java/cx/ring/client/ContactDetailsActivity.java @@ -50,7 +50,7 @@ import java.util.Map; import javax.inject.Inject; import javax.inject.Singleton; -import androidx.core.widget.ImageViewCompat; +import androidx.core.view.ViewCompat; import androidx.recyclerview.widget.RecyclerView; import cx.ring.R; @@ -100,6 +100,7 @@ public class ContactDetailsActivity extends AppCompatActivity { final IContactAction callback; int iconTint; + CharSequence iconSymbol; ContactAction(@DrawableRes int i, int tint, CharSequence t, IContactAction cb) { icon = i; @@ -118,6 +119,10 @@ public class ContactDetailsActivity extends AppCompatActivity { void setIconTint(int tint) { iconTint = tint; } + + void setSymbol(CharSequence t) { + iconSymbol = t; + } } static class ContactActionView extends RecyclerView.ViewHolder { @@ -152,9 +157,10 @@ public class ContactDetailsActivity extends AppCompatActivity { @Override public void onBindViewHolder(@NonNull ContactActionView holder, int position) { ContactAction action = actions.get(position); - holder.binding.actionIcon.setImageResource(action.icon); + holder.binding.actionIcon.setBackgroundResource(action.icon); + holder.binding.actionIcon.setText(action.iconSymbol); if (action.iconTint != Color.BLACK) - ImageViewCompat.setImageTintList(holder.binding.actionIcon, ColorStateList.valueOf(action.iconTint)); + ViewCompat.setBackgroundTintList(holder.binding.actionIcon, ColorStateList.valueOf(action.iconTint)); holder.binding.actionTitle.setText(action.title); holder.callback = action.callback; } @@ -169,8 +175,10 @@ public class ContactDetailsActivity extends AppCompatActivity { private final CompositeDisposable mDisposableBag = new CompositeDisposable(); private ContactAction colorAction; + private ContactAction symbolAction; private ContactAction contactAction; private int colorActionPosition; + private int symbolActionPosition; @Override protected void onCreate(Bundle savedInstanceState) { @@ -193,6 +201,7 @@ public class ContactDetailsActivity extends AppCompatActivity { fab.setOnClickListener(view -> goToConversationActivity(mConversation.getAccountId(), mConversation.getUri())); colorActionPosition = 1; + symbolActionPosition = 2; mDisposableBag.add(mConversationFacade .startConversation(path.getAccountId(), path.getConversationUri()) @@ -240,6 +249,18 @@ public class ContactDetailsActivity extends AppCompatActivity { collapsingToolbarLayout.setStatusBarScrimColor(color); adapter.actions.add(colorAction); + symbolAction = new ContactAction(0, getText(R.string.conversation_preference_emoji), () -> { + EmojiChooserBottomSheet frag = new EmojiChooserBottomSheet(); + frag.setCallback(s -> { + symbolAction.setSymbol(s); + adapter.notifyItemChanged(symbolActionPosition); + mPreferences.edit().putString(ConversationFragment.KEY_PREFERENCE_CONVERSATION_SYMBOL, s).apply(); + }); + frag.show(getSupportFragmentManager(), "colorChooser"); + }); + symbolAction.setSymbol(mPreferences.getString(ConversationFragment.KEY_PREFERENCE_CONVERSATION_SYMBOL, getResources().getString(R.string.conversation_default_emoji))); + adapter.actions.add(symbolAction); + if (mConversation.getContacts().size() <= 2) { CallContact contact = mConversation.getContact(); adapter.actions.add(new ContactAction(R.drawable.baseline_call_24, getText(R.string.ab_action_audio_call), () -> diff --git a/ring-android/app/src/main/java/cx/ring/client/EmojiChooserBottomSheet.java b/ring-android/app/src/main/java/cx/ring/client/EmojiChooserBottomSheet.java new file mode 100644 index 000000000..ee7e294cd --- /dev/null +++ b/ring-android/app/src/main/java/cx/ring/client/EmojiChooserBottomSheet.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2004-2021 Savoir-faire Linux Inc. + * + * Author: Adrien BΓ©raud <adrien.beraud@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +package cx.ring.client; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.ArrayRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.RecyclerView; + +import com.google.android.material.bottomsheet.BottomSheetDialogFragment; + +import cx.ring.R; + +public class EmojiChooserBottomSheet extends BottomSheetDialogFragment { + + interface IEmojiSelected { + void onEmojiSelected(String emoji); + } + + private IEmojiSelected callback; + + public void setCallback(IEmojiSelected cb) { + callback = cb; + } + + private class EmojiView extends RecyclerView.ViewHolder { + TextView view; + String emoji; + + EmojiView(@NonNull View itemView) { + super(itemView); + view = (TextView) itemView; + itemView.setOnClickListener(v -> { + if (callback != null) + callback.onEmojiSelected(emoji); + dismiss(); + }); + } + } + + class ColorAdapter extends RecyclerView.Adapter<EmojiView> { + private final String[] emojis; + + public ColorAdapter(@ArrayRes int arrayResId) { + emojis = getResources().getStringArray(arrayResId); + } + + @NonNull + @Override + public EmojiView onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_emoji, parent, false); + return new EmojiView(v); + } + + @Override + public void onBindViewHolder(@NonNull EmojiView holder, int position) { + holder.emoji = emojis[position]; + holder.view.setText(holder.emoji); + } + + @Override + public int getItemCount() { + return emojis.length; + } + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + RecyclerView view = (RecyclerView) inflater.inflate(R.layout.frag_color_chooser, container); + view.setAdapter(new ColorAdapter(R.array.conversation_emojis)); + return view; + } +} diff --git a/ring-android/app/src/main/java/cx/ring/fragments/ConversationFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/ConversationFragment.java index 3280919e8..826c3fb12 100644 --- a/ring-android/app/src/main/java/cx/ring/fragments/ConversationFragment.java +++ b/ring-android/app/src/main/java/cx/ring/fragments/ConversationFragment.java @@ -135,6 +135,7 @@ public class ConversationFragment extends BaseSupportFragment<ConversationPresen public static final String KEY_PREFERENCE_PENDING_MESSAGE = "pendingMessage"; public static final String KEY_PREFERENCE_CONVERSATION_COLOR = "color"; public static final String KEY_PREFERENCE_CONVERSATION_LAST_READ = "lastRead"; + public static final String KEY_PREFERENCE_CONVERSATION_SYMBOL = "symbol"; public static final String EXTRA_SHOW_MAP = "showMap"; private static final int REQUEST_CODE_FILE_PICKER = 1000; @@ -372,6 +373,11 @@ public class ConversationFragment extends BaseSupportFragment<ConversationPresen mAdapter.setPrimaryColor(color); } + @Override + public void setConversationSymbol(CharSequence symbol) { + binding.emojiSend.setText(symbol); + } + @Override public void onDestroyView() { if (mPreferences != null) @@ -898,8 +904,8 @@ public class ConversationFragment extends BaseSupportFragment<ConversationPresen mPreferences = requireActivity().getSharedPreferences(path.getAccountId() + "_" + uri.getUri(), Context.MODE_PRIVATE); mPreferences.registerOnSharedPreferenceChangeListener(this); presenter.setConversationColor(mPreferences.getInt(KEY_PREFERENCE_CONVERSATION_COLOR, getResources().getColor(R.color.color_primary_light))); + presenter.setConversationSymbol(mPreferences.getString(KEY_PREFERENCE_CONVERSATION_SYMBOL, getResources().getText(R.string.conversation_default_emoji).toString())); mLastRead = mPreferences.getString(KEY_PREFERENCE_CONVERSATION_LAST_READ, null); - Log.w(TAG, "Loaded last read " + mLastRead); } catch (Exception e) { Log.e(TAG, "Can't load conversation preferences"); } @@ -940,6 +946,9 @@ public class ConversationFragment extends BaseSupportFragment<ConversationPresen case KEY_PREFERENCE_CONVERSATION_COLOR: presenter.setConversationColor(prefs.getInt(KEY_PREFERENCE_CONVERSATION_COLOR, getResources().getColor(R.color.color_primary_light))); break; + case KEY_PREFERENCE_CONVERSATION_SYMBOL: + presenter.setConversationSymbol(prefs.getString(KEY_PREFERENCE_CONVERSATION_SYMBOL, getResources().getText(R.string.conversation_default_emoji).toString())); + break; } } diff --git a/ring-android/app/src/main/java/cx/ring/tv/conversation/TvConversationFragment.java b/ring-android/app/src/main/java/cx/ring/tv/conversation/TvConversationFragment.java index ee7b2b6e8..bcdae7809 100644 --- a/ring-android/app/src/main/java/cx/ring/tv/conversation/TvConversationFragment.java +++ b/ring-android/app/src/main/java/cx/ring/tv/conversation/TvConversationFragment.java @@ -682,6 +682,11 @@ public class TvConversationFragment extends BaseSupportFragment<ConversationPres } + @Override + public void setConversationSymbol(CharSequence symbol) { + + } + @Override public void startShareLocation(String accountId, String contactId) { diff --git a/ring-android/app/src/main/res/layout/item_contact_action.xml b/ring-android/app/src/main/res/layout/item_contact_action.xml index 24e369e4e..5d1899054 100644 --- a/ring-android/app/src/main/res/layout/item_contact_action.xml +++ b/ring-android/app/src/main/res/layout/item_contact_action.xml @@ -1,49 +1,49 @@ <?xml version="1.0" encoding="utf-8"?> -<layout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools"> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/call_entry" + android:layout_width="match_parent" + android:layout_height="56dp" + android:background="?android:attr/selectableItemBackground" + android:descendantFocusability="blocksDescendants" + android:paddingLeft="16dp" + android:paddingTop="8dp" + android:paddingRight="16dp" + android:paddingBottom="8dp"> - <data /> + <TextView + android:id="@+id/action_icon" + android:layout_width="32dp" + android:layout_height="32dp" + android:layout_centerVertical="true" + android:layout_marginStart="4dp" + android:layout_marginTop="4dp" + android:layout_marginEnd="20dp" + android:layout_marginBottom="4dp" + android:backgroundTint="@color/colorPrimary" + android:gravity="center" + android:scaleType="fitCenter" + android:text="" + android:textSize="24dp" + android:textColor="@color/black" + app:tint="@color/colorPrimary" + tools:background="@drawable/baseline_call_24" /> - <RelativeLayout - android:id="@+id/call_entry" + <TextView + android:id="@+id/action_title" android:layout_width="match_parent" - android:layout_height="56dp" - android:background="?android:attr/selectableItemBackground" - android:descendantFocusability="blocksDescendants" - android:paddingLeft="16dp" - android:paddingTop="8dp" - android:paddingRight="16dp" - android:paddingBottom="8dp"> + android:layout_height="wrap_content" + android:layout_centerVertical="true" + android:layout_toEndOf="@id/action_icon" + android:ellipsize="middle" + android:gravity="start" + android:marqueeRepeatLimit="marquee_forever" + android:scrollHorizontally="true" + android:singleLine="true" + android:textAlignment="viewStart" + android:textColor="@color/textColorPrimary" + android:textSize="16sp" + tools:text="Start Audio Call" /> - <ImageView - android:id="@+id/action_icon" - android:layout_width="40dp" - android:layout_height="40dp" - android:layout_centerVertical="true" - android:layout_marginEnd="16dp" - android:background="@null" - android:padding="4dp" - android:scaleType="fitCenter" - android:tint="@color/colorPrimary" - tools:src="@drawable/baseline_call_24" /> - - <TextView - android:id="@+id/action_title" - android:layout_width="match_parent" - android:layout_height="wrap_content" - - android:layout_centerVertical="true" - android:layout_toEndOf="@id/action_icon" - android:ellipsize="middle" - android:gravity="start" - android:marqueeRepeatLimit="marquee_forever" - android:scrollHorizontally="true" - android:singleLine="true" - android:textAlignment="viewStart" - android:textColor="@color/textColorPrimary" - android:textSize="16sp" - tools:text="Start Audio Call" /> - - </RelativeLayout> - -</layout> \ No newline at end of file +</RelativeLayout> diff --git a/ring-android/app/src/main/res/layout/item_emoji.xml b/ring-android/app/src/main/res/layout/item_emoji.xml new file mode 100644 index 000000000..79e8e6675 --- /dev/null +++ b/ring-android/app/src/main/res/layout/item_emoji.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<TextView xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:padding="16dp" + android:text="@string/conversation_default_emoji" + android:textAlignment="center" + android:textSize="24dp" + android:textColor="@color/text_color"/> diff --git a/ring-android/app/src/main/res/values/arrays.xml b/ring-android/app/src/main/res/values/arrays.xml index 4e34db27f..5f56bf7e5 100644 --- a/ring-android/app/src/main/res/values/arrays.xml +++ b/ring-android/app/src/main/res/values/arrays.xml @@ -56,6 +56,19 @@ along with this program; if not, write to the Free Software <item>1080</item> <item>2160</item> </string-array> + + <string-array name="conversation_emojis"> + <item>π</item> + <item>β€οΈ</item> + <item>π</item> + <item>π©</item> + <item>π»</item> + <item>π</item> + <item>β¨</item> + <item>π</item> + <item>π</item> + </string-array> + <string translatable="false" name="video_resolution_default">480</string> <string translatable="false" name="video_resolution_default_tv">720</string> </resources> diff --git a/ring-android/libringclient/src/main/java/cx/ring/conversation/ConversationPresenter.java b/ring-android/libringclient/src/main/java/cx/ring/conversation/ConversationPresenter.java index 23c14a6ac..8a94b9d2a 100644 --- a/ring-android/libringclient/src/main/java/cx/ring/conversation/ConversationPresenter.java +++ b/ring-android/libringclient/src/main/java/cx/ring/conversation/ConversationPresenter.java @@ -262,6 +262,9 @@ public class ConversationPresenter extends RootPresenter<ConversationView> { mConversationDisposable.add(c.getColor() .observeOn(mUiScheduler) .subscribe(view::setConversationColor, e -> Log.e(TAG, "Can't update conversation color", e))); + mConversationDisposable.add(c.getSymbol() + .observeOn(mUiScheduler) + .subscribe(view::setConversationSymbol, e -> Log.e(TAG, "Can't update conversation color", e))); Log.e(TAG, "getLocationUpdates subscribe"); mConversationDisposable.add(account @@ -440,6 +443,11 @@ public class ConversationPresenter extends RootPresenter<ConversationView> { .firstElement() .subscribe(conversation -> conversation.setColor(color))); } + public void setConversationSymbol(CharSequence symbol) { + mCompositeDisposable.add(mConversationSubject + .firstElement() + .subscribe(conversation -> conversation.setSymbol(symbol))); + } public void cameraPermissionChanged(boolean isGranted) { if (isGranted && mHardwareService.isVideoAvailable()) { diff --git a/ring-android/libringclient/src/main/java/cx/ring/conversation/ConversationView.java b/ring-android/libringclient/src/main/java/cx/ring/conversation/ConversationView.java index 47e8ccc50..8c881ec01 100644 --- a/ring-android/libringclient/src/main/java/cx/ring/conversation/ConversationView.java +++ b/ring-android/libringclient/src/main/java/cx/ring/conversation/ConversationView.java @@ -83,6 +83,7 @@ public interface ConversationView extends BaseView { void setLastDisplayed(Interaction interaction); void setConversationColor(int integer); + void setConversationSymbol(CharSequence symbol); void startSaveFile(DataTransfer currentFile, String fileAbsolutePath); diff --git a/ring-android/libringclient/src/main/java/cx/ring/model/Conversation.java b/ring-android/libringclient/src/main/java/cx/ring/model/Conversation.java index 1c37a4145..954b27598 100644 --- a/ring-android/libringclient/src/main/java/cx/ring/model/Conversation.java +++ b/ring-android/libringclient/src/main/java/cx/ring/model/Conversation.java @@ -60,6 +60,7 @@ public class Conversation extends ConversationHistory { private final Subject<List<Conference>> callsSubject = BehaviorSubject.create(); private final Subject<Account.ComposingStatus> composingStatusSubject = BehaviorSubject.createDefault(Account.ComposingStatus.Idle); private final Subject<Integer> color = BehaviorSubject.create(); + private final Subject<CharSequence> symbol = BehaviorSubject.create(); private final Subject<List<CallContact>> mContactSubject = BehaviorSubject.create(); private Single<Conversation> isLoaded = null; @@ -648,9 +649,17 @@ public class Conversation extends ConversationHistory { color.onNext(c); } + public void setSymbol(CharSequence s) { + symbol.onNext(s); + } + public Observable<Integer> getColor() { return color; } + public Observable<CharSequence> getSymbol() { + return symbol; + } + public String getAccountId() { return mAccountId; -- GitLab