Partly implement mention highlight

Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
Mario Danic 2018-05-04 11:59:16 +02:00
parent cfd2d0402d
commit 08f44a04e1
16 changed files with 173 additions and 105 deletions

View File

@ -129,7 +129,7 @@ dependencies {
implementation 'com.github.HITGIF:TextFieldBoxes:1.4.3'
implementation 'eu.davidea:flexible-adapter:5.0.3'
implementation 'eu.davidea:flexible-adapter:5.0.4'
implementation 'eu.davidea:flexible-adapter-ui:1.0.0-b3'
implementation 'com.github.bumptech.glide:glide:4.3.0'

View File

@ -794,38 +794,38 @@ public class CallActivity extends AppCompatActivity {
}
private void checkCapabilities() {
ncApi.getCapabilities(credentials, ApiUtils.getUrlForCapabilities(baseUrl))
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<CapabilitiesOverall>() {
@Override
public void onSubscribe(Disposable d) {
ncApi.getCapabilities(credentials, ApiUtils.getUrlForCapabilities(baseUrl))
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<CapabilitiesOverall>() {
@Override
public void onSubscribe(Disposable d) {
}
}
@Override
public void onNext(CapabilitiesOverall capabilitiesOverall) {
isMultiSession = capabilitiesOverall.getOcs().getData()
.getCapabilities().getSpreedCapability() != null &&
capabilitiesOverall.getOcs().getData()
.getCapabilities().getSpreedCapability()
.getFeatures() != null && capabilitiesOverall.getOcs().getData()
.getCapabilities().getSpreedCapability()
.getFeatures().contains("multi-room-users");
@Override
public void onNext(CapabilitiesOverall capabilitiesOverall) {
isMultiSession = capabilitiesOverall.getOcs().getData()
.getCapabilities().getSpreedCapability() != null &&
capabilitiesOverall.getOcs().getData()
.getCapabilities().getSpreedCapability()
.getFeatures() != null && capabilitiesOverall.getOcs().getData()
.getCapabilities().getSpreedCapability()
.getFeatures().contains("multi-room-users");
joinRoomAndCall();
}
joinRoomAndCall();
}
@Override
public void onError(Throwable e) {
isMultiSession = false;
}
@Override
public void onError(Throwable e) {
isMultiSession = false;
}
@Override
public void onComplete() {
@Override
public void onComplete() {
}
});
}
});
}
private void joinRoomAndCall() {

View File

@ -91,7 +91,7 @@ public class MenuItem extends AbstractFlexibleItem<MenuItem.MenuItemViewHolder>
holder.menuTitle.setText(spannableString);
} else {
holder.menuTitle.setText(title);
holder.menuTitle.setCompoundDrawablesWithIntrinsicBounds(icon,null,null,null);
holder.menuTitle.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);
holder.menuTitle.setCompoundDrawablePadding(padding);
}
}

View File

