aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlookshe <github@lookshe.org>2015-08-16 18:45:08 +0200
committerlookshe <github@lookshe.org>2015-08-16 18:45:08 +0200
commit89b28a496542b1995f60efb6b8937d11adf8e425 (patch)
tree2039e26dd5d3fdd8ce3ce277ff1bff8324f32f6e
parenta76de90fe7a53220e9358d38fa7b47b63f7694fe (diff)
parent0321ebb7a6785b4673376f9e6458e41dd96b2230 (diff)
Merge branch 'trz/rebase' into trz/rename
Conflicts: src/main/java/de/thedevstack/conversationsplus/ui/ConversationFragment.java src/main/java/de/thedevstack/conversationsplus/ui/SettingsActivity.java
-rw-r--r--libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconHandler.java85
-rw-r--r--libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconImageSpan.java14
-rw-r--r--libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconsPopup.java28
-rw-r--r--libs/emojicon/src/main/res/drawable/emo_im_angel.png (renamed from src/main/res/drawable/emo_im_angel.png)bin3592 -> 3592 bytes
-rw-r--r--libs/emojicon/src/main/res/drawable/emo_im_cool.png (renamed from src/main/res/drawable/emo_im_cool.png)bin3466 -> 3466 bytes
-rw-r--r--libs/emojicon/src/main/res/drawable/emo_im_crying.png (renamed from src/main/res/drawable/emo_im_crying.png)bin3558 -> 3558 bytes
-rw-r--r--libs/emojicon/src/main/res/drawable/emo_im_embarrassed.png (renamed from src/main/res/drawable/emo_im_embarrassed.png)bin3619 -> 3619 bytes
-rw-r--r--libs/emojicon/src/main/res/drawable/emo_im_foot_in_mouth.png (renamed from src/main/res/drawable/emo_im_foot_in_mouth.png)bin3603 -> 3603 bytes
-rw-r--r--libs/emojicon/src/main/res/drawable/emo_im_happy.png (renamed from src/main/res/drawable/emo_im_happy.png)bin3591 -> 3591 bytes
-rw-r--r--libs/emojicon/src/main/res/drawable/emo_im_heart.png (renamed from src/main/res/drawable/emo_im_heart.png)bin684 -> 684 bytes
-rw-r--r--libs/emojicon/src/main/res/drawable/emo_im_kissing.png (renamed from src/main/res/drawable/emo_im_kissing.png)bin3492 -> 3492 bytes
-rw-r--r--libs/emojicon/src/main/res/drawable/emo_im_laughing.png (renamed from src/main/res/drawable/emo_im_laughing.png)bin3624 -> 3624 bytes
-rw-r--r--libs/emojicon/src/main/res/drawable/emo_im_lips_are_sealed.png (renamed from src/main/res/drawable/emo_im_lips_are_sealed.png)bin3670 -> 3670 bytes
-rw-r--r--libs/emojicon/src/main/res/drawable/emo_im_money_mouth.png (renamed from src/main/res/drawable/emo_im_money_mouth.png)bin3649 -> 3649 bytes
-rw-r--r--libs/emojicon/src/main/res/drawable/emo_im_sad.png (renamed from src/main/res/drawable/emo_im_sad.png)bin3572 -> 3572 bytes
-rw-r--r--libs/emojicon/src/main/res/drawable/emo_im_surprised.png (renamed from src/main/res/drawable/emo_im_surprised.png)bin3490 -> 3490 bytes
-rw-r--r--libs/emojicon/src/main/res/drawable/emo_im_tongue_sticking_out.png (renamed from src/main/res/drawable/emo_im_tongue_sticking_out.png)bin3653 -> 3653 bytes
-rw-r--r--libs/emojicon/src/main/res/drawable/emo_im_undecided.png (renamed from src/main/res/drawable/emo_im_undecided.png)bin3552 -> 3552 bytes
-rw-r--r--libs/emojicon/src/main/res/drawable/emo_im_winking.png (renamed from src/main/res/drawable/emo_im_winking.png)bin3568 -> 3568 bytes
-rw-r--r--libs/emojicon/src/main/res/drawable/emo_im_wtf.png (renamed from src/main/res/drawable/emo_im_wtf.png)bin3591 -> 3591 bytes
-rw-r--r--libs/emojicon/src/main/res/drawable/emo_im_yelling.png (renamed from src/main/res/drawable/emo_im_yelling.png)bin3575 -> 3575 bytes
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/crypto/PgpEngine.java4
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/entities/Account.java6
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/entities/Contact.java2
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/entities/Conversation.java8
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/entities/Message.java62
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/generator/AbstractGenerator.java2
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/services/NotificationService.java2
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/services/XmppConnectionService.java15
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/ui/ConversationActivity.java1
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/ui/ConversationFragment.java140
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/ui/SettingsActivity.java4
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/ui/adapter/ConversationAdapter.java3
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/ui/adapter/MessageAdapter.java7
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/utils/UIHelper.java135
-rw-r--r--src/main/java/eu/siacs/conversations/ui/listeners/ConversationMoreMessagesLoadedListener.java118
-rw-r--r--src/main/java/eu/siacs/conversations/ui/listeners/ConversationSwipeRefreshListener.java48
-rw-r--r--src/main/res/layout/fragment_conversation.xml8
38 files changed, 399 insertions, 293 deletions
diff --git a/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconHandler.java b/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconHandler.java
index c84bebb8..3e032c42 100644
--- a/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconHandler.java
+++ b/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconHandler.java
@@ -19,8 +19,14 @@ import github.ankushsachdeva.emojicon.R;
import android.content.Context;
import android.text.Spannable;
+import android.text.style.ImageSpan;
import android.util.SparseIntArray;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
/**
* @author Hieu Rocker (rockerhieu@gmail.com)
*/
@@ -28,6 +34,16 @@ public final class EmojiconHandler {
private EmojiconHandler() {
}
+ public static boolean isParseEmoticons() {
+ return bParseEmoticons;
+ }
+
+ public static void setParseEmoticons(boolean bParseEmoticons) {
+ EmojiconHandler.bParseEmoticons = bParseEmoticons;
+ }
+
+ private static boolean bParseEmoticons = true;
+
private static final SparseIntArray sEmojisMap = new SparseIntArray(846);
private static final SparseIntArray sSoftbanksMap = new SparseIntArray(471);
@@ -1384,6 +1400,72 @@ public final class EmojiconHandler {
addEmojis(context, text, emojiSize, 0, -1);
}
+ public static final Map<Pattern, Integer> ANDROID_EMOTICONS = new HashMap<Pattern, Integer>();
+
+ private static final Spannable.Factory spannableFactory = Spannable.Factory
+ .getInstance();
+
+ static {
+ addPattern(ANDROID_EMOTICONS, ":-?\\)", R.drawable.emo_im_happy);
+ addPattern(ANDROID_EMOTICONS, ":-?\\(", R.drawable.emo_im_sad);
+ addPattern(ANDROID_EMOTICONS, ";-?\\)", R.drawable.emo_im_winking);
+ addPattern(ANDROID_EMOTICONS, ":-?[pP]",
+ R.drawable.emo_im_tongue_sticking_out);
+ addPattern(ANDROID_EMOTICONS, "=-[oO0]", R.drawable.emo_im_surprised);
+ addPattern(ANDROID_EMOTICONS, ":-?\\*", R.drawable.emo_im_kissing);
+ addPattern(ANDROID_EMOTICONS, ":-?[oO0]", R.drawable.emo_im_wtf);
+ addPattern(ANDROID_EMOTICONS, "[8B]-?\\)", R.drawable.emo_im_cool);
+ addPattern(ANDROID_EMOTICONS, ":-?\\$", R.drawable.emo_im_money_mouth);
+ addPattern(ANDROID_EMOTICONS, ":-?!", R.drawable.emo_im_foot_in_mouth);
+ addPattern(ANDROID_EMOTICONS, ":-?\\[", R.drawable.emo_im_embarrassed);
+ addPattern(ANDROID_EMOTICONS, "[oO0]:-?\\)", R.drawable.emo_im_angel);
+ addPattern(ANDROID_EMOTICONS, ":-?[\\\\/]", R.drawable.emo_im_undecided);
+ addPattern(ANDROID_EMOTICONS, ":'-?\\(", R.drawable.emo_im_crying);
+ addPattern(ANDROID_EMOTICONS, ":-?D", R.drawable.emo_im_laughing);
+ addPattern(ANDROID_EMOTICONS, "O_o", R.drawable.emo_im_wtf);
+ addPattern(ANDROID_EMOTICONS, "o_O", R.drawable.emo_im_wtf);
+ addPattern(ANDROID_EMOTICONS, ">:[oO0]", R.drawable.emo_im_yelling);
+ addPattern(ANDROID_EMOTICONS, ":-?[sS]", R.drawable.emo_im_lips_are_sealed);
+ addPattern(ANDROID_EMOTICONS, "<3", R.drawable.emo_im_heart);
+ }
+
+ private static void addPattern(Map<Pattern, Integer> map, String smile,
+ int resource) {
+ map.put(Pattern.compile(smile), resource);
+ }
+
+ private static boolean getSmiledText(Context context, Spannable spannable) {
+ // remove spans throughout all text
+ ImageSpan[] oldSpans = spannable.getSpans(0, spannable.length(), EmojiconImageSpan.class);
+ for (int i = 0; i < oldSpans.length; i++) {
+ spannable.removeSpan(oldSpans[i]);
+ }
+ boolean hasChanges = false;
+ Map<Pattern, Integer> emoticons = ANDROID_EMOTICONS;
+ for (Map.Entry<Pattern, Integer> entry : emoticons.entrySet()) {
+ Matcher matcher = entry.getKey().matcher(spannable);
+ while (matcher.find()) {
+ boolean set = true;
+ for (EmojiconImageSpan span : spannable.getSpans(matcher.start(),
+ matcher.end(), EmojiconImageSpan.class))
+ if (spannable.getSpanStart(span) >= matcher.start()
+ && spannable.getSpanEnd(span) <= matcher.end())
+ spannable.removeSpan(span);
+ else {
+ set = false;
+ break;
+ }
+ if (set) {
+ spannable.setSpan(new EmojiconImageSpan(context, entry.getValue()),
+ matcher.start(), matcher.end(),
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ hasChanges = true;
+ }
+ }
+ }
+ return hasChanges;
+ }
+
/**
* Convert emoji characters of the given Spannable to the according emojicon.
*
@@ -1394,6 +1476,9 @@ public final class EmojiconHandler {
* @param length
*/
public static void addEmojis(Context context, Spannable text, int emojiSize, int index, int length) {
+ if (isParseEmoticons()) {
+ getSmiledText(context, text);
+ }
int textLength = text.length();
int textLengthToProcessMax = textLength - index;
int textLengthToProcess = length < 0 || length >= textLengthToProcessMax ? textLength : (length+index);
diff --git a/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconImageSpan.java b/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconImageSpan.java
new file mode 100644
index 00000000..8ad8fbb5
--- /dev/null
+++ b/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconImageSpan.java
@@ -0,0 +1,14 @@
+package github.ankushsachdeva.emojicon;
+
+import android.content.Context;
+import android.text.style.ImageSpan;
+
+/**
+ * Created by lookshe on 16.08.2015.
+ */
+public class EmojiconImageSpan extends ImageSpan {
+
+ EmojiconImageSpan(Context context, int resourceId) {
+ super(context, resourceId);
+ }
+}
diff --git a/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconsPopup.java b/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconsPopup.java
index 12bc16e0..b5d26047 100644
--- a/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconsPopup.java
+++ b/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconsPopup.java
@@ -29,16 +29,21 @@ import java.util.List;
import android.app.Activity;
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Rect;
+import android.os.Build;
import android.os.Handler;
import android.os.SystemClock;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.Gravity;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
+import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.WindowManager.LayoutParams;
@@ -155,13 +160,28 @@ public class EmojiconsPopup extends PopupWindow implements ViewPager.OnPageChang
.getHeight();
int heightDifference = screenHeight
- (r.bottom - r.top);
- int resourceId = mContext.getResources()
+ Resources resources = mContext.getResources();
+ int statusBarId = resources
.getIdentifier("status_bar_height",
"dimen", "android");
- if (resourceId > 0) {
- heightDifference -= mContext.getResources()
- .getDimensionPixelSize(resourceId);
+ if (statusBarId > 0) {
+ heightDifference -= resources
+ .getDimensionPixelSize(statusBarId);
}
+
+ //Resolved using http://stackoverflow.com/a/16608481/2853322
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ int navBarId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
+ boolean hasMenuKey;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ hasMenuKey = ViewConfiguration.get(mContext).hasPermanentMenuKey();
+ } else hasMenuKey = true; //Skip has menu key below ICS
+ boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
+ if (navBarId > 0 && !hasMenuKey && !hasBackKey) {
+ heightDifference -= resources.getDimensionPixelSize(navBarId);
+ }
+ }
+
if (heightDifference > 100) {
keyBoardHeight = heightDifference;
setSize(LayoutParams.MATCH_PARENT, keyBoardHeight);
diff --git a/src/main/res/drawable/emo_im_angel.png b/libs/emojicon/src/main/res/drawable/emo_im_angel.png
index c34dfa69..c34dfa69 100644
--- a/src/main/res/drawable/emo_im_angel.png
+++ b/libs/emojicon/src/main/res/drawable/emo_im_angel.png
Binary files differ
diff --git a/src/main/res/drawable/emo_im_cool.png b/libs/emojicon/src/main/res/drawable/emo_im_cool.png
index d8eeb34e..d8eeb34e 100644
--- a/src/main/res/drawable/emo_im_cool.png
+++ b/libs/emojicon/src/main/res/drawable/emo_im_cool.png
Binary files differ
diff --git a/src/main/res/drawable/emo_im_crying.png b/libs/emojicon/src/main/res/drawable/emo_im_crying.png
index 1cafdb32..1cafdb32 100644
--- a/src/main/res/drawable/emo_im_crying.png
+++ b/libs/emojicon/src/main/res/drawable/emo_im_crying.png
Binary files differ
diff --git a/src/main/res/drawable/emo_im_embarrassed.png b/libs/emojicon/src/main/res/drawable/emo_im_embarrassed.png
index e4db9634..e4db9634 100644
--- a/src/main/res/drawable/emo_im_embarrassed.png
+++ b/libs/emojicon/src/main/res/drawable/emo_im_embarrassed.png
Binary files differ
diff --git a/src/main/res/drawable/emo_im_foot_in_mouth.png b/libs/emojicon/src/main/res/drawable/emo_im_foot_in_mouth.png
index 09d1fba6..09d1fba6 100644
--- a/src/main/res/drawable/emo_im_foot_in_mouth.png
+++ b/libs/emojicon/src/main/res/drawable/emo_im_foot_in_mouth.png
Binary files differ
diff --git a/src/main/res/drawable/emo_im_happy.png b/libs/emojicon/src/main/res/drawable/emo_im_happy.png
index b86602ae..b86602ae 100644
--- a/src/main/res/drawable/emo_im_happy.png
+++ b/libs/emojicon/src/main/res/drawable/emo_im_happy.png
Binary files differ
diff --git a/src/main/res/drawable/emo_im_heart.png b/libs/emojicon/src/main/res/drawable/emo_im_heart.png
index d88bcccd..d88bcccd 100644
--- a/src/main/res/drawable/emo_im_heart.png
+++ b/libs/emojicon/src/main/res/drawable/emo_im_heart.png
Binary files differ
diff --git a/src/main/res/drawable/emo_im_kissing.png b/libs/emojicon/src/main/res/drawable/emo_im_kissing.png
index 56378f6a..56378f6a 100644
--- a/src/main/res/drawable/emo_im_kissing.png
+++ b/libs/emojicon/src/main/res/drawable/emo_im_kissing.png
Binary files differ
diff --git a/src/main/res/drawable/emo_im_laughing.png b/libs/emojicon/src/main/res/drawable/emo_im_laughing.png
index 980bf281..980bf281 100644
--- a/src/main/res/drawable/emo_im_laughing.png
+++ b/libs/emojicon/src/main/res/drawable/emo_im_laughing.png
Binary files differ
diff --git a/src/main/res/drawable/emo_im_lips_are_sealed.png b/libs/emojicon/src/main/res/drawable/emo_im_lips_are_sealed.png
index f2de993b..f2de993b 100644
--- a/src/main/res/drawable/emo_im_lips_are_sealed.png
+++ b/libs/emojicon/src/main/res/drawable/emo_im_lips_are_sealed.png
Binary files differ
diff --git a/src/main/res/drawable/emo_im_money_mouth.png b/libs/emojicon/src/main/res/drawable/emo_im_money_mouth.png
index 08c53fd6..08c53fd6 100644
--- a/src/main/res/drawable/emo_im_money_mouth.png
+++ b/libs/emojicon/src/main/res/drawable/emo_im_money_mouth.png
Binary files differ
diff --git a/src/main/res/drawable/emo_im_sad.png b/libs/emojicon/src/main/res/drawable/emo_im_sad.png
index 31c08d06..31c08d06 100644
--- a/src/main/res/drawable/emo_im_sad.png
+++ b/libs/emojicon/src/main/res/drawable/emo_im_sad.png
Binary files differ
diff --git a/src/main/res/drawable/emo_im_surprised.png b/libs/emojicon/src/main/res/drawable/emo_im_surprised.png
index abe8c7ad..abe8c7ad 100644
--- a/src/main/res/drawable/emo_im_surprised.png
+++ b/libs/emojicon/src/main/res/drawable/emo_im_surprised.png
Binary files differ
diff --git a/src/main/res/drawable/emo_im_tongue_sticking_out.png b/libs/emojicon/src/main/res/drawable/emo_im_tongue_sticking_out.png
index 6f0f47b0..6f0f47b0 100644
--- a/src/main/res/drawable/emo_im_tongue_sticking_out.png
+++ b/libs/emojicon/src/main/res/drawable/emo_im_tongue_sticking_out.png
Binary files differ
diff --git a/src/main/res/drawable/emo_im_undecided.png b/libs/emojicon/src/main/res/drawable/emo_im_undecided.png
index eb4f8c5b..eb4f8c5b 100644
--- a/src/main/res/drawable/emo_im_undecided.png
+++ b/libs/emojicon/src/main/res/drawable/emo_im_undecided.png
Binary files differ
diff --git a/src/main/res/drawable/emo_im_winking.png b/libs/emojicon/src/main/res/drawable/emo_im_winking.png
index 568562ad..568562ad 100644
--- a/src/main/res/drawable/emo_im_winking.png
+++ b/libs/emojicon/src/main/res/drawable/emo_im_winking.png
Binary files differ
diff --git a/src/main/res/drawable/emo_im_wtf.png b/libs/emojicon/src/main/res/drawable/emo_im_wtf.png
index 41dd47fc..41dd47fc 100644
--- a/src/main/res/drawable/emo_im_wtf.png
+++ b/libs/emojicon/src/main/res/drawable/emo_im_wtf.png
Binary files differ
diff --git a/src/main/res/drawable/emo_im_yelling.png b/libs/emojicon/src/main/res/drawable/emo_im_yelling.png
index c3c8612b..c3c8612b 100644
--- a/src/main/res/drawable/emo_im_yelling.png
+++ b/libs/emojicon/src/main/res/drawable/emo_im_yelling.png
Binary files differ
diff --git a/src/main/java/de/thedevstack/conversationsplus/crypto/PgpEngine.java b/src/main/java/de/thedevstack/conversationsplus/crypto/PgpEngine.java
index 4b8e339c..49c8db54 100644
--- a/src/main/java/de/thedevstack/conversationsplus/crypto/PgpEngine.java
+++ b/src/main/java/de/thedevstack/conversationsplus/crypto/PgpEngine.java
@@ -244,7 +244,7 @@ public class PgpEngine {
pgpSig.append("-----BEGIN PGP SIGNATURE-----");
pgpSig.append('\n');
pgpSig.append('\n');
- pgpSig.append(signature.replace("\n", "").trim());
+ pgpSig.append(signature.replace("\n", ""));
pgpSig.append('\n');
pgpSig.append("-----END PGP SIGNATURE-----");
Intent params = new Intent();
@@ -297,7 +297,7 @@ public class PgpEngine {
sig = false;
} else {
if (!line.contains("Version")) {
- signatureBuilder.append(line.trim());
+ signatureBuilder.append(line);
}
}
}
diff --git a/src/main/java/de/thedevstack/conversationsplus/entities/Account.java b/src/main/java/de/thedevstack/conversationsplus/entities/Account.java
index b620887e..8d879fa0 100644
--- a/src/main/java/de/thedevstack/conversationsplus/entities/Account.java
+++ b/src/main/java/de/thedevstack/conversationsplus/entities/Account.java
@@ -128,6 +128,7 @@ public class Account extends AbstractEntity {
private final Roster roster = new Roster(this);
private List<Bookmark> bookmarks = new CopyOnWriteArrayList<>();
private final Collection<Jid> blocklist = new CopyOnWriteArraySet<>();
+ private XmppConnectionService mXmppConnectionService;
public Account() {
this.uuid = "0";
@@ -278,6 +279,7 @@ public class Account extends AbstractEntity {
}
public void initAccountServices(final XmppConnectionService context) {
+ this.mXmppConnectionService = context;
this.mOtrService = new OtrService(context, this);
}
@@ -418,4 +420,8 @@ public class Account extends AbstractEntity {
public boolean isOnlineAndConnected() {
return this.getStatus() == State.ONLINE && this.getXmppConnection() != null;
}
+
+ public XmppConnectionService getXmppConnectionService() {
+ return mXmppConnectionService;
+ }
}
diff --git a/src/main/java/de/thedevstack/conversationsplus/entities/Contact.java b/src/main/java/de/thedevstack/conversationsplus/entities/Contact.java
index d72a1197..ca734403 100644
--- a/src/main/java/de/thedevstack/conversationsplus/entities/Contact.java
+++ b/src/main/java/de/thedevstack/conversationsplus/entities/Contact.java
@@ -162,7 +162,7 @@ public class Contact implements ListItem, Blockable {
if (needle == null || needle.isEmpty()) {
return true;
}
- needle = needle.toLowerCase(Locale.US).trim();
+ needle = needle.toLowerCase(Locale.US);
String[] parts = needle.split("\\s+");
if (parts.length > 1) {
for(int i = 0; i < parts.length; ++i) {
diff --git a/src/main/java/de/thedevstack/conversationsplus/entities/Conversation.java b/src/main/java/de/thedevstack/conversationsplus/entities/Conversation.java
index 81c2eb4b..8d4b3c27 100644
--- a/src/main/java/de/thedevstack/conversationsplus/entities/Conversation.java
+++ b/src/main/java/de/thedevstack/conversationsplus/entities/Conversation.java
@@ -759,11 +759,17 @@ public class Conversation extends AbstractEntity implements Blockable {
synchronized (this.messages) {
int count = 0;
for(int i = this.messages.size() - 1; i >= 0; --i) {
- if (this.messages.get(i).isRead()) {
+ Message message = this.messages.get(i);
+ if (message.isRead()) {
return count;
}
+ if (getMode() == Conversation.MODE_SINGLE
+ || account.getXmppConnectionService().getNotificationService().conferenceNotificationsEnabled()
+ || account.getXmppConnectionService().getNotificationService().wasHighlightedOrPrivate(message)
+ ) {
++count;
}
+ }
return count;
}
}
diff --git a/src/main/java/de/thedevstack/conversationsplus/entities/Message.java b/src/main/java/de/thedevstack/conversationsplus/entities/Message.java
index 68b47578..a5d06f46 100644
--- a/src/main/java/de/thedevstack/conversationsplus/entities/Message.java
+++ b/src/main/java/de/thedevstack/conversationsplus/entities/Message.java
@@ -59,7 +59,7 @@ public class Message extends AbstractEntity {
protected String conversationUuid;
protected Jid counterpart;
protected Jid trueCounterpart;
- protected String body;
+ private String body;
protected String encryptedBody;
protected long timeSent;
protected int encryption;
@@ -319,16 +319,16 @@ public class Message extends AbstractEntity {
public boolean equals(Message message) {
if (this.serverMsgId != null && message.getServerMsgId() != null) {
return this.serverMsgId.equals(message.getServerMsgId());
- } else if (this.body == null || this.counterpart == null) {
+ } else if (this.getBody() == null || this.counterpart == null) {
return false;
} else {
String body, otherBody;
if (this.hasFileOnRemoteHost()) {
body = getFileParams().url.toString();
- otherBody = message.body == null ? null : message.body.trim();
+ otherBody = message.getBody() == null ? null : message.getBody();
} else {
- body = this.body;
- otherBody = message.body;
+ body = this.getBody();
+ otherBody = message.getBody();
}
if (message.getRemoteMsgId() != null) {
return (message.getRemoteMsgId().equals(this.remoteMsgId) || message.getRemoteMsgId().equals(this.uuid))
@@ -385,13 +385,11 @@ public class Message extends AbstractEntity {
this.getCounterpart().equals(message.getCounterpart()) &&
(message.getTimeSent() - this.getTimeSent()) <= (Config.MESSAGE_MERGE_WINDOW * 1000) &&
!GeoHelper.isGeoUri(message.getBody()) &&
- !GeoHelper.isGeoUri(this.body) &&
+ !GeoHelper.isGeoUri(this.getBody()) &&
message.treatAsDownloadable() == Decision.NEVER &&
this.treatAsDownloadable() == Decision.NEVER &&
!message.getBody().startsWith(ME_COMMAND) &&
- !this.getBody().startsWith(ME_COMMAND) &&
- !this.bodyIsHeart() &&
- !message.bodyIsHeart()
+ !this.getBody().startsWith(ME_COMMAND)
);
}
@@ -473,17 +471,28 @@ public class Message extends AbstractEntity {
private static String extractRelevantExtension(URL url) {
String path = url.getPath();
+ return extractRelevantExtension(path);
+ }
+
+ private static String extractRelevantExtension(String path) {
if (path == null || path.isEmpty()) {
return null;
}
+
String filename = path.substring(path.lastIndexOf('/') + 1).toLowerCase();
- String[] extensionParts = filename.split("\\.");
- if (extensionParts.length == 2) {
- return extensionParts[extensionParts.length - 1];
- } else if (extensionParts.length == 3 && Arrays
- .asList(Transferable.VALID_CRYPTO_EXTENSIONS)
- .contains(extensionParts[extensionParts.length - 1])) {
- return extensionParts[extensionParts.length -2];
+
+ int dotPosition = filename.lastIndexOf(".");
+
+ if (dotPosition != -1)
+ {
+ String extension = filename.substring(dotPosition + 1);
+
+ // we want the real file extension, not the crypto one
+ if (Arrays.asList(Transferable.VALID_CRYPTO_EXTENSIONS).contains(extension)) {
+ return extractRelevantExtension(path.substring(0,dotPosition));
+ } else {
+ return extension;
+ }
}
return null;
}
@@ -498,7 +507,7 @@ public class Message extends AbstractEntity {
}
} else {
try {
- return MimeUtils.guessMimeTypeFromExtension(extractRelevantExtension(new URL(body.trim())));
+ return MimeUtils.guessMimeTypeFromExtension(extractRelevantExtension(new URL(this.getBody())));
} catch (MalformedURLException e) {
return null;
}
@@ -506,7 +515,12 @@ public class Message extends AbstractEntity {
}
public Decision treatAsDownloadable() {
- if (body.trim().contains(" ")) {
+ /**
+ * there are a few cases where spaces result in an unwanted behavior, e.g.
+ * "http://example.com/image.jpg" text that will not be shown /abc.png"
+ * or more than one image link in one message.
+ */
+ if (getBody().contains(" ")) {
return Decision.NEVER;
}
try {
@@ -539,10 +553,6 @@ public class Message extends AbstractEntity {
}
}
- public boolean bodyIsHeart() {
- return body != null && UIHelper.HEARTS.contains(body.trim());
- }
-
public FileParams getFileParams() {
FileParams params = getLegacyFileParams();
if (params != null) {
@@ -552,10 +562,10 @@ public class Message extends AbstractEntity {
if (this.transferable != null) {
params.size = this.transferable.getFileSize();
}
- if (body == null) {
+ if (this.getBody() == null) {
return params;
}
- String parts[] = body.split("\\|");
+ String parts[] = this.getBody().split("\\|");
switch (parts.length) {
case 1:
try {
@@ -614,10 +624,10 @@ public class Message extends AbstractEntity {
public FileParams getLegacyFileParams() {
FileParams params = new FileParams();
- if (body == null) {
+ if (this.getBody() == null) {
return params;
}
- String parts[] = body.split(",");
+ String parts[] = this.getBody().split(",");
if (parts.length == 3) {
try {
params.size = Long.parseLong(parts[0]);
diff --git a/src/main/java/de/thedevstack/conversationsplus/generator/AbstractGenerator.java b/src/main/java/de/thedevstack/conversationsplus/generator/AbstractGenerator.java
index cb56228d..859a8a6c 100644
--- a/src/main/java/de/thedevstack/conversationsplus/generator/AbstractGenerator.java
+++ b/src/main/java/de/thedevstack/conversationsplus/generator/AbstractGenerator.java
@@ -71,7 +71,7 @@ public abstract class AbstractGenerator {
s.append(feature + "<");
}
byte[] sha1 = md.digest(s.toString().getBytes());
- return new String(Base64.encode(sha1, Base64.DEFAULT)).trim();
+ return new String(Base64.encode(sha1, Base64.DEFAULT));
}
public static String getTimestamp(long time) {
diff --git a/src/main/java/de/thedevstack/conversationsplus/services/NotificationService.java b/src/main/java/de/thedevstack/conversationsplus/services/NotificationService.java
index 52d7e2a2..563a7d67 100644
--- a/src/main/java/de/thedevstack/conversationsplus/services/NotificationService.java
+++ b/src/main/java/de/thedevstack/conversationsplus/services/NotificationService.java
@@ -442,7 +442,7 @@ public class NotificationService {
return PendingIntent.getService(mXmppConnectionService,0,intent,PendingIntent.FLAG_UPDATE_CURRENT);
}
- private boolean wasHighlightedOrPrivate(final Message message) {
+ public boolean wasHighlightedOrPrivate(final Message message) {
final String nick = message.getConversation().getMucOptions().getActualNick();
final Pattern highlight = generateNickHighlightPattern(nick);
if (message.getBody() == null || nick == null) {
diff --git a/src/main/java/de/thedevstack/conversationsplus/services/XmppConnectionService.java b/src/main/java/de/thedevstack/conversationsplus/services/XmppConnectionService.java
index e5125f29..8ff5f0d2 100644
--- a/src/main/java/de/thedevstack/conversationsplus/services/XmppConnectionService.java
+++ b/src/main/java/de/thedevstack/conversationsplus/services/XmppConnectionService.java
@@ -1047,6 +1047,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
public void loadMoreMessages(final Conversation conversation, final long timestamp, final OnMoreMessagesLoaded callback) {
Log.d(Config.LOGTAG, "load more messages for " + conversation.getName() + " prior to " + MessageGenerator.getTimestamp(timestamp));
if (XmppConnectionService.this.getMessageArchiveService().queryInProgress(conversation,callback)) {
+ Log.d("mam", "Query in progress");
return;
}
Runnable runnable = new Runnable() {
@@ -1054,18 +1055,25 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
public void run() {
final Account account = conversation.getAccount();
List<Message> messages = databaseBackend.getMessages(conversation, 50,timestamp);
+ Log.d("mam", "runnable load more messages");
if (messages.size() > 0) {
+ Log.d("mam", "At least one message");
conversation.addAll(0, messages);
checkDeletedFiles(conversation);
callback.onMoreMessagesLoaded(messages.size(), conversation);
} else if (conversation.hasMessagesLeftOnServer()
&& account.isOnlineAndConnected()
&& account.getXmppConnection().getFeatures().mam()) {
+ Log.d("mam", "mam activate, account online and connected and messages left on server");
MessageArchiveService.Query query = getMessageArchiveService().query(conversation,0,timestamp - 1);
if (query != null) {
query.setCallback(callback);
}
callback.informUser(R.string.fetching_history_from_server);
+ } else {
+ Log.d("mam", ((!conversation.hasMessagesLeftOnServer()) ? "no" : "") + " more messages left on server, mam " + ((account.getXmppConnection().getFeatures().mam()) ? "" : "not") + " activated, account is " + ((account.isOnlineAndConnected()) ? "" : "not") + " online or connected)");
+ callback.onMoreMessagesLoaded(0, conversation);
+ callback.informUser(R.string.no_more_history_on_server);
}
}
};
@@ -2496,7 +2504,12 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
public void clearConversationHistory(final Conversation conversation) {
conversation.clearMessages();
- conversation.setHasMessagesLeftOnServer(false); //avoid messages getting loaded through mam
+ /*
+ * In case the history was loaded completely before.
+ * The flag "hasMessagesLeftOnServer" is set to false and no messages will be loaded anymore
+ * Therefore set this flag to true and try to get messages from server
+ */
+ conversation.setHasMessagesLeftOnServer(true);
new Thread(new Runnable() {
@Override
public void run() {
diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/ConversationActivity.java b/src/main/java/de/thedevstack/conversationsplus/ui/ConversationActivity.java
index f5de4ae8..cff681a9 100644
--- a/src/main/java/de/thedevstack/conversationsplus/ui/ConversationActivity.java
+++ b/src/main/java/de/thedevstack/conversationsplus/ui/ConversationActivity.java
@@ -247,6 +247,7 @@ public class ConversationActivity extends XmppActivity
}
});
listView.enableSwipeToDismiss();
+ listView.setSwipeDirection(EnhancedListView.SwipeDirection.START);
listView.setSwipingLayout(R.id.swipeable_item);
listView.setUndoStyle(EnhancedListView.UndoStyle.SINGLE_POPUP);
listView.setUndoHideDelay(5000);
diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/ConversationFragment.java b/src/main/java/de/thedevstack/conversationsplus/ui/ConversationFragment.java
index a30b3483..26e2b3c1 100644
--- a/src/main/java/de/thedevstack/conversationsplus/ui/ConversationFragment.java
+++ b/src/main/java/de/thedevstack/conversationsplus/ui/ConversationFragment.java
@@ -10,7 +10,9 @@ import android.content.Intent;
import android.content.IntentSender;
import android.content.IntentSender.SendIntentException;
import android.os.Bundle;
+import android.support.v4.widget.SwipeRefreshLayout;
import android.text.InputType;
+import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Gravity;
@@ -22,8 +24,6 @@ import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
-import android.widget.AbsListView;
-import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.ImageButton;
@@ -107,6 +107,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
}
};
protected ListView messagesView;
+ protected SwipeRefreshLayout swipeLayout;
final protected List<Message> messageList = new ArrayList<>();
protected MessageAdapter messageListAdapter;
private EditMessage mEditMessage;
@@ -117,96 +118,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
private RelativeLayout snackbar;
private TextView snackbarMessage;
private TextView snackbarAction;
- private boolean messagesLoaded = true;
- private Toast messageLoaderToast;
-
- private OnScrollListener mOnScrollListener = new OnScrollListener() {
-
- @Override
- public void onScrollStateChanged(AbsListView view, int scrollState) {
- // TODO Auto-generated method stub
-
- }
-
- private int getIndexOf(String uuid, List<Message> messages) {
- if (uuid == null) {
- return 0;
- }
- for(int i = 0; i < messages.size(); ++i) {
- if (uuid.equals(messages.get(i).getUuid())) {
- return i;
- } else {
- Message next = messages.get(i);
- while(next != null && next.wasMergedIntoPrevious()) {
- if (uuid.equals(next.getUuid())) {
- return i;
- }
- next = next.next();
- }
-
- }
- }
- return 0;
- }
-
- @Override
- public void onScroll(AbsListView view, int firstVisibleItem,
- int visibleItemCount, int totalItemCount) {
- synchronized (ConversationFragment.this.messageList) {
- if (firstVisibleItem < 5 && messagesLoaded && messageList.size() > 0) {
- long timestamp = ConversationFragment.this.messageList.get(0).getTimeSent();
- messagesLoaded = false;
- activity.xmppConnectionService.loadMoreMessages(conversation, timestamp, new XmppConnectionService.OnMoreMessagesLoaded() {
- @Override
- public void onMoreMessagesLoaded(final int c, Conversation conversation) {
- if (ConversationFragment.this.conversation != conversation) {
- return;
- }
- activity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- final int oldPosition = messagesView.getFirstVisiblePosition();
- Message message = messageList.get(oldPosition);
- String uuid = message != null ? message.getUuid() : null;
- View v = messagesView.getChildAt(0);
- final int pxOffset = (v == null) ? 0 : v.getTop();
- ConversationFragment.this.conversation.populateWithMessages(ConversationFragment.this.messageList);
- updateStatusMessages();
- messageListAdapter.notifyDataSetChanged();
- int pos = getIndexOf(uuid,messageList);
- messagesView.setSelectionFromTop(pos, pxOffset);
- messagesLoaded = true;
- if (messageLoaderToast != null) {
- messageLoaderToast.cancel();
- }
- }
- });
- }
-
- @Override
- public void informUser(final int resId) {
-
- activity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- if (messageLoaderToast != null) {
- messageLoaderToast.cancel();
- }
- if (ConversationFragment.this.conversation != conversation) {
- return;
- }
- messageLoaderToast = Toast.makeText(activity, resId, Toast.LENGTH_LONG);
- messageLoaderToast.show();
- }
- });
-
- }
- });
-
- }
- }
- }
- };
private IntentSender askForPassphraseIntent = null;
protected OnClickListener clickToDecryptListener = new OnClickListener() {
@@ -379,26 +290,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
//Will automatically set size according to the soft keyboard size
mEmojPopup.setSizeForSoftKeyboard();
- //Set on emojicon click listener
- mEmojPopup.setOnEmojiconClickedListener(new EmojiconGridView.OnEmojiconClickedListener() {
-
- @Override
- public void onEmojiconClicked(Emojicon emojicon) {
- mEditMessage.append(emojicon.getEmoji());
- }
- });
-
- //Set on backspace click listener
- mEmojPopup.setOnEmojiconBackspaceClickedListener(new EmojiconsPopup.OnEmojiconBackspaceClickedListener() {
-
- @Override
- public void onEmojiconBackspaceClicked(View v) {
- KeyEvent event = new KeyEvent(
- 0, 0, 0, KeyEvent.KEYCODE_DEL, 0, 0, 0, 0, KeyEvent.KEYCODE_ENDCALL);
- mEditMessage.dispatchKeyEvent(event);
- }
- });
-
//If the emoji popup is dismissed, change emojiButton to smiley icon
mEmojPopup.setOnDismissListener(new PopupWindow.OnDismissListener() {
@@ -428,7 +319,19 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
@Override
public void onEmojiconClicked(Emojicon emojicon) {
+ if (mEditMessage == null || emojicon == null) {
+ return;
+ }
+
+ int start = mEditMessage.getSelectionStart();
+ int end = mEditMessage.getSelectionEnd();
+ if (start < 0) {
mEditMessage.append(emojicon.getEmoji());
+ } else {
+ mEditMessage.getText().replace(Math.min(start, end),
+ Math.max(start, end), emojicon.getEmoji(), 0,
+ emojicon.getEmoji().length());
+ }
}
});
@@ -486,7 +389,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
snackbarAction = (TextView) view.findViewById(R.id.snackbar_action);
messagesView = (ListView) view.findViewById(R.id.messages_view);
- messagesView.setOnScrollListener(mOnScrollListener);
messagesView.setTranscriptMode(ListView.TRANSCRIPT_MODE_NORMAL);
messageListAdapter = new MessageAdapter((ConversationActivity) getActivity(), this.messageList);
messageListAdapter.setOnContactPictureClicked(new OnContactPictureClicked() {
@@ -533,6 +435,12 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
registerForContextMenu(messagesView);
+ // Start of swipe refresh
+ // New Swipe refresh
+ swipeLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipe_refresh_container);
+ swipeLayout.setOnRefreshListener(new ConversationSwipeRefreshListener(messageList, swipeLayout, this, messagesView, messageListAdapter));
+ // End of swipe refresh
+
return view;
}
@@ -671,7 +579,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
resId = R.string.file_url;
url = message.getFileParams().url.toString();
} else {
- url = message.getBody().trim();
+ url = message.getBody();
resId = R.string.file_url;
}
if (activity.copyTextToClipboard(url, resId)) {
@@ -763,11 +671,11 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
this.mEditMessage.setKeyboardListener(this);
this.messagesView.setAdapter(messageListAdapter);
updateMessages();
- this.messagesLoaded = true;
int size = this.messageList.size();
if (size > 0) {
messagesView.setSelection(size - 1);
}
+ swipeLayout.setRefreshing(false);
}
private OnClickListener mUnblockClickListener = new OnClickListener() {
@@ -1094,7 +1002,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
this.mSendButton.setImageResource(getSendButtonImageResource(action, status));
}
- protected void updateStatusMessages() {
+ public void updateStatusMessages() {
synchronized (this.messageList) {
if (conversation.getMode() == Conversation.MODE_SINGLE) {
ChatState state = conversation.getIncomingChatState();
diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/SettingsActivity.java b/src/main/java/de/thedevstack/conversationsplus/ui/SettingsActivity.java
index 36e2cca0..46a68f65 100644
--- a/src/main/java/de/thedevstack/conversationsplus/ui/SettingsActivity.java
+++ b/src/main/java/de/thedevstack/conversationsplus/ui/SettingsActivity.java
@@ -12,6 +12,7 @@ import de.duenndns.ssl.MemorizingTrustManager;
import de.thedevstack.conversationsplus.R;
import de.thedevstack.conversationsplus.entities.Account;
import de.thedevstack.conversationsplus.xmpp.XmppConnection;
+import github.ankushsachdeva.emojicon.EmojiconHandler;
import android.app.AlertDialog;
import android.app.Fragment;
@@ -168,6 +169,9 @@ public class SettingsActivity extends XmppActivity implements
xmppConnectionService.updateMemorizingTrustmanager();
reconnectAccounts();
break;
+ case "parse_emoticons":
+ EmojiconHandler.setParseEmoticons(Settings.PARSE_EMOTICONS);
+ break;
}
}
diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/adapter/ConversationAdapter.java b/src/main/java/de/thedevstack/conversationsplus/ui/adapter/ConversationAdapter.java
index c9698114..2da7bea3 100644
--- a/src/main/java/de/thedevstack/conversationsplus/ui/adapter/ConversationAdapter.java
+++ b/src/main/java/de/thedevstack/conversationsplus/ui/adapter/ConversationAdapter.java
@@ -107,8 +107,7 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
Pair<String,Boolean> preview = UIHelper.getMessagePreview(activity,message);
mLastMessage.setVisibility(View.VISIBLE);
imagePreview.setVisibility(View.GONE);
- boolean parseEmoticons = Settings.PARSE_EMOTICONS;
- CharSequence msgText = parseEmoticons ? UIHelper.transformAsciiEmoticons(getContext(), preview.first) : preview.first;
+ CharSequence msgText = preview.first;
mLastMessage.setText(msgText);
if (preview.second) {
if (conversation.isRead()) {
diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/adapter/MessageAdapter.java b/src/main/java/de/thedevstack/conversationsplus/ui/adapter/MessageAdapter.java
index 67391136..48debdaf 100644
--- a/src/main/java/de/thedevstack/conversationsplus/ui/adapter/MessageAdapter.java
+++ b/src/main/java/de/thedevstack/conversationsplus/ui/adapter/MessageAdapter.java
@@ -251,10 +251,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
viewHolder.messageBody.setText(span);
} else {
- boolean parseEmoticons = Settings.PARSE_EMOTICONS;
- viewHolder.messageBody.setText(parseEmoticons ? UIHelper
- .transformAsciiEmoticons(getContext(), message.getMergedBody())
- : formattedBody);
+ viewHolder.messageBody.setText(formattedBody);
}
} else {
String privateMarker;
@@ -528,8 +525,6 @@ public class MessageAdapter extends ArrayAdapter<Message> {
} else {
if (GeoHelper.isGeoUri(message.getBody())) {
displayLocationMessage(viewHolder,message);
- } else if (message.bodyIsHeart()) {
- displayHeartMessage(viewHolder, message.getBody().trim());
} else if (message.treatAsDownloadable() == Message.Decision.MUST) {
displayDownloadableMessage(viewHolder, message, activity.getString(R.string.check_x_filesize, UIHelper.getFileDescriptionString(activity, message)));
} else {
diff --git a/src/main/java/de/thedevstack/conversationsplus/utils/UIHelper.java b/src/main/java/de/thedevstack/conversationsplus/utils/UIHelper.java
index a66b1bf8..0ef07808 100644
--- a/src/main/java/de/thedevstack/conversationsplus/utils/UIHelper.java
+++ b/src/main/java/de/thedevstack/conversationsplus/utils/UIHelper.java
@@ -141,135 +141,6 @@ public class UIHelper {
}
}
- public static final Map<Pattern, Integer> ANDROID_EMOTICONS = new HashMap<Pattern, Integer>();
-
- private static final Factory spannableFactory = Spannable.Factory
- .getInstance();
-
- static {
- addPattern(ANDROID_EMOTICONS, ":)", R.drawable.emo_im_happy);
- addPattern(ANDROID_EMOTICONS, ":-)", R.drawable.emo_im_happy);
- addPattern(ANDROID_EMOTICONS, ":(", R.drawable.emo_im_sad);
- addPattern(ANDROID_EMOTICONS, ":-(", R.drawable.emo_im_sad);
- addPattern(ANDROID_EMOTICONS, ";)", R.drawable.emo_im_winking);
- addPattern(ANDROID_EMOTICONS, ";-)", R.drawable.emo_im_winking);
- addPattern(ANDROID_EMOTICONS, ":P",
- R.drawable.emo_im_tongue_sticking_out);
- addPattern(ANDROID_EMOTICONS, ":-P",
- R.drawable.emo_im_tongue_sticking_out);
- addPattern(ANDROID_EMOTICONS, "=-O", R.drawable.emo_im_surprised);
- addPattern(ANDROID_EMOTICONS, ":*", R.drawable.emo_im_kissing);
- addPattern(ANDROID_EMOTICONS, ":-*", R.drawable.emo_im_kissing);
- addPattern(ANDROID_EMOTICONS, ":O", R.drawable.emo_im_wtf);
- addPattern(ANDROID_EMOTICONS, ":-O", R.drawable.emo_im_wtf);
- addPattern(ANDROID_EMOTICONS, "B)", R.drawable.emo_im_cool);
- addPattern(ANDROID_EMOTICONS, "B-)", R.drawable.emo_im_cool);
- addPattern(ANDROID_EMOTICONS, "8)", R.drawable.emo_im_cool);
- addPattern(ANDROID_EMOTICONS, "8-)", R.drawable.emo_im_cool);
- addPattern(ANDROID_EMOTICONS, ":$", R.drawable.emo_im_money_mouth);
- addPattern(ANDROID_EMOTICONS, ":-$", R.drawable.emo_im_money_mouth);
- addPattern(ANDROID_EMOTICONS, ":-!", R.drawable.emo_im_foot_in_mouth);
- addPattern(ANDROID_EMOTICONS, ":-[", R.drawable.emo_im_embarrassed);
- addPattern(ANDROID_EMOTICONS, "O:)", R.drawable.emo_im_angel);
- addPattern(ANDROID_EMOTICONS, "O:-)", R.drawable.emo_im_angel);
- addPattern(ANDROID_EMOTICONS, ":\\", R.drawable.emo_im_undecided);
- addPattern(ANDROID_EMOTICONS, ":-\\", R.drawable.emo_im_undecided);
- addPattern(ANDROID_EMOTICONS, ":'(", R.drawable.emo_im_crying);
- addPattern(ANDROID_EMOTICONS, ":D", R.drawable.emo_im_laughing);
- addPattern(ANDROID_EMOTICONS, ":-D", R.drawable.emo_im_laughing);
- addPattern(ANDROID_EMOTICONS, "O_o", R.drawable.emo_im_wtf);
- addPattern(ANDROID_EMOTICONS, "o_O", R.drawable.emo_im_wtf);
- addPattern(ANDROID_EMOTICONS, ">:O", R.drawable.emo_im_yelling);
- addPattern(ANDROID_EMOTICONS, ">:0", R.drawable.emo_im_yelling);
- addPattern(ANDROID_EMOTICONS, ":S", R.drawable.emo_im_lips_are_sealed);
- addPattern(ANDROID_EMOTICONS, ":-S", R.drawable.emo_im_lips_are_sealed);
- addPattern(ANDROID_EMOTICONS, "<3", R.drawable.emo_im_heart);
- }
-
- private static void addPattern(Map<Pattern, Integer> map, String smile,
- int resource) {
- map.put(Pattern.compile(Pattern.quote(smile)), resource);
- }
-
- private static boolean getSmiledText(Context context, Spannable spannable) {
- boolean hasChanges = false;
- Map<Pattern, Integer> emoticons = ANDROID_EMOTICONS;
- for (Entry<Pattern, Integer> entry : emoticons.entrySet()) {
- Matcher matcher = entry.getKey().matcher(spannable);
- while (matcher.find()) {
- boolean set = true;
- for (ImageSpan span : spannable.getSpans(matcher.start(),
- matcher.end(), ImageSpan.class))
- if (spannable.getSpanStart(span) >= matcher.start()
- && spannable.getSpanEnd(span) <= matcher.end())
- spannable.removeSpan(span);
- else {
- set = false;
- break;
- }
- if (set) {
- spannable.setSpan(new ImageSpan(context, entry.getValue()),
- matcher.start(), matcher.end(),
- Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- hasChanges = true;
- }
- }
- }
- return hasChanges;
- }
-
- private final static class EmoticonPattern {
- Pattern pattern;
- String replacement;
-
- EmoticonPattern(String ascii, int unicode) {
- this.pattern = Pattern.compile("(?<=(^|\\s))" + ascii
- + "(?=(\\s|$))");
- this.replacement = new String(new int[] { unicode, }, 0, 1);
- }
-
- String replaceAll(String body) {
- return pattern.matcher(body).replaceAll(replacement);
- }
- }
-
- private static final EmoticonPattern[] patterns = new EmoticonPattern[] {
- new EmoticonPattern(":-?D", 0x1f600),
- new EmoticonPattern("\\^\\^", 0x1f601),
- new EmoticonPattern(":'D", 0x1f602),
- new EmoticonPattern("\\]-?D", 0x1f608),
- new EmoticonPattern(";-?\\)", 0x1f609),
- new EmoticonPattern(":-?\\)", 0x1f60a),
- new EmoticonPattern("[B8]-?\\)", 0x1f60e),
- new EmoticonPattern(":-?\\|", 0x1f610),
- new EmoticonPattern(":-?[/\\\\]", 0x1f615),
- new EmoticonPattern(":-?\\*", 0x1f617),
- new EmoticonPattern(":-?[Ppb]", 0x1f61b),
- new EmoticonPattern(":-?\\(", 0x1f61e),
- new EmoticonPattern(":-?[0Oo]", 0x1f62e),
- new EmoticonPattern("\\\\o/", 0x1F631), };
-
- public static String transformAsciiEmoticonsToUtf8(String body) {
- if (body != null) {
- for (EmoticonPattern p : patterns) {
- body = p.replaceAll(body);
- }
- }
- return body;
- }
-
- public static Spannable transformAsciiEmoticons(Context context, String body) {
- Spannable spannable;
- if (Config.UTF8_EMOTICONS) {
- spannable = spannableFactory.newSpannable(transformAsciiEmoticonsToUtf8(body));
- }
- else {
- spannable = spannableFactory.newSpannable(body);
- getSmiledText(context, spannable);
- }
- return spannable;
- }
-
public static int getColorForName(String name) {
if (name.isEmpty()) {
return 0xFF202020;
@@ -399,9 +270,9 @@ public class UIHelper {
if (counterpart==null) {
return "";
} else if (!counterpart.isBareJid()) {
- return counterpart.getResourcepart().trim();
+ return counterpart.getResourcepart();
} else {
- return counterpart.toString().trim();
+ return counterpart.toString();
}
}
@@ -411,7 +282,7 @@ public class UIHelper {
|| message.getType() != Message.TYPE_TEXT) {
return false;
}
- String body = message.getBody() == null ? null : message.getBody().trim().toLowerCase(Locale.getDefault());
+ String body = message.getBody() == null ? null : message.getBody().toLowerCase(Locale.getDefault());
body = body.replace("?","").replace("¿","");
return LOCATION_QUESTIONS.contains(body);
}
diff --git a/src/main/java/eu/siacs/conversations/ui/listeners/ConversationMoreMessagesLoadedListener.java b/src/main/java/eu/siacs/conversations/ui/listeners/ConversationMoreMessagesLoadedListener.java
new file mode 100644
index 00000000..2154f8d8
--- /dev/null
+++ b/src/main/java/eu/siacs/conversations/ui/listeners/ConversationMoreMessagesLoadedListener.java
@@ -0,0 +1,118 @@
+package eu.siacs.conversations.ui.listeners;
+
+import android.support.v4.widget.SwipeRefreshLayout;
+import android.view.View;
+import android.widget.ListView;
+import android.widget.Toast;
+
+import java.util.List;
+
+import eu.siacs.conversations.entities.Conversation;
+import eu.siacs.conversations.entities.Message;
+import eu.siacs.conversations.services.XmppConnectionService;
+import eu.siacs.conversations.ui.ConversationActivity;
+import eu.siacs.conversations.ui.ConversationFragment;
+import eu.siacs.conversations.ui.adapter.MessageAdapter;
+
+/**
+ * This listener updates the UI when messages are loaded from the server.
+ */
+public class ConversationMoreMessagesLoadedListener implements XmppConnectionService.OnMoreMessagesLoaded {
+ private SwipeRefreshLayout swipeLayout;
+ private List<Message> messageList;
+ private ConversationFragment fragment;
+ private ListView messagesView;
+ private MessageAdapter messageListAdapter;
+ private Toast messageLoaderToast;
+
+ public ConversationMoreMessagesLoadedListener(SwipeRefreshLayout swipeLayout, List<Message> messageList, ConversationFragment fragment, ListView messagesView, MessageAdapter messageListAdapter) {
+ this.swipeLayout = swipeLayout;
+ this.messageList = messageList;
+ this.fragment = fragment;
+ this.messagesView = messagesView;
+ this.messageListAdapter = messageListAdapter;
+ }
+
+ @Override
+ public void onMoreMessagesLoaded(final int c, final Conversation conversation) {
+ ConversationActivity activity = (ConversationActivity) fragment.getActivity();
+ if (activity.getSelectedConversation() != conversation) {
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ swipeLayout.setRefreshing(false);
+ }
+ });
+ return;
+ }
+ if (0 == c) {
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ swipeLayout.setRefreshing(false);
+ }
+ });
+ }
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ final int oldPosition = messagesView.getFirstVisiblePosition();
+ int pos = 0;
+ View v = messagesView.getChildAt(0);
+ final int pxOffset = (v == null) ? 0 : v.getTop();
+ if (-1 < oldPosition && messageList.size() > oldPosition) {
+ Message message = messageList.get(oldPosition);
+ String uuid = message != null ? message.getUuid() : null;
+ pos = getIndexOf(uuid, messageList);
+ }
+ conversation.populateWithMessages(messageList);
+ fragment.updateStatusMessages();
+ messageListAdapter.notifyDataSetChanged();
+ messagesView.setSelectionFromTop(pos, pxOffset);
+
+ if (messageLoaderToast != null) {
+ messageLoaderToast.cancel();
+ }
+ swipeLayout.setRefreshing(false);
+ }
+ });
+ }
+
+ @Override
+ public void informUser(final int resId) {
+ final ConversationActivity activity = (ConversationActivity) fragment.getActivity();
+
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (messageLoaderToast != null) {
+ messageLoaderToast.cancel();
+ }
+ messageLoaderToast = Toast.makeText(activity, resId, Toast.LENGTH_LONG);
+ messageLoaderToast.show();
+ }
+ });
+
+ }
+
+ private int getIndexOf(String uuid, List<Message> messages) {
+ if (uuid == null) {
+ return 0;
+ }
+ for(int i = 0; i < messages.size(); ++i) {
+ if (uuid.equals(messages.get(i).getUuid())) {
+ return i;
+ } else {
+ Message next = messages.get(i);
+ while(next != null && next.wasMergedIntoPrevious()) {
+ if (uuid.equals(next.getUuid())) {
+ return i;
+ }
+ next = next.next();
+ }
+
+ }
+ }
+ return 0;
+ }
+}
diff --git a/src/main/java/eu/siacs/conversations/ui/listeners/ConversationSwipeRefreshListener.java b/src/main/java/eu/siacs/conversations/ui/listeners/ConversationSwipeRefreshListener.java
new file mode 100644
index 00000000..09a8d730
--- /dev/null
+++ b/src/main/java/eu/siacs/conversations/ui/listeners/ConversationSwipeRefreshListener.java
@@ -0,0 +1,48 @@
+package eu.siacs.conversations.ui.listeners;
+
+import android.support.v4.widget.SwipeRefreshLayout;
+import android.util.Log;
+import android.view.View;
+import android.widget.ListView;
+import android.widget.Toast;
+
+import java.util.List;
+
+import eu.siacs.conversations.Config;
+import eu.siacs.conversations.entities.Conversation;
+import eu.siacs.conversations.entities.Message;
+import eu.siacs.conversations.services.XmppConnectionService;
+import eu.siacs.conversations.ui.ConversationActivity;
+import eu.siacs.conversations.ui.ConversationFragment;
+import eu.siacs.conversations.ui.adapter.MessageAdapter;
+
+/**
+ * This listener starts loading messages from the server.
+ */
+public class ConversationSwipeRefreshListener implements SwipeRefreshLayout.OnRefreshListener {
+ private List<Message> messageList;
+ private ConversationFragment fragment;
+ private ConversationMoreMessagesLoadedListener listener;
+
+ public ConversationSwipeRefreshListener(List<Message> messageList, SwipeRefreshLayout swipeLayout, ConversationFragment fragment, ListView messagesView, MessageAdapter messageListAdapter) {
+ this.messageList = messageList;
+ this.fragment = fragment;
+ this.listener = new ConversationMoreMessagesLoadedListener(swipeLayout, messageList, fragment, messagesView, messageListAdapter);
+ }
+
+ @Override
+ public void onRefresh() {
+ Log.d(Config.LOGTAG, "Refresh swipe container");
+ synchronized (this.messageList) {
+ long timestamp;
+ if (messageList.isEmpty()) {
+ timestamp = System.currentTimeMillis();
+ } else {
+ timestamp = this.messageList.get(0).getTimeSent();
+ }
+ ConversationActivity activity = (ConversationActivity) fragment.getActivity();
+ activity.xmppConnectionService.loadMoreMessages(activity.getSelectedConversation(), timestamp, this.listener);
+ }
+ Log.d(Config.LOGTAG, "End Refresh swipe container");
+ }
+}
diff --git a/src/main/res/layout/fragment_conversation.xml b/src/main/res/layout/fragment_conversation.xml
index bb706e5b..0a69f508 100644
--- a/src/main/res/layout/fragment_conversation.xml
+++ b/src/main/res/layout/fragment_conversation.xml
@@ -5,6 +5,13 @@
android:layout_height="match_parent"
android:background="@color/grey200" >
+ <android.support.v4.widget.SwipeRefreshLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_above="@+id/snackbar"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:id="@+id/swipe_refresh_container">
<ListView
android:id="@+id/messages_view"
android:layout_width="fill_parent"
@@ -20,6 +27,7 @@
android:transcriptMode="normal"
tools:listitem="@layout/message_sent" >
</ListView>
+ </android.support.v4.widget.SwipeRefreshLayout>
<RelativeLayout
android:id="@+id/textsend"