@ -163,7 +163,8 @@ public class UserItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder>
public TextView contactDisplayName;
@BindView(R.id.avatar_flip_view)
public FlipView avatarFlipView;
@Nullable @BindView(R.id.secondary_text)
@Nullable
@BindView(R.id.secondary_text)
public TextView contactMentionId;
/**

View File

@ -20,26 +20,48 @@
package com.nextcloud.talk.adapters.messages;
import android.text.Html;
import android.text.TextUtils;
import android.view.View;
import android.widget.TextView;
import com.nextcloud.talk.R;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.models.json.chat.ChatMessage;
import com.nextcloud.talk.utils.DisplayUtils;
import com.nextcloud.talk.utils.database.user.UserUtils;
import com.stfalcon.chatkit.messages.MessageHolders;
import java.util.HashMap;
import javax.inject.Inject;
import autodagger.AutoInjector;
import butterknife.BindView;
import butterknife.ButterKnife;
@AutoInjector(NextcloudTalkApplication.class)
public class MagicIncomingTextMessageViewHolder
extends MessageHolders.IncomingTextMessageViewHolder<ChatMessage> {
@BindView(R.id.messageAuthor)
TextView messageAuthor;
@BindView(R.id.messageText)
TextView messageText;
@Inject
UserUtils userUtils;
private UserEntity currentUser;
public MagicIncomingTextMessageViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
currentUser = userUtils.getCurrentUser();
}
@ -52,5 +74,32 @@ public class MagicIncomingTextMessageViewHolder
} else {
messageAuthor.setText(R.string.nc_nick_guest);
}
HashMap<String, HashMap<String, String>> messageParameters = message.getMessageParameters();
String messageString = message.getText();
if (messageParameters != null && message.getMessageParameters().size() > 0) {
for (String key : message.getMessageParameters().keySet()) {
HashMap<String, String> individualHashMap = message.getMessageParameters().get(key);
if (individualHashMap.get("type").equals("user")) {
int color;
if (messageParameters.get(key).get("id").equals(currentUser.getUserId())) {
color = NextcloudTalkApplication.getSharedApplication().getResources().getColor(R.color
.colorAccent);
} else {
color = NextcloudTalkApplication.getSharedApplication().getResources().getColor(R.color
.colorAccentComplement);
}
messageString = DisplayUtils.searchAndColor(messageString,
"@" + messageParameters.get(key).get("name"), color);
}
}
}
messageText.setText(Html.fromHtml(messageString));
}
}

View File

@ -261,13 +261,13 @@ public interface NcApi {
@GET
Observable<CapabilitiesOverall> getCapabilities(@Header("Authorization") String authorization, @Url String url);
/*
QueryMap items are as follows:
- "lookIntoFuture": int (0 or 1),
- "limit" : int, range 100-200,
- "timeout": used with look into future, 30 default, 60 at most
- "lastKnownMessageId", int, use one from X-Chat-Last-Given
*/
/*
QueryMap items are as follows:
- "lookIntoFuture": int (0 or 1),
- "limit" : int, range 100-200,
- "timeout": used with look into future, 30 default, 60 at most
- "lastKnownMessageId", int, use one from X-Chat-Last-Given
*/
@GET
Observable<Response<ChatOverall>> pullChatMessages(@Header("Authorization") String authorization, @Url String url,
@QueryMap Map<String, Integer> fields);
@ -286,7 +286,7 @@ public interface NcApi {
@GET
Observable<MentionOverall> getMentionAutocompleteSuggestions(@Header("Authorization") String authorization,
@Url String url, @Query("search") String query,
@Nullable @Query("limit") Integer limit);
@Url String url, @Query("search") String query,
@Nullable @Query("limit") Integer limit);
}

View File

@ -118,6 +118,7 @@ public class ChatController extends BaseController implements MessagesListAdapte
private Menu globalMenu;
private Autocomplete mentionAutocomplete;
/*
TODO:
- format mentions

View File

@ -99,15 +99,15 @@ public class ServerSelectionController extends BaseController {
@OnClick(R.id.cert_text_view)
public void onCertClick() {
if (getActivity() != null) {
KeyChain.choosePrivateKeyAlias(getActivity(), alias -> {
if (alias != null) {
appPreferences.setTemporaryClientCertAlias(alias);
} else {
appPreferences.removeTemporaryClientCertAlias();
}
KeyChain.choosePrivateKeyAlias(getActivity(), alias -> {
if (alias != null) {
appPreferences.setTemporaryClientCertAlias(alias);
} else {
appPreferences.removeTemporaryClientCertAlias();
}
setCertTextView();
}, new String[]{"RSA", "EC"}, null, null, -1, null);
setCertTextView();
}, new String[]{"RSA", "EC"}, null, null, -1, null);
}
}

View File

@ -43,12 +43,10 @@ import autodagger.AutoInjector;
@AutoInjector(NextcloudTalkApplication.class)
public abstract class BaseController extends RefWatchingController {
private static final String TAG = "BaseController";
@Inject
AppPreferences appPreferences;
private static final String TAG = "BaseController";
protected BaseController() {
cleanTempCertPreference();
}
@ -72,6 +70,7 @@ public abstract class BaseController extends RefWatchingController {
}
}
@Override
protected void onViewBound(@NonNull View view) {
super.onViewBound(view);

View File

@ -55,9 +55,10 @@ import butterknife.BindView;
* The backstack of each {@link MenuItem} is switched out, in order to maintain a separate backstack
* for each {@link MenuItem} - even though that is against the Google Design Guidelines:
*
* @author chris6647@gmail.com
* @see <a
* href="https://material.io/guidelines/components/bottom-navigation.html#bottom-navigation-behavior">Material
* Design Guidelines</a>
* href="https://material.io/guidelines/components/bottom-navigation.html#bottom-navigation-behavior">Material
* Design Guidelines</a>
*
* Internally works similarly to {@link com.bluelinelabs.conductor.support.RouterPagerAdapter},
* in the sense that it keeps track of the currently active {@link MenuItem} and the paired
@ -66,18 +67,14 @@ import butterknife.BindView;
* of the Child {@link Router}, and cache it, so we have it available when we navigate to
* another {@link MenuItem} and can then restore the correct Child {@link Router}
* (and thus the entire backstack)
*
* @author chris6647@gmail.com
*/
public abstract class BottomNavigationController extends BaseController {
public static final String TAG = "BottomNavigationContr";
public static final int INVALID_INT = -1;
private static final String KEY_MENU_RESOURCE = "key_menu_resource";
private static final String KEY_STATE_ROUTER_BUNDLES = "key_state_router_bundles";
private static final String KEY_STATE_CURRENTLY_SELECTED_ID = "key_state_currently_selected_id";
public static final int INVALID_INT = -1;
@BindView(R.id.navigation)
BottomNavigationView bottomNavigationView;

View File

@ -24,7 +24,6 @@ import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;

View File

@ -160,21 +160,21 @@ public class AccountRemovalJob extends Job {
userEntity.getBaseUrl())
.subscribeOn(Schedulers.newThread())
.subscribe(new CompletableObserver() {
@Override
public void onSubscribe(Disposable d) {
@Override
public void onSubscribe(Disposable d) {
}
}
@Override
public void onComplete() {
@Override
public void onComplete() {
}
}
@Override
public void onError(Throwable e) {
@Override
public void onError(Throwable e) {
}
});
}
});
}
} catch (IOException e) {
Log.d(TAG, "Something went wrong while removing job at parsing PushConfigurationState");
@ -182,21 +182,21 @@ public class AccountRemovalJob extends Job {
userEntity.getBaseUrl())
.subscribeOn(Schedulers.newThread())
.subscribe(new CompletableObserver() {
@Override
public void onSubscribe(Disposable d) {
@Override
public void onSubscribe(Disposable d) {
}
}
@Override
public void onComplete() {
@Override
public void onComplete() {
}
}
@Override
public void onError(Throwable e) {
@Override
public void onError(Throwable e) {
}
});
}
});
}
}
return Result.SUCCESS;

View File

@ -37,6 +37,25 @@ import lombok.Data;
@JsonObject
public class ChatMessage implements IMessage {
String baseUrl;
@JsonField(name = "id")
int jsonMessageId;
@JsonField(name = "token")
String token;
// guests or users
@JsonField(name = "actorType")
String actorType;
@JsonField(name = "actorId")
String actorId;
// send when crafting a message
@JsonField(name = "actorDisplayName")
String actorDisplayName;
@JsonField(name = "timestamp")
long timestamp;
// send when crafting a message, max 1000 lines
@JsonField(name = "message")
String message;
@JsonField(name = "messageParameters")
HashMap<String, HashMap<String, String>> messageParameters;
public String getBaseUrl() {
return baseUrl;
@ -46,33 +65,6 @@ public class ChatMessage implements IMessage {
this.baseUrl = baseUrl;
}
@JsonField(name = "id")
int jsonMessageId;
@JsonField(name = "token")
String token;
// guests or users
@JsonField(name = "actorType")
String actorType;
@JsonField(name = "actorId")
String actorId;
// send when crafting a message
@JsonField(name = "actorDisplayName")
String actorDisplayName;
@JsonField(name = "timestamp")
long timestamp;
// send when crafting a message, max 1000 lines
@JsonField(name = "message")
String message;
@JsonField(name = "messageParameters")
HashMap<String, HashMap<String, String>> messageParameters;
@Override
public String getId() {
return Integer.toString(jsonMessageId);

View File

@ -35,6 +35,7 @@ import lombok.Data;
@Parcel
@JsonObject
public class ChatOCS extends GenericOCS {
@Nullable @JsonField(name = "data")
@Nullable
@JsonField(name = "data")
List<ChatMessage> data;
}

View File

@ -25,15 +25,19 @@ import android.content.Context;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.annotation.ColorInt;
import android.support.annotation.ColorRes;
import android.support.annotation.DrawableRes;
import android.support.v7.widget.AppCompatDrawableManager;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class DisplayUtils {
@ -75,4 +79,28 @@ public class DisplayUtils {
drawable.setTint(color);
return drawable;
}
public static String searchAndColor(String text, String searchText, @ColorInt int color) {
if (TextUtils.isEmpty(text) || TextUtils.isEmpty(searchText)) {
return text;
}
Matcher m = Pattern.compile(searchText, Pattern.CASE_INSENSITIVE | Pattern.LITERAL)
.matcher(text);
StringBuffer sb = new StringBuffer();
while (m.find()) {
String replacement = m.group().replace(
m.group(),
"<font color='" + color + "'><b>" + m.group() + "</b></font>"
);
m.appendReplacement(sb, Matcher.quoteReplacement(replacement));
}
m.appendTail(sb);
return sb.toString();
}
}

View File

@ -3,6 +3,7 @@
<color name="colorPrimary">#0082C9</color>
<color name="colorPrimaryDark">#006AA3</color>
<color name="colorAccent">#007CC2</color>
<color name="colorAccentComplement">#C34700</color>
<color name="nc_darkRed">#D32F2F</color>
<color name="nc_darkGreen">#006400</color>