diff --git a/.travis.yml b/.travis.yml
index ac9f7ea3ac..9900afd6f2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -30,7 +30,7 @@ install:
script:
# By default Travis-ci executes './gradlew build connectedCheck' if no 'script:' section found.
- - ./gradlew clean build -Pbuild=dev
+ - ./gradlew clean build -Pbuild=open
env:
diff --git a/README.md b/README.md
index 0827778730..0e65604e0e 100644
--- a/README.md
+++ b/README.md
@@ -18,7 +18,7 @@ Xabber uses Gradle build system. The only specific thing is git submodule for ge
**2. Build**
-To build Xabber use **"dev"** productFlavour. Other flavours like "beta", "prod", "ru" and "vip" requare api keys that not represent in this repository.
+To build Xabber use **"open"** productFlavour. Other flavours like "beta", "prod", "dev" and "vip" requare api keys that not represent in this repository.
## Translations [![Crowdin](https://d322cqt584bo4o.cloudfront.net/xabber/localized.svg)](https://crowdin.com/project/xabber)
diff --git a/xabber/build.gradle b/xabber/build.gradle
index 2243a22f2b..126eefcfcd 100644
--- a/xabber/build.gradle
+++ b/xabber/build.gradle
@@ -10,8 +10,8 @@ android {
defaultConfig {
minSdkVersion 15
targetSdkVersion 28
- versionCode 533
- versionName '2.5(533)'
+ versionCode 568
+ versionName '2.6(568)'
}
lintOptions {
@@ -38,6 +38,13 @@ android {
flavorDimensions "build"
productFlavors {
+ open {
+ dimension "build"
+ applicationId "com.xabber.android.open"
+ resValue 'string', 'application_package', applicationId
+ multiDexEnabled true
+ }
+
dev {
dimension "build"
applicationId "com.xabber.androiddev"
@@ -65,28 +72,13 @@ android {
resValue 'string', 'application_package', applicationId
multiDexEnabled true
}
-
- ru {
- dimension "build"
- applicationId "com.xabber.android.ru"
- resValue 'string', 'application_package', applicationId
- multiDexEnabled true
- }
-
}
buildTypes {
release {
minifyEnabled true
shrinkResources true
- proguardFiles getDefaultProguardFile('proguard-android.txt'),
- 'proguard-rules.pro'
- // enable crashlytics
- buildConfigField "boolean", "USE_CRASHLYTICS", "true"
- }
- debug {
- // disable crashlytics
- buildConfigField "boolean", "USE_CRASHLYTICS", "false"
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
@@ -103,33 +95,14 @@ android {
universalApk true
}
}
-
- afterEvaluate {
- initFabricPropertiesIfNeeded()
- }
-}
-
-def initFabricPropertiesIfNeeded() {
- def propertiesFile = file('fabric.properties')
-
- def apiSecret = hasProperty('crashlyticsApisecret') ? crashlyticsApisecret : System.getenv('crashlyticsApisecret')
- def apiKey = hasProperty('crashlyticsApikey') ? crashlyticsApikey : System.getenv('crashlyticsApikey')
-
- if (!propertiesFile.exists()) {
- def commentMessage = "This is autogenerated fabric property from system environment to prevent key to be committed to source control."
- ant.propertyfile(file: "fabric.properties", comment: commentMessage) {
- entry(key: "apiSecret", value: apiSecret)
- entry(key: "apiKey", value: apiKey)
- }
- }
}
def build_param = "${build}";
-if (build_param == "dev") {
- //exclude all but dev
+if (build_param == "open") {
+ // exclude all flavours except open
android.variantFilter { variant ->
- if (!variant.getFlavors().get(0).name.equals('dev')) {
+ if (!variant.getFlavors().get(0).name.equals('open')) {
variant.setIgnore(true);
}
}
@@ -172,7 +145,7 @@ dependencies {
// social
implementation 'com.google.android.gms:play-services-safetynet:11.4.0'
- implementation 'com.facebook.android:facebook-android-sdk:4.31.0'
+ implementation 'com.facebook.android:facebook-login:4.36.1'
implementation 'com.twitter.sdk.android:twitter:3.0.0'
implementation 'com.google.android.gms:play-services-auth:11.4.0'
implementation ('com.google.api-client:google-api-client-android:1.22.0') {
diff --git a/xabber/proguard-rules.pro b/xabber/proguard-rules.pro
index b818fb83cb..6880b122b3 100644
--- a/xabber/proguard-rules.pro
+++ b/xabber/proguard-rules.pro
@@ -35,6 +35,9 @@
-keep @io.realm.internal.Keep class * { *; }
-dontwarn javax.**
-dontwarn io.realm.**
+-keepnames public class * extends io.realm.RealmObject
+-keep public class * extends io.realm.RealmObject { *; }
+-keep class io.realm.** { *; }
# EbentBus
-keepattributes *Annotation*
diff --git a/xabber/src/beta/res/drawable-hdpi/xabber_logo_80dp.png b/xabber/src/beta/res/drawable-hdpi/xabber_logo_80dp.png
index b3e044ea75..0fe69df4e1 100644
Binary files a/xabber/src/beta/res/drawable-hdpi/xabber_logo_80dp.png and b/xabber/src/beta/res/drawable-hdpi/xabber_logo_80dp.png differ
diff --git a/xabber/src/beta/res/drawable-hdpi/xabber_logo_grey_80dp.png b/xabber/src/beta/res/drawable-hdpi/xabber_logo_grey_80dp.png
deleted file mode 100644
index 073142d156..0000000000
Binary files a/xabber/src/beta/res/drawable-hdpi/xabber_logo_grey_80dp.png and /dev/null differ
diff --git a/xabber/src/beta/res/drawable-mdpi/xabber_logo_80dp.png b/xabber/src/beta/res/drawable-mdpi/xabber_logo_80dp.png
index 0be85f8d56..761c1b34fc 100644
Binary files a/xabber/src/beta/res/drawable-mdpi/xabber_logo_80dp.png and b/xabber/src/beta/res/drawable-mdpi/xabber_logo_80dp.png differ
diff --git a/xabber/src/beta/res/drawable-mdpi/xabber_logo_grey_80dp.png b/xabber/src/beta/res/drawable-mdpi/xabber_logo_grey_80dp.png
deleted file mode 100644
index bc9323eeac..0000000000
Binary files a/xabber/src/beta/res/drawable-mdpi/xabber_logo_grey_80dp.png and /dev/null differ
diff --git a/xabber/src/beta/res/drawable-xhdpi/xabber_logo_80dp.png b/xabber/src/beta/res/drawable-xhdpi/xabber_logo_80dp.png
index f257c090b6..9d18cd4cc2 100644
Binary files a/xabber/src/beta/res/drawable-xhdpi/xabber_logo_80dp.png and b/xabber/src/beta/res/drawable-xhdpi/xabber_logo_80dp.png differ
diff --git a/xabber/src/beta/res/drawable-xhdpi/xabber_logo_grey_80dp.png b/xabber/src/beta/res/drawable-xhdpi/xabber_logo_grey_80dp.png
deleted file mode 100644
index c151755b02..0000000000
Binary files a/xabber/src/beta/res/drawable-xhdpi/xabber_logo_grey_80dp.png and /dev/null differ
diff --git a/xabber/src/beta/res/drawable-xxhdpi/xabber_logo_80dp.png b/xabber/src/beta/res/drawable-xxhdpi/xabber_logo_80dp.png
index e353c4f776..39081d5868 100644
Binary files a/xabber/src/beta/res/drawable-xxhdpi/xabber_logo_80dp.png and b/xabber/src/beta/res/drawable-xxhdpi/xabber_logo_80dp.png differ
diff --git a/xabber/src/beta/res/drawable-xxhdpi/xabber_logo_grey_80dp.png b/xabber/src/beta/res/drawable-xxhdpi/xabber_logo_grey_80dp.png
deleted file mode 100644
index 19e3bccc95..0000000000
Binary files a/xabber/src/beta/res/drawable-xxhdpi/xabber_logo_grey_80dp.png and /dev/null differ
diff --git a/xabber/src/beta/res/drawable-xxxhdpi/xabber_logo_80dp.png b/xabber/src/beta/res/drawable-xxxhdpi/xabber_logo_80dp.png
index caf40aee50..745dfbf8a3 100644
Binary files a/xabber/src/beta/res/drawable-xxxhdpi/xabber_logo_80dp.png and b/xabber/src/beta/res/drawable-xxxhdpi/xabber_logo_80dp.png differ
diff --git a/xabber/src/beta/res/drawable-xxxhdpi/xabber_logo_grey_80dp.png b/xabber/src/beta/res/drawable-xxxhdpi/xabber_logo_grey_80dp.png
deleted file mode 100644
index 8d33a31247..0000000000
Binary files a/xabber/src/beta/res/drawable-xxxhdpi/xabber_logo_grey_80dp.png and /dev/null differ
diff --git a/xabber/src/beta/res/drawable/ic_stat_offline.xml b/xabber/src/beta/res/drawable/ic_stat_offline.xml
new file mode 100644
index 0000000000..56ef505e50
--- /dev/null
+++ b/xabber/src/beta/res/drawable/ic_stat_offline.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
diff --git a/xabber/src/beta/res/drawable/ic_stat_online.xml b/xabber/src/beta/res/drawable/ic_stat_online.xml
new file mode 100644
index 0000000000..bdbd9d6343
--- /dev/null
+++ b/xabber/src/beta/res/drawable/ic_stat_online.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
diff --git a/xabber/src/beta/res/mipmap-hdpi/ic_launcher.png b/xabber/src/beta/res/mipmap-hdpi/ic_launcher.png
index f33afc9c00..2faaeafb4e 100644
Binary files a/xabber/src/beta/res/mipmap-hdpi/ic_launcher.png and b/xabber/src/beta/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/xabber/src/beta/res/mipmap-hdpi/ic_launcher_foreground.png b/xabber/src/beta/res/mipmap-hdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000000..900f232f4c
Binary files /dev/null and b/xabber/src/beta/res/mipmap-hdpi/ic_launcher_foreground.png differ
diff --git a/xabber/src/beta/res/mipmap-hdpi/ic_launcher_round.png b/xabber/src/beta/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000000..3e4a724a02
Binary files /dev/null and b/xabber/src/beta/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/xabber/src/beta/res/mipmap-mdpi/ic_launcher.png b/xabber/src/beta/res/mipmap-mdpi/ic_launcher.png
index 686edc7c70..9b941ecd25 100644
Binary files a/xabber/src/beta/res/mipmap-mdpi/ic_launcher.png and b/xabber/src/beta/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/xabber/src/beta/res/mipmap-mdpi/ic_launcher_foreground.png b/xabber/src/beta/res/mipmap-mdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000000..ed41aa60b0
Binary files /dev/null and b/xabber/src/beta/res/mipmap-mdpi/ic_launcher_foreground.png differ
diff --git a/xabber/src/beta/res/mipmap-mdpi/ic_launcher_round.png b/xabber/src/beta/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000000..5954057eec
Binary files /dev/null and b/xabber/src/beta/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/xabber/src/beta/res/mipmap-xhdpi/ic_launcher.png b/xabber/src/beta/res/mipmap-xhdpi/ic_launcher.png
index 6338ec961f..c525309e68 100644
Binary files a/xabber/src/beta/res/mipmap-xhdpi/ic_launcher.png and b/xabber/src/beta/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/xabber/src/beta/res/mipmap-xhdpi/ic_launcher_foreground.png b/xabber/src/beta/res/mipmap-xhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000000..8f4806f11f
Binary files /dev/null and b/xabber/src/beta/res/mipmap-xhdpi/ic_launcher_foreground.png differ
diff --git a/xabber/src/beta/res/mipmap-xhdpi/ic_launcher_round.png b/xabber/src/beta/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000000..aaf3ca0ddd
Binary files /dev/null and b/xabber/src/beta/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/xabber/src/beta/res/mipmap-xxhdpi/ic_launcher.png b/xabber/src/beta/res/mipmap-xxhdpi/ic_launcher.png
index a56158cc3e..36b050be67 100644
Binary files a/xabber/src/beta/res/mipmap-xxhdpi/ic_launcher.png and b/xabber/src/beta/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/xabber/src/beta/res/mipmap-xxhdpi/ic_launcher_foreground.png b/xabber/src/beta/res/mipmap-xxhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000000..63e489b425
Binary files /dev/null and b/xabber/src/beta/res/mipmap-xxhdpi/ic_launcher_foreground.png differ
diff --git a/xabber/src/beta/res/mipmap-xxhdpi/ic_launcher_round.png b/xabber/src/beta/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000000..c451b01b72
Binary files /dev/null and b/xabber/src/beta/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/xabber/src/beta/res/mipmap-xxxhdpi/ic_launcher.png b/xabber/src/beta/res/mipmap-xxxhdpi/ic_launcher.png
index 52e759c3a2..a1775f3df3 100644
Binary files a/xabber/src/beta/res/mipmap-xxxhdpi/ic_launcher.png and b/xabber/src/beta/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/xabber/src/beta/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/xabber/src/beta/res/mipmap-xxxhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000000..9d55b15c03
Binary files /dev/null and b/xabber/src/beta/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ
diff --git a/xabber/src/beta/res/mipmap-xxxhdpi/ic_launcher_round.png b/xabber/src/beta/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000000..2861c8b99b
Binary files /dev/null and b/xabber/src/beta/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/xabber/src/dev/res/drawable-hdpi/xabber_logo_80dp.png b/xabber/src/dev/res/drawable-hdpi/xabber_logo_80dp.png
new file mode 100644
index 0000000000..c1fc54056a
Binary files /dev/null and b/xabber/src/dev/res/drawable-hdpi/xabber_logo_80dp.png differ
diff --git a/xabber/src/dev/res/drawable-mdpi/xabber_logo_80dp.png b/xabber/src/dev/res/drawable-mdpi/xabber_logo_80dp.png
new file mode 100644
index 0000000000..a7aa211046
Binary files /dev/null and b/xabber/src/dev/res/drawable-mdpi/xabber_logo_80dp.png differ
diff --git a/xabber/src/dev/res/drawable-xhdpi/xabber_logo_80dp.png b/xabber/src/dev/res/drawable-xhdpi/xabber_logo_80dp.png
new file mode 100644
index 0000000000..06bdcbf736
Binary files /dev/null and b/xabber/src/dev/res/drawable-xhdpi/xabber_logo_80dp.png differ
diff --git a/xabber/src/dev/res/drawable-xxhdpi/xabber_logo_80dp.png b/xabber/src/dev/res/drawable-xxhdpi/xabber_logo_80dp.png
new file mode 100644
index 0000000000..9a0de84d65
Binary files /dev/null and b/xabber/src/dev/res/drawable-xxhdpi/xabber_logo_80dp.png differ
diff --git a/xabber/src/dev/res/drawable-xxxhdpi/xabber_logo_80dp.png b/xabber/src/dev/res/drawable-xxxhdpi/xabber_logo_80dp.png
new file mode 100644
index 0000000000..55c41b5b7d
Binary files /dev/null and b/xabber/src/dev/res/drawable-xxxhdpi/xabber_logo_80dp.png differ
diff --git a/xabber/src/dev/res/drawable/ic_stat_offline.xml b/xabber/src/dev/res/drawable/ic_stat_offline.xml
new file mode 100644
index 0000000000..56135c97dc
--- /dev/null
+++ b/xabber/src/dev/res/drawable/ic_stat_offline.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
diff --git a/xabber/src/dev/res/drawable/ic_stat_online.xml b/xabber/src/dev/res/drawable/ic_stat_online.xml
new file mode 100644
index 0000000000..91720b4b8c
--- /dev/null
+++ b/xabber/src/dev/res/drawable/ic_stat_online.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
diff --git a/xabber/src/dev/res/layout/activity_tutorial.xml b/xabber/src/dev/res/layout/activity_tutorial.xml
new file mode 100644
index 0000000000..466f31cd7f
--- /dev/null
+++ b/xabber/src/dev/res/layout/activity_tutorial.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/xabber/src/dev/res/layout/fragment_crowdfunding.xml b/xabber/src/dev/res/layout/fragment_crowdfunding.xml
new file mode 100644
index 0000000000..08edda2aa9
--- /dev/null
+++ b/xabber/src/dev/res/layout/fragment_crowdfunding.xml
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/xabber/src/dev/res/mipmap-hdpi/ic_launcher.png b/xabber/src/dev/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000000..448d601f33
Binary files /dev/null and b/xabber/src/dev/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/xabber/src/dev/res/mipmap-hdpi/ic_launcher_foreground.png b/xabber/src/dev/res/mipmap-hdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000000..0acf8f717b
Binary files /dev/null and b/xabber/src/dev/res/mipmap-hdpi/ic_launcher_foreground.png differ
diff --git a/xabber/src/dev/res/mipmap-hdpi/ic_launcher_round.png b/xabber/src/dev/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000000..d93794f001
Binary files /dev/null and b/xabber/src/dev/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/xabber/src/dev/res/mipmap-mdpi/ic_launcher.png b/xabber/src/dev/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000000..2030270ec7
Binary files /dev/null and b/xabber/src/dev/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/xabber/src/dev/res/mipmap-mdpi/ic_launcher_foreground.png b/xabber/src/dev/res/mipmap-mdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000000..673ac9fef3
Binary files /dev/null and b/xabber/src/dev/res/mipmap-mdpi/ic_launcher_foreground.png differ
diff --git a/xabber/src/dev/res/mipmap-mdpi/ic_launcher_round.png b/xabber/src/dev/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000000..fefa850ad2
Binary files /dev/null and b/xabber/src/dev/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/xabber/src/dev/res/mipmap-xhdpi/ic_launcher.png b/xabber/src/dev/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000000..236813f140
Binary files /dev/null and b/xabber/src/dev/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/xabber/src/dev/res/mipmap-xhdpi/ic_launcher_foreground.png b/xabber/src/dev/res/mipmap-xhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000000..56c0d2638f
Binary files /dev/null and b/xabber/src/dev/res/mipmap-xhdpi/ic_launcher_foreground.png differ
diff --git a/xabber/src/dev/res/mipmap-xhdpi/ic_launcher_round.png b/xabber/src/dev/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000000..5618c2b9d8
Binary files /dev/null and b/xabber/src/dev/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/xabber/src/dev/res/mipmap-xxhdpi/ic_launcher.png b/xabber/src/dev/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000000..dda42f7539
Binary files /dev/null and b/xabber/src/dev/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/xabber/src/dev/res/mipmap-xxhdpi/ic_launcher_foreground.png b/xabber/src/dev/res/mipmap-xxhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000000..51a26c1a06
Binary files /dev/null and b/xabber/src/dev/res/mipmap-xxhdpi/ic_launcher_foreground.png differ
diff --git a/xabber/src/dev/res/mipmap-xxhdpi/ic_launcher_round.png b/xabber/src/dev/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000000..9f03ecb62d
Binary files /dev/null and b/xabber/src/dev/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/xabber/src/dev/res/mipmap-xxxhdpi/ic_launcher.png b/xabber/src/dev/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000000..79fe2381ee
Binary files /dev/null and b/xabber/src/dev/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/xabber/src/dev/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/xabber/src/dev/res/mipmap-xxxhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000000..abace4f271
Binary files /dev/null and b/xabber/src/dev/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ
diff --git a/xabber/src/dev/res/mipmap-xxxhdpi/ic_launcher_round.png b/xabber/src/dev/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000000..a2d7149fbd
Binary files /dev/null and b/xabber/src/dev/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/xabber/src/dev/res/values/preferences.xml b/xabber/src/dev/res/values/preferences.xml
new file mode 100644
index 0000000000..224b22e6ad
--- /dev/null
+++ b/xabber/src/dev/res/values/preferences.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+ true
+ true
+
+
diff --git a/xabber/src/dev/res/xml/preference_debug.xml b/xabber/src/dev/res/xml/preference_debug.xml
new file mode 100644
index 0000000000..983205d8b4
--- /dev/null
+++ b/xabber/src/dev/res/xml/preference_debug.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/xabber/src/main/AndroidManifest.xml b/xabber/src/main/AndroidManifest.xml
index d8fa86b6b8..f527aa5f3b 100644
--- a/xabber/src/main/AndroidManifest.xml
+++ b/xabber/src/main/AndroidManifest.xml
@@ -548,10 +548,15 @@
+
+
+
+
+
+
+
+
-
-
+
+
+
\ No newline at end of file
diff --git a/xabber/src/main/java/com/xabber/android/data/Application.java b/xabber/src/main/java/com/xabber/android/data/Application.java
index bae49e42a6..fc5b431b44 100644
--- a/xabber/src/main/java/com/xabber/android/data/Application.java
+++ b/xabber/src/main/java/com/xabber/android/data/Application.java
@@ -48,6 +48,7 @@
import com.xabber.android.data.extension.otr.OTRManager;
import com.xabber.android.data.extension.ssn.SSNManager;
import com.xabber.android.data.extension.vcard.VCardManager;
+import com.xabber.android.data.http.CrowdfundingManager;
import com.xabber.android.data.http.PatreonManager;
import com.xabber.android.data.log.LogManager;
import com.xabber.android.data.message.MessageManager;
@@ -334,22 +335,14 @@ public void onCreate() {
}
/** Crashlytics */
- // Set up Crashlytics, disabled for debug builds
- Crashlytics crashlyticsKit = new Crashlytics.Builder()
- .core(new CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build())
+ CrashlyticsCore crashlyticsCore = new CrashlyticsCore.Builder()
+ .disabled(BuildConfig.DEBUG || BuildConfig.FLAVOR == "open")
.build();
-
- // Initialize Fabric with the debug-disabled crashlytics.
- if (BuildConfig.USE_CRASHLYTICS) {
- Fabric.with(this, crashlyticsKit);
- }
+ Fabric.with(this, new Crashlytics.Builder().core(crashlyticsCore).build());
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
-
addManagers();
-
DatabaseManager.getInstance().addTables();
-
LogManager.i(this, "onCreate finished...");
}
@@ -364,6 +357,7 @@ private void addManagers() {
addManager(AccountManager.getInstance());
addManager(XabberAccountManager.getInstance());
addManager(PatreonManager.getInstance());
+ addManager(CrowdfundingManager.getInstance());
addManager(MUCManager.getInstance());
addManager(MessageManager.getInstance());
addManager(ChatManager.getInstance());
diff --git a/xabber/src/main/java/com/xabber/android/data/SettingsManager.java b/xabber/src/main/java/com/xabber/android/data/SettingsManager.java
index 16f0979c70..643633ffb8 100644
--- a/xabber/src/main/java/com/xabber/android/data/SettingsManager.java
+++ b/xabber/src/main/java/com/xabber/android/data/SettingsManager.java
@@ -560,6 +560,10 @@ public static boolean sendCrashReports() {
return getBoolean(R.string.debug_crash_reports_key, R.bool.debug_crash_reports_default);
}
+ public static boolean useDevelopAPI() {
+ return getBoolean(R.string.debug_use_develop_api_key, R.bool.debug_use_develop_api_default);
+ }
+
public static boolean isCrashReportsSupported() {
return BuildConfig.FLAVOR.equals("beta")
|| BuildConfig.FLAVOR.equals("vip")
@@ -782,6 +786,38 @@ public static int getLastPatreonLoadTimestamp() {
return getInteger(R.string.patreon_last_load_timestamp_key, 1);
}
+ public static void setLastCrowdfundingLoadTimestamp(int timestamp) {
+ setInt(R.string.crowdfunding_last_load_timestamp_key, timestamp);
+ }
+
+ public static int getLastCrowdfundingLoadTimestamp() {
+ return getInteger(R.string.crowdfunding_last_load_timestamp_key, 1);
+ }
+
+ public static void setLastLeaderCrowdfundingLoadTimestamp(int timestamp) {
+ setInt(R.string.crowdfunding_leader_last_load_timestamp_key, timestamp);
+ }
+
+ public static int getLastLeaderCrowdfundingLoadTimestamp() {
+ return getInteger(R.string.crowdfunding_leader_last_load_timestamp_key, 1);
+ }
+
+ public static void setFirstAppRunTimestamp(int timestamp) {
+ setInt(R.string.first_app_run_timestamp_key, timestamp);
+ }
+
+ public static int getFirstAppRunTimestamp() {
+ return getInteger(R.string.first_app_run_timestamp_key, 0);
+ }
+
+ public static void setLastCrowdfundingPosition(int position) {
+ setInt(R.string.crowdfunding_last_position_key, position);
+ }
+
+ public static int getLastCrowdfundingPosition() {
+ return getInteger(R.string.crowdfunding_last_position_key, 0);
+ }
+
@Override
public void onInitialized() {
incrementBootCount();
diff --git a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java
index 0d3cf9702c..f9b5d44de2 100644
--- a/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java
+++ b/xabber/src/main/java/com/xabber/android/data/account/AccountManager.java
@@ -419,7 +419,7 @@ public AccountJid addAccount(String user, String password, String token, boolean
accountItem = addAccount(useCustomHost, host, port, serverName, userName,
storePassword, password, token, resource, getNextColorIndex(), getNextOrder(), false,
- 0, 0, StatusMode.available,
+ XabberAccountManager.getInstance().getCurrentTime(), 0, StatusMode.available,
SettingsManager.statusText(), enabled, true, tlsRequired ? TLSMode.required : TLSMode.enabled,
useCompression, useOrbot ? ProxyType.orbot : ProxyType.none, "localhost", 8080,
"", "", syncable, null, null, archiveMode, registerNewAccount);
diff --git a/xabber/src/main/java/com/xabber/android/data/connection/ConnectionThread.java b/xabber/src/main/java/com/xabber/android/data/connection/ConnectionThread.java
index ff968470b4..f6cb85568c 100644
--- a/xabber/src/main/java/com/xabber/android/data/connection/ConnectionThread.java
+++ b/xabber/src/main/java/com/xabber/android/data/connection/ConnectionThread.java
@@ -19,9 +19,13 @@
import com.xabber.android.data.account.AccountErrorEvent;
import com.xabber.android.data.account.AccountItem;
+import com.xabber.android.data.extension.forward.ForwardComment;
+import com.xabber.android.data.extension.forward.ForwardCommentProvider;
import com.xabber.android.data.extension.httpfileupload.CustomDataProvider;
import com.xabber.android.data.log.AndroidLoggingHandler;
import com.xabber.android.data.log.LogManager;
+import com.xabber.android.data.xaccount.HttpConfirmIq;
+import com.xabber.android.data.xaccount.HttpConfirmIqProvider;
import org.greenrobot.eventbus.EventBus;
import org.jivesoftware.smack.AbstractXMPPConnection;
@@ -132,12 +136,18 @@ void connectAndLogin() {
}
if (!connection.isAuthenticated()) {
+ ProviderManager.addIQProvider(HttpConfirmIq.ELEMENT,
+ HttpConfirmIq.NAMESPACE, new HttpConfirmIqProvider());
+
connection.login();
// can be a cause of strange Smack behavior
// not authorization or not receiving a iq's
ProviderManager.addExtensionProvider(DataForm.ELEMENT,
DataForm.NAMESPACE, new CustomDataProvider());
+
+ ProviderManager.addExtensionProvider(ForwardComment.ELEMENT,
+ ForwardComment.NAMESPACE, new ForwardCommentProvider());
} else {
LogManager.i(this, "Already authenticated");
}
diff --git a/xabber/src/main/java/com/xabber/android/data/database/MessageDatabaseManager.java b/xabber/src/main/java/com/xabber/android/data/database/MessageDatabaseManager.java
index f9fb36afdb..f43f64a1ba 100644
--- a/xabber/src/main/java/com/xabber/android/data/database/MessageDatabaseManager.java
+++ b/xabber/src/main/java/com/xabber/android/data/database/MessageDatabaseManager.java
@@ -6,6 +6,7 @@
import com.xabber.android.data.Application;
import com.xabber.android.data.database.messagerealm.Attachment;
+import com.xabber.android.data.database.messagerealm.ForwardId;
import com.xabber.android.data.database.messagerealm.MessageItem;
import com.xabber.android.data.database.messagerealm.SyncInfo;
import com.xabber.android.data.database.sqlite.MessageTable;
@@ -30,7 +31,7 @@
public class MessageDatabaseManager {
private static final String REALM_MESSAGE_DATABASE_NAME = "xabber.realm";
- static final int REALM_MESSAGE_DATABASE_VERSION = 16;
+ static final int REALM_MESSAGE_DATABASE_VERSION = 17;
private final RealmConfiguration realmConfiguration;
private static MessageDatabaseManager instance;
@@ -102,8 +103,9 @@ public static RealmQuery getChatMessagesQuery(Realm realm, AccountJ
return realm.where(MessageItem.class)
.equalTo(MessageItem.Fields.ACCOUNT, accountJid.toString())
.equalTo(MessageItem.Fields.USER, userJid.toString())
- .isNotNull(MessageItem.Fields.TEXT)
- .isNotEmpty(MessageItem.Fields.TEXT);
+ .isNull(MessageItem.Fields.PARENT_MESSAGE_ID)
+ .isNotNull(MessageItem.Fields.TEXT);
+ //.isNotEmpty(MessageItem.Fields.TEXT);
}
@@ -133,7 +135,7 @@ public void execute(Realm realm) {
}
- @RealmModule(classes = {MessageItem.class, SyncInfo.class, Attachment.class})
+ @RealmModule(classes = {MessageItem.class, SyncInfo.class, Attachment.class, ForwardId.class})
static class MessageRealmDatabaseModule {
}
@@ -281,6 +283,23 @@ public void migrate(DynamicRealm realm1, long oldVersion, long newVersion) {
oldVersion++;
}
+ if (oldVersion == 16) {
+ schema.create(ForwardId.class.getSimpleName())
+ .addField("id", String.class,
+ FieldAttribute.PRIMARY_KEY, FieldAttribute.REQUIRED)
+ .addField("forwardMessageId", String.class);
+
+ schema.get(MessageItem.class.getSimpleName())
+ .addField(MessageItem.Fields.ORIGINAL_STANZA, String.class)
+ .addField(MessageItem.Fields.ORIGINAL_FROM, String.class)
+ .addField(MessageItem.Fields.PARENT_MESSAGE_ID, String.class)
+ .addField(MessageItem.Fields.FROM_MUC, boolean.class)
+ .addRealmListField(MessageItem.Fields.FORWARDED_IDS,
+ schema.get(ForwardId.class.getSimpleName()));
+
+ oldVersion++;
+ }
+
}
})
.build();
diff --git a/xabber/src/main/java/com/xabber/android/data/database/RealmManager.java b/xabber/src/main/java/com/xabber/android/data/database/RealmManager.java
index 82d0804ce1..1b9030d625 100644
--- a/xabber/src/main/java/com/xabber/android/data/database/RealmManager.java
+++ b/xabber/src/main/java/com/xabber/android/data/database/RealmManager.java
@@ -6,6 +6,7 @@
import com.xabber.android.data.Application;
import com.xabber.android.data.database.realm.AccountRealm;
import com.xabber.android.data.database.realm.ChatDataRealm;
+import com.xabber.android.data.database.realm.CrowdfundingMessage;
import com.xabber.android.data.database.realm.DiscoveryInfoCache;
import com.xabber.android.data.database.realm.EmailRealm;
import com.xabber.android.data.database.realm.NotificationStateRealm;
@@ -29,7 +30,7 @@
public class RealmManager {
private static final String REALM_DATABASE_NAME = "realm_database.realm";
- private static final int REALM_DATABASE_VERSION = 17;
+ private static final int REALM_DATABASE_VERSION = 18;
private static final String LOG_TAG = RealmManager.class.getSimpleName();
private final RealmConfiguration realmConfiguration;
@@ -62,7 +63,8 @@ void deleteRealm() {
@RealmModule(classes = {DiscoveryInfoCache.class, AccountRealm.class, XabberAccountRealm.class,
XMPPUserRealm.class, EmailRealm.class, SocialBindingRealm.class, SyncStateRealm.class,
- PatreonGoalRealm.class, PatreonRealm.class, ChatDataRealm.class, NotificationStateRealm.class})
+ PatreonGoalRealm.class, PatreonRealm.class, ChatDataRealm.class, NotificationStateRealm.class,
+ CrowdfundingMessage.class})
static class RealmDatabaseModule {
}
@@ -240,6 +242,24 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) {
oldVersion++;
}
+
+ if (oldVersion == 17) {
+ schema.create(CrowdfundingMessage.class.getSimpleName())
+ .addField("id", String.class, FieldAttribute.PRIMARY_KEY, FieldAttribute.REQUIRED)
+ .addField("timestamp", int.class)
+ .addField("receivedTimestamp", int.class)
+ .addField("isLeader", boolean.class)
+ .addField("messageRu", String.class)
+ .addField("messageEn", String.class)
+ .addField("read", boolean.class)
+ .addField("delay", int.class)
+ .addField("authorAvatar", String.class)
+ .addField("authorJid", String.class)
+ .addField("authorNameRu", String.class)
+ .addField("authorNameEn", String.class);
+
+ oldVersion++;
+ }
}
})
.modules(new RealmDatabaseModule())
diff --git a/xabber/src/main/java/com/xabber/android/data/database/messagerealm/ForwardId.java b/xabber/src/main/java/com/xabber/android/data/database/messagerealm/ForwardId.java
new file mode 100644
index 0000000000..82f1f52a7f
--- /dev/null
+++ b/xabber/src/main/java/com/xabber/android/data/database/messagerealm/ForwardId.java
@@ -0,0 +1,41 @@
+package com.xabber.android.data.database.messagerealm;
+
+import java.util.UUID;
+
+import io.realm.RealmObject;
+import io.realm.annotations.PrimaryKey;
+import io.realm.annotations.Required;
+
+public class ForwardId extends RealmObject {
+
+ @PrimaryKey
+ @Required
+ private String id;
+
+ private String forwardMessageId;
+
+ public ForwardId() {
+ this.id = UUID.randomUUID().toString();
+ }
+
+ public ForwardId(String forwardMessageId) {
+ this.id = UUID.randomUUID().toString();
+ this.forwardMessageId = forwardMessageId;
+ }
+
+ public String getForwardMessageId() {
+ return forwardMessageId;
+ }
+
+ public void setForwardMessageId(String forwardMessageId) {
+ this.forwardMessageId = forwardMessageId;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+}
diff --git a/xabber/src/main/java/com/xabber/android/data/database/messagerealm/MessageItem.java b/xabber/src/main/java/com/xabber/android/data/database/messagerealm/MessageItem.java
index 27602246e7..10f43c8cfb 100644
--- a/xabber/src/main/java/com/xabber/android/data/database/messagerealm/MessageItem.java
+++ b/xabber/src/main/java/com/xabber/android/data/database/messagerealm/MessageItem.java
@@ -27,6 +27,7 @@
import org.jxmpp.jid.parts.Resourcepart;
import org.jxmpp.stringprep.XmppStringprepException;
+import java.util.List;
import java.util.UUID;
import io.realm.RealmList;
@@ -67,6 +68,11 @@ public static class Fields {
public static final String ACKNOWLEDGED = "acknowledged";
public static final String IS_IN_PROGRESS = "isInProgress";
public static final String ATTACHMENTS = "attachments";
+ public static final String FORWARDED_IDS = "forwardedIds";
+ public static final String ORIGINAL_STANZA = "originalStanza";
+ public static final String ORIGINAL_FROM = "originalFrom";
+ public static final String PARENT_MESSAGE_ID = "parentMessageId";
+ public static final String FROM_MUC = "fromMUC";
}
/**
@@ -190,6 +196,19 @@ public static class Fields {
private RealmList attachments;
+ /** Message forwarding */
+
+ private String originalStanza;
+
+ /** If message was forwarded contains jid of original message author */
+ private String originalFrom;
+
+ private String parentMessageId;
+
+ private RealmList forwardedIds;
+
+ private boolean fromMUC;
+
public MessageItem(String uniqueId) {
this.uniqueId = uniqueId;
}
@@ -474,4 +493,60 @@ public void setAttachments(RealmList attachments) {
public boolean haveAttachments() {
return attachments != null && attachments.size() > 0;
}
+
+ public RealmList getForwardedIds() {
+ return forwardedIds;
+ }
+
+ public String[] getForwardedIdsAsArray() {
+ String forwardedIds[] = new String[getForwardedIds().size()];
+
+ int i = 0;
+ for (ForwardId id : getForwardedIds()) {
+ forwardedIds[i] = id.getForwardMessageId();
+ i++;
+ }
+
+ return forwardedIds;
+ }
+
+ public void setForwardedIds(RealmList forwardedMessages) {
+ this.forwardedIds = forwardedMessages;
+ }
+
+ public boolean haveForwardedMessages() {
+ return forwardedIds != null && forwardedIds.size() > 0;
+ }
+
+ public String getOriginalStanza() {
+ return originalStanza;
+ }
+
+ public void setOriginalStanza(String originalStanza) {
+ this.originalStanza = originalStanza;
+ }
+
+ public String getOriginalFrom() {
+ return originalFrom;
+ }
+
+ public void setOriginalFrom(String originalFrom) {
+ this.originalFrom = originalFrom;
+ }
+
+ public String getParentMessageId() {
+ return parentMessageId;
+ }
+
+ public void setParentMessageId(String parentMessageId) {
+ this.parentMessageId = parentMessageId;
+ }
+
+ public boolean isFromMUC() {
+ return fromMUC;
+ }
+
+ public void setFromMUC(boolean fromMUC) {
+ this.fromMUC = fromMUC;
+ }
}
diff --git a/xabber/src/main/java/com/xabber/android/data/database/realm/CrowdfundingMessage.java b/xabber/src/main/java/com/xabber/android/data/database/realm/CrowdfundingMessage.java
new file mode 100644
index 0000000000..3d04be60ed
--- /dev/null
+++ b/xabber/src/main/java/com/xabber/android/data/database/realm/CrowdfundingMessage.java
@@ -0,0 +1,143 @@
+package com.xabber.android.data.database.realm;
+
+import com.xabber.android.data.Application;
+
+import java.util.Locale;
+import java.util.UUID;
+
+import io.realm.RealmObject;
+import io.realm.annotations.PrimaryKey;
+import io.realm.annotations.Required;
+
+public class CrowdfundingMessage extends RealmObject {
+
+ @PrimaryKey
+ @Required
+ private String id;
+ private boolean isLeader;
+ private int timestamp;
+ private int receivedTimestamp;
+ private String messageRu;
+ private String messageEn;
+ private boolean read;
+ private int delay;
+
+ private String authorAvatar;
+ private String authorJid;
+ private String authorNameRu;
+ private String authorNameEn;
+
+ public CrowdfundingMessage(String id) {
+ this.id = id;
+ }
+
+ public CrowdfundingMessage() {
+ this.id = UUID.randomUUID().toString();
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public int getTimestamp() {
+ return timestamp;
+ }
+
+ public void setTimestamp(int timestamp) {
+ this.timestamp = timestamp;
+ }
+
+ public String getMessageRu() {
+ return messageRu;
+ }
+
+ public void setMessageRu(String messageRu) {
+ this.messageRu = messageRu;
+ }
+
+ public String getMessageEn() {
+ return messageEn;
+ }
+
+ public void setMessageEn(String messageEn) {
+ this.messageEn = messageEn;
+ }
+
+ public boolean isRead() {
+ return read;
+ }
+
+ public void setRead(boolean read) {
+ this.read = read;
+ }
+
+ public String getAuthorAvatar() {
+ return authorAvatar;
+ }
+
+ public void setAuthorAvatar(String authorAvatar) {
+ this.authorAvatar = authorAvatar;
+ }
+
+ public String getAuthorJid() {
+ return authorJid;
+ }
+
+ public void setAuthorJid(String authorJid) {
+ this.authorJid = authorJid;
+ }
+
+ public String getAuthorNameRu() {
+ return authorNameRu;
+ }
+
+ public void setAuthorNameRu(String authorNameRu) {
+ this.authorNameRu = authorNameRu;
+ }
+
+ public String getAuthorNameEn() {
+ return authorNameEn;
+ }
+
+ public void setAuthorNameEn(String authorNameEn) {
+ this.authorNameEn = authorNameEn;
+ }
+
+ public boolean isLeader() {
+ return isLeader;
+ }
+
+ public void setLeader(boolean leader) {
+ isLeader = leader;
+ }
+
+ public int getDelay() {
+ return delay;
+ }
+
+ public void setDelay(int delay) {
+ this.delay = delay;
+ }
+
+ public int getReceivedTimestamp() {
+ return receivedTimestamp;
+ }
+
+ public void setReceivedTimestamp(int receivedTimestamp) {
+ this.receivedTimestamp = receivedTimestamp;
+ }
+
+ public String getNameForCurrentLocale() {
+ Locale currentLocale = Application.getInstance().getResources().getConfiguration().locale;
+ if (currentLocale.getLanguage().equals("ru") && getAuthorNameRu() != null)
+ return getAuthorNameRu();
+ else return getAuthorNameEn();
+ }
+
+ public String getMessageForCurrentLocale() {
+ Locale currentLocale = Application.getInstance().getResources().getConfiguration().locale;
+ if (currentLocale.getLanguage().equals("ru") && getMessageRu() != null)
+ return getMessageRu();
+ else return getMessageEn();
+ }
+}
diff --git a/xabber/src/main/java/com/xabber/android/data/extension/attention/AttentionManager.java b/xabber/src/main/java/com/xabber/android/data/extension/attention/AttentionManager.java
index b67d35d1a8..776933a03a 100644
--- a/xabber/src/main/java/com/xabber/android/data/extension/attention/AttentionManager.java
+++ b/xabber/src/main/java/com/xabber/android/data/extension/attention/AttentionManager.java
@@ -168,10 +168,11 @@ public void onStanza(ConnectionItem connection, Stanza stanza) {
for (ExtensionElement packetExtension : stanza.getExtensions()) {
if (packetExtension instanceof AttentionExtension) {
+ boolean fromMUC = ((Message) stanza).getType().equals(Message.Type.groupchat);
MessageManager.getInstance().openChat(account, from);
MessageManager.getInstance()
.getOrCreateChat(account, from)
- .newAction(null, null, ChatAction.attention_requested);
+ .newAction(null, null, ChatAction.attention_requested, fromMUC);
attentionRequestProvider.add(new AttentionRequest(account, from.getBareUserJid()), true);
}
}
@@ -205,7 +206,7 @@ public void sendAttention(AccountJid account, UserJid user) throws NetworkExcept
message.setType(Message.Type.headline);
message.addExtension(new AttentionExtension());
StanzaSender.sendStanza(account, message);
- chat.newAction(null, null, ChatAction.attention_called);
+ chat.newAction(null, null, ChatAction.attention_called, false);
}
public void removeAccountNotifications(AccountJid accountJid, UserJid userJid) {
diff --git a/xabber/src/main/java/com/xabber/android/data/extension/forward/ForwardComment.java b/xabber/src/main/java/com/xabber/android/data/extension/forward/ForwardComment.java
new file mode 100644
index 0000000000..e948d2d4d1
--- /dev/null
+++ b/xabber/src/main/java/com/xabber/android/data/extension/forward/ForwardComment.java
@@ -0,0 +1,39 @@
+package com.xabber.android.data.extension.forward;
+
+import org.jivesoftware.smack.packet.ExtensionElement;
+import org.jivesoftware.smack.util.XmlStringBuilder;
+
+public class ForwardComment implements ExtensionElement {
+
+ public static final String NAMESPACE = "xabber/comment";
+ public static final String ELEMENT = "comment";
+
+ private final String comment;
+
+ public ForwardComment(String comment) {
+ this.comment = comment;
+ }
+
+ @Override
+ public String getNamespace() {
+ return NAMESPACE;
+ }
+
+ @Override
+ public String getElementName() {
+ return ELEMENT;
+ }
+
+ @Override
+ public CharSequence toXML() {
+ XmlStringBuilder xml = new XmlStringBuilder(this);
+ xml.rightAngleBracket();
+ xml.append(comment);
+ xml.closeElement(this);
+ return xml;
+ }
+
+ public String getComment() {
+ return comment;
+ }
+}
\ No newline at end of file
diff --git a/xabber/src/main/java/com/xabber/android/data/extension/forward/ForwardCommentProvider.java b/xabber/src/main/java/com/xabber/android/data/extension/forward/ForwardCommentProvider.java
new file mode 100644
index 0000000000..aedf45d73e
--- /dev/null
+++ b/xabber/src/main/java/com/xabber/android/data/extension/forward/ForwardCommentProvider.java
@@ -0,0 +1,38 @@
+package com.xabber.android.data.extension.forward;
+
+import android.util.Log;
+
+import org.jivesoftware.smack.provider.ExtensionElementProvider;
+import org.xmlpull.v1.XmlPullParser;
+
+public class ForwardCommentProvider extends ExtensionElementProvider {
+
+ @Override
+ public ForwardComment parse(XmlPullParser parser, int initialDepth) throws Exception {
+ String comment = null;
+
+ outerloop: while (true) {
+ int eventType = parser.getEventType();
+ switch (eventType) {
+ case XmlPullParser.START_TAG:
+ if (parser.getEventType() == XmlPullParser.START_TAG
+ && ForwardComment.ELEMENT.equals(parser.getName())
+ && ForwardComment.NAMESPACE.equals(parser.getNamespace())) {
+ try {
+ comment = parser.nextText();
+ } catch (Exception e) { Log.d("CommentProvider", "error in parsing"); }
+ } else parser.next();
+ break;
+ case XmlPullParser.END_TAG:
+ if (parser.getDepth() == initialDepth) {
+ break outerloop;
+ }
+ break;
+ default:
+ parser.next();
+ }
+ }
+ if (comment != null) return new ForwardComment(comment);
+ else return null;
+ }
+}
diff --git a/xabber/src/main/java/com/xabber/android/data/extension/mam/MamManager.java b/xabber/src/main/java/com/xabber/android/data/extension/mam/MamManager.java
index cbe21d216f..f2360ba1e5 100644
--- a/xabber/src/main/java/com/xabber/android/data/extension/mam/MamManager.java
+++ b/xabber/src/main/java/com/xabber/android/data/extension/mam/MamManager.java
@@ -2,6 +2,7 @@
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import android.util.Log;
import com.xabber.android.data.Application;
import com.xabber.android.data.account.AccountItem;
@@ -9,6 +10,7 @@
import com.xabber.android.data.connection.ConnectionItem;
import com.xabber.android.data.database.MessageDatabaseManager;
import com.xabber.android.data.database.messagerealm.Attachment;
+import com.xabber.android.data.database.messagerealm.ForwardId;
import com.xabber.android.data.database.messagerealm.MessageItem;
import com.xabber.android.data.database.messagerealm.SyncInfo;
import com.xabber.android.data.entity.AccountJid;
@@ -19,6 +21,7 @@
import com.xabber.android.data.extension.otr.OTRManager;
import com.xabber.android.data.log.LogManager;
import com.xabber.android.data.message.AbstractChat;
+import com.xabber.android.data.message.ForwardManager;
import com.xabber.android.data.message.MessageManager;
import com.xabber.android.data.roster.OnRosterReceivedListener;
import com.xabber.android.data.roster.RosterContact;
@@ -32,6 +35,7 @@
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
+import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smackx.delay.packet.DelayInformation;
import org.jivesoftware.smackx.forward.packet.Forwarded;
@@ -42,6 +46,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
@@ -58,6 +63,9 @@ public class MamManager implements OnRosterReceivedListener {
private Map supportedByAccount;
+ private boolean isRequested = false;
+ private final Object lock = new Object();
+
public static MamManager getInstance() {
if (instance == null) {
instance = new MamManager();
@@ -299,6 +307,16 @@ private void syncMessages(Realm realm, AbstractChat chat, final Collection forwardIds = chat.parseForwardedMessage(false, originalMessage, remoteMessage.getUniqueId());
+ if (forwardIds != null && !forwardIds.isEmpty())
+ remoteMessage.setForwardedIds(forwardIds);
+ }
}
realm.beginTransaction();
@@ -421,6 +446,11 @@ public void run() {
return;
}
+ synchronized (lock) {
+ if (isRequested) return;
+ else isRequested = true;
+ }
+
String firstMamMessageMamId;
boolean remoteHistoryCompletelyLoaded;
{
@@ -436,6 +466,7 @@ public void run() {
}
if (firstMamMessageMamId == null || remoteHistoryCompletelyLoaded) {
+ disableLock();
return;
}
@@ -449,25 +480,34 @@ public void run() {
} catch (SmackException.NotLoggedInException | SmackException.NoResponseException | XMPPException.XMPPErrorException | InterruptedException | SmackException.NotConnectedException e) {
LogManager.exception(this, e);
EventBus.getDefault().post(new PreviousHistoryLoadFinishedEvent(chat));
+ disableLock();
return;
}
- EventBus.getDefault().post(new PreviousHistoryLoadFinishedEvent(chat));
-
LogManager.i("MAM", "queryArchive finished. fin count expected: " + mamQueryResult.mamFin.getRSMSet().getCount() + " real: " + mamQueryResult.forwardedMessages.size());
Realm realm = MessageDatabaseManager.getInstance().getNewBackgroundRealm();
+ updatePreviousHistorySyncInfo(realm, chat, mamQueryResult);
List messageItems = getMessageItems(mamQueryResult, chat);
syncMessages(realm, chat, messageItems);
- updatePreviousHistorySyncInfo(realm, chat, mamQueryResult, messageItems);
realm.close();
+
+ EventBus.getDefault().post(new PreviousHistoryLoadFinishedEvent(chat));
+ disableLock();
}
});
}
- private void updatePreviousHistorySyncInfo(Realm realm, BaseEntity chat, org.jivesoftware.smackx.mam.MamManager.MamQueryResult mamQueryResult, List messageItems) {
+ private void disableLock() {
+ synchronized (lock) {
+ isRequested = false;
+ }
+ }
+
+ private void updatePreviousHistorySyncInfo(Realm realm, BaseEntity chat,
+ org.jivesoftware.smackx.mam.MamManager.MamQueryResult mamQueryResult) {
SyncInfo syncInfo = getSyncInfo(realm, chat.getAccount(), chat.getUser());
realm.beginTransaction();
@@ -522,7 +562,8 @@ private List getMessageItems(org.jivesoftware.smackx.mam.MamManager
boolean incoming = message.getFrom().asBareJid().equals(chat.getUser().getJid().asBareJid());
- MessageItem messageItem = new MessageItem();
+ String uid = UUID.randomUUID().toString();
+ MessageItem messageItem = new MessageItem(uid);
messageItem.setAccount(chat.getAccount());
messageItem.setUser(chat.getUser());
@@ -539,12 +580,17 @@ private List getMessageItems(org.jivesoftware.smackx.mam.MamManager
messageItem.setSent(true);
messageItem.setEncrypted(encrypted);
+ // attachments
FileManager.processFileMessage(messageItem);
RealmList attachments = HttpFileUploadManager.parseFileMessage(message);
if (attachments.size() > 0)
messageItem.setAttachments(attachments);
+ // forwarded
+ messageItem.setOriginalStanza(message.toXML().toString());
+ messageItem.setOriginalFrom(message.getFrom().toString());
+
messageItems.add(messageItem);
}
return messageItems;
@@ -607,7 +653,7 @@ public void requestFullChatHistory(final AbstractChat chat) {
Realm realm = MessageDatabaseManager.getInstance().getNewBackgroundRealm();
List messageItems = getMessageItems(mamQueryResult, chat);
syncMessages(realm, chat, messageItems);
- updatePreviousHistorySyncInfo(realm, chat, mamQueryResult, messageItems);
+ updatePreviousHistorySyncInfo(realm, chat, mamQueryResult);
realm.close();
}
}
diff --git a/xabber/src/main/java/com/xabber/android/data/extension/muc/MUCManager.java b/xabber/src/main/java/com/xabber/android/data/extension/muc/MUCManager.java
index d1041197de..a2c103846c 100644
--- a/xabber/src/main/java/com/xabber/android/data/extension/muc/MUCManager.java
+++ b/xabber/src/main/java/com/xabber/android/data/extension/muc/MUCManager.java
@@ -452,7 +452,7 @@ public void leaveRoom(AccountJid account, EntityBareJid room) {
multiUserChat = roomChat.getMultiUserChat();
roomChat.setState(RoomState.unavailable);
roomChat.setRequested(false);
- roomChat.newAction(roomChat.getNickname(), null, ChatAction.leave);
+ roomChat.newAction(roomChat.getNickname(), null, ChatAction.leave, true);
requestToWriteRoom(account, room, roomChat.getNickname(), roomChat.getPassword(), false);
if (multiUserChat != null) {
Application.getInstance().runInBackgroundUserRequest(new Runnable() {
@@ -535,7 +535,7 @@ public void invite(AccountJid account, EntityBareJid room, UserJid user) throws
message.addExtension(mucUser);
StanzaSender.sendStanza(account, message);
roomChat.putInvite(message.getStanzaId(), user);
- roomChat.newAction(roomChat.getNickname(), user.toString(), ChatAction.invite_sent);
+ roomChat.newAction(roomChat.getNickname(), user.toString(), ChatAction.invite_sent, true);
}
public void removeAuthorizationError(AccountJid account, EntityBareJid room) {
diff --git a/xabber/src/main/java/com/xabber/android/data/extension/muc/RoomChat.java b/xabber/src/main/java/com/xabber/android/data/extension/muc/RoomChat.java
index 1f09cc657d..9d11721a9e 100644
--- a/xabber/src/main/java/com/xabber/android/data/extension/muc/RoomChat.java
+++ b/xabber/src/main/java/com/xabber/android/data/extension/muc/RoomChat.java
@@ -24,12 +24,14 @@
import com.xabber.android.data.account.StatusMode;
import com.xabber.android.data.database.MessageDatabaseManager;
import com.xabber.android.data.database.messagerealm.Attachment;
+import com.xabber.android.data.database.messagerealm.ForwardId;
import com.xabber.android.data.database.messagerealm.MessageItem;
import com.xabber.android.data.entity.AccountJid;
import com.xabber.android.data.entity.UserJid;
import com.xabber.android.data.extension.httpfileupload.HttpFileUploadManager;
import com.xabber.android.data.message.AbstractChat;
import com.xabber.android.data.message.ChatAction;
+import com.xabber.android.data.message.ForwardManager;
import com.xabber.android.data.message.NewIncomingMessageEvent;
import com.xabber.android.data.message.chat.ChatManager;
import com.xabber.android.data.roster.RosterManager;
@@ -187,7 +189,8 @@ void putInvite(String packetID, UserJid user) {
@Override
protected MessageItem createNewMessageItem(String text) {
return createMessageItem(nickname, text, null, null, false,
- false, false, false, UUID.randomUUID().toString(), null);
+ false, false, false, UUID.randomUUID().toString(), null,
+ null, null, account.getFullJid().toString(), null, false);
}
@Override
@@ -218,7 +221,7 @@ protected boolean onPacket(UserJid bareAddress, Stanza stanza, boolean isCarbons
if (message.getType() == Message.Type.error) {
UserJid invite = invites.remove(message.getStanzaId());
if (invite != null) {
- newAction(nickname, invite.toString(), ChatAction.invite_error);
+ newAction(nickname, invite.toString(), ChatAction.invite_error, true);
}
return true;
}
@@ -232,7 +235,7 @@ protected boolean onPacket(UserJid bareAddress, Stanza stanza, boolean isCarbons
// 'This room is not anonymous'
return true;
}
- final String text = message.getBody();
+ String text = message.getBody();
final String subject = message.getSubject();
if (text == null && subject == null) {
return true;
@@ -243,7 +246,7 @@ protected boolean onPacket(UserJid bareAddress, Stanza stanza, boolean isCarbons
}
this.subject = subject;
RosterManager.onContactChanged(account, bareAddress);
- newAction(resource, subject, ChatAction.subject);
+ newAction(resource, subject, ChatAction.subject, true);
} else {
boolean notify = true;
String stanzaId = message.getStanzaId();
@@ -261,6 +264,11 @@ protected boolean onPacket(UserJid bareAddress, Stanza stanza, boolean isCarbons
notify = false;
}
+ // forward comment
+ String forwardComment = ForwardManager.parseForwardComment(stanza);
+ if (forwardComment != null && !forwardComment.isEmpty())
+ text = forwardComment;
+
String messageUId = getMessageIdIfInHistory(stanzaId, text);
if (messageUId != null) {
if (isSelf(resource)) {
@@ -277,14 +285,21 @@ protected boolean onPacket(UserJid bareAddress, Stanza stanza, boolean isCarbons
RealmList attachments = HttpFileUploadManager.parseFileMessage(stanza);
+ String uid = UUID.randomUUID().toString();
+ RealmList forwardIds = parseForwardedMessage(true, stanza, uid);
+ String originalStanza = stanza.toXML().toString();
+ String originalFrom = stanza.getFrom().toString();
+
// create message with file-attachments
if (attachments.size() > 0)
- createAndSaveFileMessage(resource, text, null, delay, true, notify,
- false, false, stanzaId, attachments);
+ createAndSaveFileMessage(true, uid, resource, text, null, delay, true, notify,
+ false, false, stanzaId, attachments,
+ originalStanza, null, originalFrom, true, false);
// create message without attachments
- else createAndSaveNewMessage(resource, text, null, delay, true, notify,
- false, false, stanzaId);
+ else createAndSaveNewMessage(true, uid, resource, text, null, delay, true, notify,
+ false, false, stanzaId,
+ originalStanza, null, originalFrom, forwardIds, true, false);
EventBus.getDefault().post(new NewIncomingMessageEvent(account, user));
}
@@ -345,7 +360,48 @@ else createAndSaveNewMessage(resource, text, null, delay, true, notify,
return true;
}
- private void markMessageAsDelivered(final String messageUId) {
+ @Override
+ protected String parseInnerMessage(boolean ui, Message message, String parentMessageId) {
+ if (message.getType() == Message.Type.error) return null;
+
+ final org.jxmpp.jid.Jid from = message.getFrom();
+ final Resourcepart resource = from.getResourceOrNull();
+ String text = message.getBody();
+ final String subject = message.getSubject();
+
+ if (text == null) return null;
+ if (subject != null) return null;
+
+ String stanzaId = message.getStanzaId();
+
+ // Use stanza id from XEP-0359 if common stanza id is null
+ if (stanzaId == null) stanzaId = UniqStanzaHelper.getStanzaId(message);
+
+ RealmList attachments = HttpFileUploadManager.parseFileMessage(message);
+
+ String uid = UUID.randomUUID().toString();
+ RealmList forwardIds = parseForwardedMessage(ui, message, uid);
+ String originalStanza = message.toXML().toString();
+ String originalFrom = message.getFrom().toString();
+ boolean fromMUC = message.getType().equals(Type.groupchat);
+ String forwardComment = ForwardManager.parseForwardComment(message);
+ if (forwardComment != null) text = forwardComment;
+
+ // create message with file-attachments
+ if (attachments.size() > 0)
+ createAndSaveFileMessage(ui, uid, resource, text, null, null,
+ true, false, false, false, stanzaId, attachments,
+ originalStanza, parentMessageId, originalFrom, fromMUC, true);
+
+ // create message without attachments
+ else createAndSaveNewMessage(ui, uid, resource, text, null, null,
+ true, false, false, false, stanzaId,
+ originalStanza, parentMessageId, originalFrom, forwardIds, fromMUC, true);
+
+ return uid;
+ }
+
+ private void markMessageAsDelivered(final String messageUId) {
Application.getInstance().runInBackground(new Runnable() {
@Override
public void run() {
@@ -406,21 +462,23 @@ private void onAvailable(Resourcepart resource) {
setState(RoomState.available);
if (isRequested()) {
if (showStatusChange()) {
- createAndSaveNewMessage(resource, Application.getInstance().getString(
+ createAndSaveNewMessage(true, UUID.randomUUID().toString(), resource, Application.getInstance().getString(
R.string.action_join_complete_to, user),
- ChatAction.complete, null, true, true, false, false, null);
+ ChatAction.complete, null, true, true,
+ false, false, null,
+ null, null, null, null, true, false);
}
active = true;
setRequested(false);
} else {
if (showStatusChange()) {
- newAction(resource, null, ChatAction.complete);
+ newAction(resource, null, ChatAction.complete, true);
}
}
} else {
if (state == RoomState.available) {
if (showStatusChange()) {
- newAction(resource, null, ChatAction.join);
+ newAction(resource, null, ChatAction.join, true);
}
}
}
@@ -483,7 +541,7 @@ private void onStatusChanged(Resourcepart resource, StatusMode statusMode, Strin
*/
private void onLeave(Resourcepart resource) {
if (showStatusChange()) {
- newAction(resource, null, ChatAction.leave);
+ newAction(resource, null, ChatAction.leave, true);
}
if (isSelf(resource)) {
setState(RoomState.waiting);
@@ -499,8 +557,8 @@ private void onLeave(Resourcepart resource) {
*/
private void onKick(Resourcepart resource, org.jxmpp.jid.Jid actor) {
if (showStatusChange()) {
- if (actor != null) newAction(resource, actor.toString(), ChatAction.kick);
- else newAction(resource, "", ChatAction.kick);
+ if (actor != null) newAction(resource, actor.toString(), ChatAction.kick, true);
+ else newAction(resource, "", ChatAction.kick, true);
}
if (isSelf(resource)) {
MUCManager.getInstance().leaveRoom(account, getRoom());
@@ -515,7 +573,7 @@ private void onKick(Resourcepart resource, org.jxmpp.jid.Jid actor) {
*/
private void onBan(Resourcepart resource, org.jxmpp.jid.Jid actor) {
if (showStatusChange()) {
- newAction(resource, actor.toString(), ChatAction.ban);
+ newAction(resource, actor.toString(), ChatAction.ban, true);
}
if (isSelf(resource)) {
MUCManager.getInstance().leaveRoom(account, getRoom());
@@ -530,7 +588,7 @@ private void onBan(Resourcepart resource, org.jxmpp.jid.Jid actor) {
*/
private void onRename(Resourcepart resource, Resourcepart newNick) {
if (showStatusChange()) {
- newAction(resource, newNick.toString(), ChatAction.nickname);
+ newAction(resource, newNick.toString(), ChatAction.nickname, true);
}
}
@@ -542,7 +600,7 @@ private void onRename(Resourcepart resource, Resourcepart newNick) {
*/
private void onRevoke(Resourcepart resource, org.jxmpp.jid.Jid actor) {
if (showStatusChange()) {
- newAction(resource, actor.toString(), ChatAction.kick);
+ newAction(resource, actor.toString(), ChatAction.kick, true);
}
if (isSelf(resource)) {
MUCManager.getInstance().leaveRoom(account, getRoom());
diff --git a/xabber/src/main/java/com/xabber/android/data/extension/otr/OTRManager.java b/xabber/src/main/java/com/xabber/android/data/extension/otr/OTRManager.java
index ac83b5ffc9..a39ee04fb3 100644
--- a/xabber/src/main/java/com/xabber/android/data/extension/otr/OTRManager.java
+++ b/xabber/src/main/java/com/xabber/android/data/extension/otr/OTRManager.java
@@ -287,7 +287,7 @@ private void newAction(String account, String user, String text, ChatAction acti
LogManager.i(this, "newAction. text: " + text + " action " + action);
AbstractChat chat = getChat(account, user);
if (chat != null) {
- chat.newAction(null, text, action);
+ chat.newAction(null, text, action, false);
}
}
diff --git a/xabber/src/main/java/com/xabber/android/data/http/CrowdfundingClient.java b/xabber/src/main/java/com/xabber/android/data/http/CrowdfundingClient.java
new file mode 100644
index 0000000000..0a0178a45f
--- /dev/null
+++ b/xabber/src/main/java/com/xabber/android/data/http/CrowdfundingClient.java
@@ -0,0 +1,142 @@
+package com.xabber.android.data.http;
+
+import com.xabber.android.R;
+import com.xabber.android.data.Application;
+import com.xabber.android.data.database.realm.CrowdfundingMessage;
+import com.xabber.android.data.xaccount.HttpApiManager;
+
+import java.util.List;
+
+import rx.Single;
+import rx.functions.Func1;
+
+public class CrowdfundingClient {
+
+ public static Single> getLeader() {
+ if (getAPIKey().length() < 20) return Single.error(new Throwable("API key not provided"));
+ return HttpApiManager.getCrowdfundingApi().getLeader(getAPIKey())
+ .flatMap(new Func1, Single extends List>>() {
+ @Override
+ public Single extends List> call(List messages) {
+ return CrowdfundingManager.getInstance().saveCrowdfundingMessageToRealm(messages);
+ }
+ });
+ }
+
+ public static Single> getFeed(int timestamp) {
+ if (getAPIKey().length() < 20) return Single.error(new Throwable("API key not provided"));
+ return HttpApiManager.getCrowdfundingApi().getFeed(getAPIKey(), timestamp)
+ .flatMap(new Func1, Single extends List>>() {
+ @Override
+ public Single extends List> call(List messages) {
+ return CrowdfundingManager.getInstance().saveCrowdfundingMessageToRealm(messages);
+ }
+ });
+ }
+
+ private static String getAPIKey() {
+ return "APIKey " + Application.getInstance().getResources().getString(R.string.CROWDFUNDING_KEY);
+ }
+
+ public static class Message {
+ private final String uuid;
+ private final boolean is_leader;
+ private final int timestamp;
+ private final List feed;
+ private final Author author;
+ private int delay;
+
+ public Message(String uuid, boolean is_leader, int timestamp, List feed, Author author, int delay) {
+ this.uuid = uuid;
+ this.is_leader = is_leader;
+ this.timestamp = timestamp;
+ this.feed = feed;
+ this.author = author;
+ this.delay = delay;
+ }
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ public int getTimestamp() {
+ return timestamp;
+ }
+
+ public List getFeed() {
+ return feed;
+ }
+
+ public Author getAuthor() {
+ return author;
+ }
+
+ public boolean isLeader() {
+ return is_leader;
+ }
+
+ public int getDelay() {
+ return delay;
+ }
+ }
+
+ public static class LocalizedMessage {
+ private final String locale;
+ private final String message;
+
+ public LocalizedMessage(String locale, String message) {
+ this.locale = locale;
+ this.message = message;
+ }
+
+ public String getLocale() {
+ return locale;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+ }
+
+ public static class Author {
+ private final String avatar;
+ private final String jabber_id;
+ private List name;
+
+ public Author(String avatar, String jabber_id, List name) {
+ this.avatar = avatar;
+ this.jabber_id = jabber_id;
+ this.name = name;
+ }
+
+ public String getAvatar() {
+ return avatar;
+ }
+
+ public String getJabberId() {
+ return jabber_id;
+ }
+
+ public List getName() {
+ return name;
+ }
+ }
+
+ public static class LocalizedName {
+ private final String locale;
+ private final String name;
+
+ public LocalizedName(String locale, String name) {
+ this.locale = locale;
+ this.name = name;
+ }
+
+ public String getLocale() {
+ return locale;
+ }
+
+ public String getName() {
+ return name;
+ }
+ }
+}
\ No newline at end of file
diff --git a/xabber/src/main/java/com/xabber/android/data/http/CrowdfundingManager.java b/xabber/src/main/java/com/xabber/android/data/http/CrowdfundingManager.java
new file mode 100644
index 0000000000..c573fc5f73
--- /dev/null
+++ b/xabber/src/main/java/com/xabber/android/data/http/CrowdfundingManager.java
@@ -0,0 +1,258 @@
+package com.xabber.android.data.http;
+
+import android.util.Log;
+
+import com.xabber.android.BuildConfig;
+import com.xabber.android.data.SettingsManager;
+import com.xabber.android.data.database.RealmManager;
+import com.xabber.android.data.database.realm.CrowdfundingMessage;
+import com.xabber.android.data.message.NewMessageEvent;
+
+import org.greenrobot.eventbus.EventBus;
+
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.TimeUnit;
+
+import io.realm.Realm;
+import io.realm.RealmList;
+import io.realm.RealmResults;
+import rx.Observable;
+import rx.Single;
+import rx.android.schedulers.AndroidSchedulers;
+import rx.functions.Action1;
+import rx.schedulers.Schedulers;
+import rx.subscriptions.CompositeSubscription;
+
+public class CrowdfundingManager {
+
+ private static final int CACHE_LIFETIME = (int) TimeUnit.DAYS.toSeconds(1);
+ private static final int CROWDFUNDING_DELAY = BuildConfig.FLAVOR.equals("dev") ?
+ (int) TimeUnit.MINUTES.toSeconds(1) : (int) TimeUnit.HOURS.toSeconds(1);
+
+ private static CrowdfundingManager instance;
+ private CompositeSubscription compositeSubscription = new CompositeSubscription();
+ private Timer timer;
+
+ public static CrowdfundingManager getInstance() {
+ if (instance == null)
+ instance = new CrowdfundingManager ();
+ return instance;
+ }
+
+ public void onLoad() {
+ CrowdfundingMessage lastMessage = getLastMessageFromRealm();
+ if (lastMessage == null) {
+ if (SettingsManager.getFirstAppRunTimestamp() == 0)
+ SettingsManager.setFirstAppRunTimestamp(getCurrentTime());
+ else if (isTimeToCrowdfunding() && isLeaderCacheExpired()) requestLeader();
+ }
+ else if (!CrowdfundingManager.getInstance().haveDelayedMessages() && isCacheExpired())
+ requestFeed(lastMessage.getReceivedTimestamp());
+ }
+
+ private void requestLeader() {
+ compositeSubscription.add(CrowdfundingClient.getLeader()
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(new Action1>() {
+ @Override
+ public void call(List crowdfundingMessages) {
+ Log.d("crowd", "ok");
+ SettingsManager.setLastLeaderCrowdfundingLoadTimestamp(getCurrentTime());
+ EventBus.getDefault().post(new NewMessageEvent());
+ }
+ }, new Action1() {
+ @Override
+ public void call(Throwable throwable) {
+ Log.d("crowd", throwable.toString());
+ }
+ }));
+ }
+
+ public void startUpdateTimer(final int delay, final int step) {
+ if (timer != null) timer.cancel();
+ if (!CrowdfundingManager.getInstance().haveDelayedMessages()) {
+ CrowdfundingMessage lastMessage = getLastMessageFromRealm();
+ if (lastMessage != null && isCacheExpired()) requestFeed(lastMessage.getReceivedTimestamp());
+ return;
+ }
+
+ timer = new Timer();
+ timer.schedule(new TimerTask() {
+ @Override
+ public void run() {
+ CrowdfundingManager.getInstance().removeDelay(delay + step);
+ EventBus.getDefault().post(new NewMessageEvent());
+ startUpdateTimer(delay + step, step);
+ }
+ }, step * 1000);
+ }
+
+ private void requestFeed(int timestamp) {
+ compositeSubscription.add(CrowdfundingClient.getFeed(timestamp)
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(new Action1>() {
+ @Override
+ public void call(List crowdfundingMessages) {
+ Log.d("crowd", "ok");
+ SettingsManager.setLastCrowdfundingLoadTimestamp(getCurrentTime());
+ EventBus.getDefault().post(new NewMessageEvent());
+ }
+ }, new Action1() {
+ @Override
+ public void call(Throwable throwable) {
+ Log.d("crowd", throwable.toString());
+ }
+ }));
+ }
+
+ public Single> saveCrowdfundingMessageToRealm(List messages) {
+
+ RealmList realmMessages = new RealmList<>();
+ for (CrowdfundingClient.Message message : messages) {
+ realmMessages.add(messageToRealm(message));
+ }
+
+ Realm realm = RealmManager.getInstance().getNewRealm();
+ realm.beginTransaction();
+ List result = realm.copyToRealmOrUpdate(realmMessages);
+ realm.commitTransaction();
+
+ return Single.just(result);
+ }
+
+ private CrowdfundingMessage messageToRealm(CrowdfundingClient.Message message) {
+ CrowdfundingMessage realmMessage = new CrowdfundingMessage(message.getUuid());
+ realmMessage.setRead(false);
+ realmMessage.setDelay(message.getDelay());
+ realmMessage.setLeader(message.isLeader());
+ realmMessage.setTimestamp(message.getTimestamp());
+ realmMessage.setReceivedTimestamp(getCurrentTime());
+ realmMessage.setAuthorAvatar(message.getAuthor().getAvatar());
+ realmMessage.setAuthorJid(message.getAuthor().getJabberId());
+
+ for (CrowdfundingClient.LocalizedMessage locale : message.getFeed()) {
+ if ("en".equals(locale.getLocale())) realmMessage.setMessageEn(locale.getMessage());
+ if ("ru".equals(locale.getLocale())) realmMessage.setMessageRu(locale.getMessage());
+ }
+
+ for (CrowdfundingClient.LocalizedName name : message.getAuthor().getName()) {
+ if ("en".equals(name.getLocale())) realmMessage.setAuthorNameEn(name.getName());
+ if ("ru".equals(name.getLocale())) realmMessage.setAuthorNameRu(name.getName());
+ }
+
+ return realmMessage;
+ }
+
+ public boolean haveDelayedMessages() {
+ Realm realm = RealmManager.getInstance().getNewRealm();
+ CrowdfundingMessage message = realm.where(CrowdfundingMessage.class)
+ .notEqualTo("delay", 0).findFirst();
+ return message != null;
+ }
+
+ public RealmResults getMessagesWithDelay(int delay) {
+ Realm realm = RealmManager.getInstance().getNewRealm();
+ return realm.where(CrowdfundingMessage.class)
+ .lessThanOrEqualTo("delay", delay)
+ .findAllSorted("timestamp");
+ }
+
+ public void removeDelay(int delay) {
+ Realm realm = RealmManager.getInstance().getNewRealm();
+ RealmResults messages = getMessagesWithDelay(delay);
+ realm.beginTransaction();
+ for (CrowdfundingMessage message : messages) {
+ // remove delay and update received time
+ message.setDelay(0);
+ message.setReceivedTimestamp(getCurrentTime());
+ }
+ realm.commitTransaction();
+ realm.close();
+ }
+
+ public CrowdfundingMessage getLastMessageFromRealm() {
+ Realm realm = RealmManager.getInstance().getNewRealm();
+ RealmResults messages = realm.where(CrowdfundingMessage.class).findAllSorted("timestamp");
+ if (messages != null && !messages.isEmpty()) return messages.last();
+ else return null;
+ }
+
+ public CrowdfundingMessage getLastNotDelayedMessageFromRealm() {
+ Realm realm = RealmManager.getInstance().getNewRealm();
+ RealmResults messages = realm.where(CrowdfundingMessage.class)
+ .equalTo("delay", 0)
+ .findAllSorted("timestamp");
+ if (messages != null && !messages.isEmpty()) return messages.last();
+ else return null;
+ }
+
+ public int getUnreadMessageCount() {
+ Realm realm = RealmManager.getInstance().getNewRealm();
+ Long count = realm.where(CrowdfundingMessage.class).equalTo("read", false)
+ .equalTo("delay", 0).count();
+ return count.intValue();
+ }
+
+ public Observable> getUnreadMessageCountAsObservable() {
+ Realm realm = RealmManager.getInstance().getNewRealm();
+ return realm.where(CrowdfundingMessage.class).equalTo("read", false)
+ .equalTo("delay", 0).findAll().asObservable();
+ }
+
+ public void reloadMessages() {
+ removeAllMessages();
+ requestLeader();
+ SettingsManager.setFirstAppRunTimestamp(0);
+ SettingsManager.setLastCrowdfundingLoadTimestamp(1);
+ SettingsManager.setLastLeaderCrowdfundingLoadTimestamp(1);
+ }
+
+ /** Ignore business rules. Use only for debug */
+ public void fetchFeedForDebug() {
+ CrowdfundingMessage lastMessage = getLastMessageFromRealm();
+ if (lastMessage != null) requestFeed(lastMessage.getReceivedTimestamp());
+ }
+
+ public void markMessagesAsRead(String[] ids) {
+ if (ids.length == 0) return;
+ Realm realm = RealmManager.getInstance().getNewRealm();
+ RealmResults messages = realm.where(CrowdfundingMessage.class)
+ .equalTo("read", false).in("id", ids).findAll();
+
+ realm.beginTransaction();
+ for (CrowdfundingMessage message : messages) {
+ message.setRead(true);
+ }
+ realm.commitTransaction();
+ }
+
+ private void removeAllMessages() {
+ Realm realm = RealmManager.getInstance().getNewRealm();
+ RealmResults messages = realm.where(CrowdfundingMessage.class).findAllSorted("timestamp");
+ realm.beginTransaction();
+ for (CrowdfundingMessage message : messages)
+ message.deleteFromRealm();
+ realm.commitTransaction();
+ }
+
+ private boolean isCacheExpired() {
+ return getCurrentTime() > SettingsManager.getLastCrowdfundingLoadTimestamp() + CACHE_LIFETIME;
+ }
+
+ private boolean isLeaderCacheExpired() {
+ return getCurrentTime() > SettingsManager.getLastLeaderCrowdfundingLoadTimestamp() + CACHE_LIFETIME;
+ }
+
+ private boolean isTimeToCrowdfunding() {
+ return getCurrentTime() > SettingsManager.getFirstAppRunTimestamp() + CROWDFUNDING_DELAY;
+ }
+
+ public int getCurrentTime() {
+ return (int) (System.currentTimeMillis() / 1000L);
+ }
+
+}
diff --git a/xabber/src/main/java/com/xabber/android/data/http/ICrowdfundingApi.java b/xabber/src/main/java/com/xabber/android/data/http/ICrowdfundingApi.java
new file mode 100644
index 0000000000..e360e21861
--- /dev/null
+++ b/xabber/src/main/java/com/xabber/android/data/http/ICrowdfundingApi.java
@@ -0,0 +1,18 @@
+package com.xabber.android.data.http;
+
+import java.util.List;
+
+import retrofit2.http.GET;
+import retrofit2.http.Header;
+import retrofit2.http.Query;
+import rx.Single;
+
+public interface ICrowdfundingApi {
+
+ @GET("leader/")
+ Single> getLeader(@Header("Authorization") String apiKey);
+
+ @GET("feed/")
+ Single> getFeed(@Header("Authorization") String apiKey, @Query("timestamp") int timestamp);
+
+}
diff --git a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java
index 16e04df82e..0272c81c47 100644
--- a/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java
+++ b/xabber/src/main/java/com/xabber/android/data/message/AbstractChat.java
@@ -18,12 +18,14 @@
import android.support.annotation.Nullable;
import android.util.Log;
+import com.xabber.android.R;
import com.xabber.android.data.Application;
import com.xabber.android.data.NetworkException;
import com.xabber.android.data.SettingsManager;
import com.xabber.android.data.connection.StanzaSender;
import com.xabber.android.data.database.MessageDatabaseManager;
import com.xabber.android.data.database.messagerealm.Attachment;
+import com.xabber.android.data.database.messagerealm.ForwardId;
import com.xabber.android.data.database.messagerealm.MessageItem;
import com.xabber.android.data.database.messagerealm.SyncInfo;
import com.xabber.android.data.entity.AccountJid;
@@ -32,6 +34,7 @@
import com.xabber.android.data.extension.carbons.CarbonManager;
import com.xabber.android.data.extension.cs.ChatStateManager;
import com.xabber.android.data.extension.file.FileManager;
+import com.xabber.android.data.extension.forward.ForwardComment;
import com.xabber.android.data.extension.httpfileupload.ExtendedFormField;
import com.xabber.android.data.extension.httpfileupload.HttpFileUploadManager;
import com.xabber.android.data.extension.otr.OTRManager;
@@ -42,11 +45,14 @@
import org.greenrobot.eventbus.EventBus;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.StanzaListener;
+import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Message.Type;
import org.jivesoftware.smack.packet.Stanza;
+import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.delay.packet.DelayInformation;
+import org.jivesoftware.smackx.forward.packet.Forwarded;
import org.jivesoftware.smackx.xdata.packet.DataForm;
import org.jxmpp.jid.Jid;
import org.jxmpp.jid.parts.Resourcepart;
@@ -237,8 +243,10 @@ public boolean notifyAboutMessage() {
* @param resource can be null
.
* @param text can be null
.
*/
- public void newAction(Resourcepart resource, String text, ChatAction action) {
- createAndSaveNewMessage(resource, text, action, null, true, false, false, false, null);
+ public void newAction(Resourcepart resource, String text, ChatAction action, boolean fromMUC) {
+ createAndSaveNewMessage(true, UUID.randomUUID().toString(), resource, text, action,
+ null, true, false, false, false,
+ null, null, null, null, null, fromMUC, false);
}
/**
@@ -256,28 +264,41 @@ public void newAction(Resourcepart resource, String text, ChatAction action) {
* @param offline Whether message was received from server side offline storage.
* @return
*/
- protected void createAndSaveNewMessage(Resourcepart resource, String text,
- final ChatAction action, final Date delayTimestamp, final boolean incoming,
- boolean notify, final boolean encrypted, final boolean offline, final String stanzaId) {
- final MessageItem messageItem = createMessageItem(resource, text, action, delayTimestamp,
- incoming, notify, encrypted, offline, stanzaId, null);
- saveMessageItem(messageItem);
+ protected void createAndSaveNewMessage(boolean ui, String uid, Resourcepart resource, String text, final ChatAction action,
+ final Date delayTimestamp, final boolean incoming, boolean notify,
+ final boolean encrypted, final boolean offline, final String stanzaId,
+ final String originalStanza, final String parentMessageId, final String originalFrom,
+ final RealmList forwardIds, boolean fromMUC, boolean fromMAM) {
+
+ final MessageItem messageItem = createMessageItem(uid, resource, text, action, delayTimestamp,
+ incoming, notify, encrypted, offline, stanzaId, null,
+ originalStanza, parentMessageId, originalFrom, forwardIds, fromMUC, fromMAM);
+
+ saveMessageItem(ui, messageItem);
EventBus.getDefault().post(new NewMessageEvent());
}
- protected void createAndSaveFileMessage(Resourcepart resource, String text, final ChatAction action, final Date delayTimestamp,
- final boolean incoming, boolean notify, final boolean encrypted, final boolean offline,
- final String stanzaId, RealmList attachments) {
- final MessageItem messageItem = createMessageItem(resource, text, action, delayTimestamp,
- incoming, notify, encrypted, offline, stanzaId, attachments);
- saveMessageItem(messageItem);
+ protected void createAndSaveFileMessage(boolean ui, String uid, Resourcepart resource, String text, final ChatAction action,
+ final Date delayTimestamp, final boolean incoming, boolean notify,
+ final boolean encrypted, final boolean offline, final String stanzaId,
+ RealmList attachments, final String originalStanza,
+ final String parentMessageId, final String originalFrom, boolean fromMUC, boolean fromMAM) {
+
+ final MessageItem messageItem = createMessageItem(uid, resource, text, action, delayTimestamp,
+ incoming, notify, encrypted, offline, stanzaId, attachments,
+ originalStanza, parentMessageId, originalFrom, null, fromMUC, fromMAM);
+
+ saveMessageItem(ui, messageItem);
EventBus.getDefault().post(new NewMessageEvent());
}
- public void saveMessageItem(final MessageItem messageItem) {
+ public void saveMessageItem(boolean ui, final MessageItem messageItem) {
final long startTime = System.currentTimeMillis();
- MessageDatabaseManager.getInstance().getRealmUiThread()
- .executeTransactionAsync(new Realm.Transaction() {
+ Realm realm;
+ if (ui) realm = MessageDatabaseManager.getInstance().getRealmUiThread();
+ else realm = MessageDatabaseManager.getInstance().getNewBackgroundRealm();
+
+ realm.executeTransactionAsync(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
realm.copyToRealm(messageItem);
@@ -288,9 +309,22 @@ public void execute(Realm realm) {
}
protected MessageItem createMessageItem(Resourcepart resource, String text, ChatAction action,
- Date delayTimestamp, boolean incoming, boolean notify,
- boolean encrypted, boolean offline, String stanzaId,
- RealmList attachments) {
+ Date delayTimestamp, boolean incoming, boolean notify, boolean encrypted,
+ boolean offline, String stanzaId, RealmList attachments,
+ String originalStanza, String parentMessageId, String originalFrom,
+ RealmList forwardIds, boolean fromMUC) {
+
+ return createMessageItem(UUID.randomUUID().toString(), resource, text, action,
+ delayTimestamp, incoming, notify, encrypted, offline, stanzaId, attachments,
+ originalStanza, parentMessageId, originalFrom, forwardIds, fromMUC, false);
+ }
+
+ protected MessageItem createMessageItem(String uid, Resourcepart resource, String text, ChatAction action,
+ Date delayTimestamp, boolean incoming, boolean notify, boolean encrypted,
+ boolean offline, String stanzaId, RealmList attachments,
+ String originalStanza, String parentMessageId, String originalFrom,
+ RealmList forwardIds, boolean fromMUC, boolean fromMAM) {
+
final boolean visible = MessageManager.getInstance().isVisibleChat(this);
boolean read = incoming ? visible : true;
boolean send = incoming;
@@ -324,7 +358,7 @@ protected MessageItem createMessageItem(Resourcepart resource, String text, Chat
}
}
- MessageItem messageItem = new MessageItem();
+ MessageItem messageItem = new MessageItem(uid);
messageItem.setAccount(account);
messageItem.setUser(user);
@@ -344,21 +378,28 @@ protected MessageItem createMessageItem(Resourcepart resource, String text, Chat
messageItem.setDelayTimestamp(delayTimestamp.getTime());
}
messageItem.setIncoming(incoming);
- messageItem.setRead(read);
+ messageItem.setRead(fromMAM || read);
messageItem.setSent(send);
messageItem.setEncrypted(encrypted);
messageItem.setOffline(offline);
+ messageItem.setFromMUC(fromMUC);
messageItem.setStanzaId(stanzaId);
if (attachments != null) messageItem.setAttachments(attachments);
FileManager.processFileMessage(messageItem);
+ // forwarding
+ if (forwardIds != null) messageItem.setForwardedIds(forwardIds);
+ messageItem.setOriginalStanza(originalStanza);
+ messageItem.setOriginalFrom(originalFrom);
+ messageItem.setParentMessageId(parentMessageId);
+
if (notify && notifyAboutMessage() && !visible) {
NotificationManager.getInstance().onMessageNotification(messageItem);
}
// unread message count
if (!visible && action == null) {
- if (incoming) increaseUnreadMessageCount();
+ if (incoming && !fromMAM) increaseUnreadMessageCount();
else resetUnreadMessageCount();
}
@@ -577,6 +618,28 @@ boolean sendMessage(MessageItem messageItem) {
message = createFileMessagePacket(messageItem.getStanzaId(),
messageItem.getAttachments(), text);
+ } else if (messageItem.haveForwardedMessages()) {
+
+ int count = messageItem.getForwardedIds().size();
+ String body = String.format(Application.getInstance().getResources()
+ .getString(R.string.forwarded_support_text), count);
+ if (text != null && !text.isEmpty()) body += "\n" + text;
+
+ message = createMessagePacket(body, messageItem.getStanzaId());
+
+ Realm realm = MessageDatabaseManager.getInstance().getNewBackgroundRealm();
+ for (ForwardId id : messageItem.getForwardedIds()) {
+ MessageItem forwardedMessage = realm.where(MessageItem.class)
+ .equalTo(MessageItem.Fields.UNIQUE_ID, id.getForwardMessageId()).findFirst();
+ try {
+ Message forwarded = (Message) PacketParserUtils.parseStanza(forwardedMessage.getOriginalStanza());
+ message.addExtension(new Forwarded(new DelayInformation(new Date(forwardedMessage.getTimestamp())), forwarded));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ message.addExtension(new ForwardComment(text));
+
} else if (text != null) {
message = createMessagePacket(text, messageItem.getStanzaId());
}
@@ -618,6 +681,9 @@ public void execute(Realm realm) {
if (message == null) {
messageItem.setError(true);
messageItem.setErrorDescription("Internal error: message is null");
+ } else {
+ message.setFrom(account.getFullJid());
+ messageItem.setOriginalStanza(message.toXML().toString());
}
if (delayTimestamp != null) {
@@ -736,4 +802,22 @@ public void saveLastPosition(int lastPosition) {
public void setLastPosition(int lastPosition) {
this.lastPosition = lastPosition;
}
+
+ public RealmList parseForwardedMessage(boolean ui, Stanza packet, String parentMessageId) {
+ List elements = packet.getExtensions(Forwarded.ELEMENT, Forwarded.NAMESPACE);
+ if (elements == null || elements.size() == 0) return null;
+
+ RealmList forwarded = new RealmList<>();
+ for (ExtensionElement element : elements) {
+ if (element instanceof Forwarded) {
+ Stanza stanza = ((Forwarded) element).getForwardedStanza();
+ if (stanza instanceof Message) {
+ forwarded.add(new ForwardId(parseInnerMessage(ui, (Message) stanza, parentMessageId)));
+ }
+ }
+ }
+ return forwarded;
+ }
+
+ protected abstract String parseInnerMessage(boolean ui, Message message, String parentMessageId);
}
\ No newline at end of file
diff --git a/xabber/src/main/java/com/xabber/android/data/message/CrowdfundingChat.java b/xabber/src/main/java/com/xabber/android/data/message/CrowdfundingChat.java
new file mode 100644
index 0000000000..9637deacba
--- /dev/null
+++ b/xabber/src/main/java/com/xabber/android/data/message/CrowdfundingChat.java
@@ -0,0 +1,98 @@
+package com.xabber.android.data.message;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import com.xabber.android.data.database.messagerealm.MessageItem;
+import com.xabber.android.data.database.realm.CrowdfundingMessage;
+import com.xabber.android.data.entity.AccountJid;
+import com.xabber.android.data.entity.UserJid;
+
+import org.jivesoftware.smack.packet.Message;
+import org.jxmpp.jid.Jid;
+import org.jxmpp.stringprep.XmppStringprepException;
+
+import java.util.Date;
+
+public class CrowdfundingChat extends AbstractChat {
+
+ public final static String ACCOUNT = "user@xabber.com/something";
+ public final static String USER = "crowdfunding@xabber.com";
+
+ private CrowdfundingMessage lastMessage;
+ private int unreadCount;
+
+ public CrowdfundingChat(@NonNull AccountJid account, @NonNull UserJid user,
+ boolean isPrivateMucChat, CrowdfundingMessage lastMessage,
+ int unreadCount) {
+ super(account, user, isPrivateMucChat);
+ this.lastMessage = lastMessage;
+ this.unreadCount = unreadCount;
+ }
+
+ public static CrowdfundingChat createCrowdfundingChat(int unreadCount, CrowdfundingMessage message) {
+ AccountJid accountJid = getDefaultAccount();
+ UserJid userJid = getDefaultUser();
+ if (accountJid != null && userJid != null) {
+ CrowdfundingChat chat = new CrowdfundingChat(accountJid, userJid, false,
+ message, unreadCount);
+ return chat;
+ } else return null;
+ }
+
+ public Date getLastTime() {
+ if (lastMessage != null)
+ return new Date((long) lastMessage.getReceivedTimestamp() * 1000);
+ return new Date(0);
+ }
+
+ public int getUnreadCount() {
+ return unreadCount;
+ }
+
+ @Nullable
+ public CrowdfundingMessage getLastCrowdMessage() {
+ return lastMessage;
+ }
+
+ @Override
+ protected String parseInnerMessage(boolean ui, Message message, String parentMessageId) {
+ return null;
+ }
+
+ @NonNull
+ @Override
+ public Jid getTo() {
+ return null;
+ }
+
+ @Override
+ public Message.Type getType() {
+ return null;
+ }
+
+ @Override
+ protected MessageItem createNewMessageItem(String text) {
+ return null;
+ }
+
+ @Nullable
+ public static AccountJid getDefaultAccount() {
+ try {
+ return AccountJid.from(ACCOUNT);
+ } catch (XmppStringprepException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ @Nullable
+ public static UserJid getDefaultUser() {
+ try {
+ return UserJid.from(USER);
+ } catch (UserJid.UserJidCreateException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+}
diff --git a/xabber/src/main/java/com/xabber/android/data/message/ForwardManager.java b/xabber/src/main/java/com/xabber/android/data/message/ForwardManager.java
new file mode 100644
index 0000000000..ab4e630624
--- /dev/null
+++ b/xabber/src/main/java/com/xabber/android/data/message/ForwardManager.java
@@ -0,0 +1,43 @@
+package com.xabber.android.data.message;
+
+import com.xabber.android.data.database.messagerealm.ForwardId;
+import com.xabber.android.data.database.messagerealm.MessageItem;
+import com.xabber.android.data.entity.AccountJid;
+import com.xabber.android.data.entity.UserJid;
+import com.xabber.android.data.extension.forward.ForwardComment;
+
+import org.greenrobot.eventbus.EventBus;
+import org.jivesoftware.smack.packet.ExtensionElement;
+import org.jivesoftware.smack.packet.Stanza;
+
+import java.util.List;
+
+import io.realm.RealmList;
+
+public class ForwardManager {
+
+ public static void forwardMessage(List messages, AccountJid account, UserJid user, String text) {
+ AbstractChat chat = MessageManager.getInstance().getOrCreateChat(account, user);
+ MessageItem messageItem = chat.createNewMessageItem(text);
+
+ RealmList ids = new RealmList<>();
+
+ for (String message : messages) {
+ ids.add(new ForwardId(message));
+ }
+
+ messageItem.setForwardedIds(ids);
+ chat.saveMessageItem(true, messageItem);
+ chat.sendMessages();
+ EventBus.getDefault().post(new NewMessageEvent());
+ }
+
+ public static String parseForwardComment(Stanza packet) {
+ ExtensionElement comment = packet.getExtension(ForwardComment.ELEMENT, ForwardComment.NAMESPACE);
+ if (comment instanceof ForwardComment) {
+ return ((ForwardComment) comment).getComment();
+ }
+ return null;
+ }
+
+}
diff --git a/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java b/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java
index 6607135b10..ea07a046d4 100644
--- a/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java
+++ b/xabber/src/main/java/com/xabber/android/data/message/MessageManager.java
@@ -597,6 +597,29 @@ public void run() {
});
}
+ /**
+ * Removes message from history.
+ *
+ */
+ public void removeMessage(final List messageIDs) {
+ final String[] ids = messageIDs.toArray(new String[0]);
+ Application.getInstance().runInBackgroundUserRequest(new Runnable() {
+ @Override
+ public void run() {
+ Realm realm = MessageDatabaseManager.getInstance().getNewBackgroundRealm();
+ RealmResults items = realm.where(MessageItem.class)
+ .in(MessageItem.Fields.UNIQUE_ID, ids).findAll();
+
+ if (items != null && !items.isEmpty()) {
+ realm.beginTransaction();
+ items.deleteAllFromRealm();
+ realm.commitTransaction();
+ }
+ realm.close();
+ }
+ });
+ }
+
/**
* Called on action settings change.
diff --git a/xabber/src/main/java/com/xabber/android/data/message/ReceiptManager.java b/xabber/src/main/java/com/xabber/android/data/message/ReceiptManager.java
index 84f23a231f..803c95f1fb 100644
--- a/xabber/src/main/java/com/xabber/android/data/message/ReceiptManager.java
+++ b/xabber/src/main/java/com/xabber/android/data/message/ReceiptManager.java
@@ -24,7 +24,6 @@
import com.xabber.android.data.database.messagerealm.MessageItem;
import com.xabber.android.data.entity.AccountJid;
import com.xabber.android.data.log.LogManager;
-import com.xabber.android.ui.adapter.ChatMessageAdapter;
import org.greenrobot.eventbus.EventBus;
import org.jivesoftware.smack.ConnectionCreationListener;
diff --git a/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java b/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java
index d528aa03c1..c9f608588f 100644
--- a/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java
+++ b/xabber/src/main/java/com/xabber/android/data/message/RegularChat.java
@@ -21,6 +21,7 @@
import com.xabber.android.data.NetworkException;
import com.xabber.android.data.SettingsManager;
import com.xabber.android.data.database.messagerealm.Attachment;
+import com.xabber.android.data.database.messagerealm.ForwardId;
import com.xabber.android.data.database.messagerealm.MessageItem;
import com.xabber.android.data.entity.AccountJid;
import com.xabber.android.data.entity.UserJid;
@@ -142,7 +143,9 @@ protected String prepareText(String text) {
@Override
protected MessageItem createNewMessageItem(String text) {
return createMessageItem(null, text, null, null, false,
- false, false, false, UUID.randomUUID().toString(), null);
+ false, false, false, UUID.randomUUID().toString(),
+ null, null, null,
+ account.getFullJid().toString(), null, false);
}
@Override
@@ -204,28 +207,80 @@ protected boolean onPacket(UserJid bareAddress, Stanza packet, boolean isCarbons
}
}
+ RealmList attachments = HttpFileUploadManager.parseFileMessage(packet);
+
+ String uid = UUID.randomUUID().toString();
+ RealmList forwardIds = parseForwardedMessage(true, packet, uid);
+ String originalStanza = packet.toXML().toString();
+ String originalFrom = packet.getFrom().toString();
+ String forwardComment = ForwardManager.parseForwardComment(packet);
+ if (forwardComment != null) text = forwardComment;
+
// System message received.
- if (text == null || text.trim().equals(""))
+ if ((text == null || text.trim().equals("")) && (forwardIds == null || forwardIds.isEmpty()))
return true;
- RealmList attachments = HttpFileUploadManager.parseFileMessage(packet);
-
// create message with file-attachments
if (attachments.size() > 0)
- createAndSaveFileMessage(resource, text, null, getDelayStamp(message), true,
- true, encrypted, isOfflineMessage(account.getFullJid().getDomain(), packet),
- packet.getStanzaId(), attachments);
+ createAndSaveFileMessage(true, uid, resource, text, null, getDelayStamp(message),
+ true, true, encrypted,
+ isOfflineMessage(account.getFullJid().getDomain(), packet),
+ packet.getStanzaId(), attachments, originalStanza, null,
+ originalFrom, false, false);
// create message without attachments
- else createAndSaveNewMessage(resource, text, null, getDelayStamp(message), true,
- true, encrypted, isOfflineMessage(account.getFullJid().getDomain(), packet),
- packet.getStanzaId());
+ else createAndSaveNewMessage(true, uid, resource, text, null, getDelayStamp(message),
+ true, true, encrypted,
+ isOfflineMessage(account.getFullJid().getDomain(), packet),
+ packet.getStanzaId(), originalStanza, null,
+ originalFrom, forwardIds,false, false);
EventBus.getDefault().post(new NewIncomingMessageEvent(account, user));
}
return true;
}
+ @Override
+ protected String parseInnerMessage(boolean ui, Message message, String parentMessageId) {
+ if (message.getType() == Message.Type.error) return null;
+
+ MUCUser mucUser = MUCUser.from(message);
+ if (mucUser != null && mucUser.getInvite() != null) return null;
+
+ final Jid fromJid = message.getFrom();
+ Resourcepart resource = null;
+ if (fromJid != null) resource = fromJid.getResourceOrNull();
+ String text = message.getBody();
+ if (text == null) return null;
+
+ boolean encrypted = OTRManager.getInstance().isEncrypted(text);
+
+ RealmList attachments = HttpFileUploadManager.parseFileMessage(message);
+
+ String uid = UUID.randomUUID().toString();
+ RealmList forwardIds = parseForwardedMessage(ui, message, uid);
+ String originalStanza = message.toXML().toString();
+ String originalFrom = "";
+ if (fromJid != null) originalFrom = fromJid.toString();
+ boolean fromMuc = message.getType().equals(Type.groupchat);
+ String forwardComment = ForwardManager.parseForwardComment(message);
+ if (forwardComment != null && !forwardComment.isEmpty())
+ text = forwardComment;
+
+ // create message with file-attachments
+ if (attachments.size() > 0)
+ createAndSaveFileMessage(ui, uid, resource, text, null, null, true,
+ false, encrypted, false, message.getStanzaId(), attachments,
+ originalStanza, parentMessageId, originalFrom, fromMuc, true);
+
+ // create message without attachments
+ else createAndSaveNewMessage(ui, uid, resource, text, null, null, true,
+ false, encrypted, false, message.getStanzaId(), originalStanza,
+ parentMessageId, originalFrom, forwardIds, fromMuc, true);
+
+ return uid;
+ }
+
/**
* @return Whether message was delayed by server.
*/
diff --git a/xabber/src/main/java/com/xabber/android/data/roster/CrowdfundingContact.java b/xabber/src/main/java/com/xabber/android/data/roster/CrowdfundingContact.java
new file mode 100644
index 0000000000..1e3d4da8d9
--- /dev/null
+++ b/xabber/src/main/java/com/xabber/android/data/roster/CrowdfundingContact.java
@@ -0,0 +1,35 @@
+package com.xabber.android.data.roster;
+
+import com.xabber.android.data.database.realm.CrowdfundingMessage;
+import com.xabber.android.data.message.CrowdfundingChat;
+
+import java.util.Date;
+
+public class CrowdfundingContact extends AbstractContact {
+
+ private String lastMessageText;
+ private Date lastMessageTime;
+ private int unreadCount;
+
+ public CrowdfundingContact(CrowdfundingChat chat) {
+ super(chat.getAccount(), chat.getUser());
+ CrowdfundingMessage lastMessage = chat.getLastCrowdMessage();
+ if (lastMessage != null) {
+ this.lastMessageText = lastMessage.getMessageForCurrentLocale();
+ this.lastMessageTime = new Date((long) lastMessage.getReceivedTimestamp() * 1000);
+ }
+ this.unreadCount = chat.getUnreadCount();
+ }
+
+ public String getLastMessageText() {
+ return lastMessageText;
+ }
+
+ public Date getLastMessageTime() {
+ return lastMessageTime;
+ }
+
+ public int getUnreadCount() {
+ return unreadCount;
+ }
+}
diff --git a/xabber/src/main/java/com/xabber/android/data/roster/PresenceComparatorByPriority.java b/xabber/src/main/java/com/xabber/android/data/roster/PresenceComparatorByPriority.java
index e0903f5a93..184651056c 100644
--- a/xabber/src/main/java/com/xabber/android/data/roster/PresenceComparatorByPriority.java
+++ b/xabber/src/main/java/com/xabber/android/data/roster/PresenceComparatorByPriority.java
@@ -11,15 +11,10 @@ class PresenceComparatorByPriority implements Comparator {
public int compare(Presence presence1, Presence presence2) {
int priority1 = presence1.getPriority();
int priority2 = presence2.getPriority();
-
- if (priority1 == Integer.MIN_VALUE) {
+ if (priority1 > priority2) {
return 1;
- }
-
- if (priority2 == Integer.MIN_VALUE) {
+ } else if (priority2 > priority1) {
return -1;
- }
-
- return priority2 - priority1;
+ } else return 0;
}
}
diff --git a/xabber/src/main/java/com/xabber/android/data/roster/RosterManager.java b/xabber/src/main/java/com/xabber/android/data/roster/RosterManager.java
index bbfdc065d1..5699c59732 100644
--- a/xabber/src/main/java/com/xabber/android/data/roster/RosterManager.java
+++ b/xabber/src/main/java/com/xabber/android/data/roster/RosterManager.java
@@ -28,6 +28,7 @@
import com.xabber.android.data.connection.ConnectionItem;
import com.xabber.android.data.connection.StanzaSender;
import com.xabber.android.data.connection.listeners.OnDisconnectListener;
+import com.xabber.android.data.database.messagerealm.MessageItem;
import com.xabber.android.data.entity.AccountJid;
import com.xabber.android.data.entity.NestedMap;
import com.xabber.android.data.entity.UserJid;
@@ -269,6 +270,17 @@ public String getName(AccountJid account, UserJid user) {
return contact.getName();
}
+ /**
+ * @return Contact's name or BareJid if that contacts not exist.
+ */
+ public String getNameOrBareJid(AccountJid account, UserJid user) {
+ RosterContact contact = getRosterContact(account, user);
+ if (contact == null) {
+ return user.getBareJid().toString();
+ }
+ return contact.getName();
+ }
+
/**
* @return Contact's groups.
*/
@@ -612,4 +624,21 @@ public void run() {
}
});
}
+
+ public static String getDisplayAuthorName(MessageItem messageItem) {
+ UserJid jid = null;
+ try {
+ jid = UserJid.from(messageItem.getOriginalFrom());
+ } catch (UserJid.UserJidCreateException e) {
+ e.printStackTrace();
+ }
+
+ String author = null;
+ if (jid != null) {
+ if (messageItem.isFromMUC()) author = jid.getJid().getResourceOrEmpty().toString();
+ else author = RosterManager.getInstance().getNameOrBareJid(messageItem.getAccount(), jid);
+ }
+
+ return author;
+ }
}
diff --git a/xabber/src/main/java/com/xabber/android/data/xaccount/AuthManager.java b/xabber/src/main/java/com/xabber/android/data/xaccount/AuthManager.java
index fed3231c25..04541808f9 100644
--- a/xabber/src/main/java/com/xabber/android/data/xaccount/AuthManager.java
+++ b/xabber/src/main/java/com/xabber/android/data/xaccount/AuthManager.java
@@ -245,7 +245,7 @@ public static Single deleteEmail(int emailId) {
// API v2
public static Single requestXMPPCode(String jid) {
- return HttpApiManager.getXabberApi().requestXMPPCode(new Jid(jid));
+ return HttpApiManager.getXabberApi().requestXMPPCode(new XMPPCodeRequest(jid, "iq"));
}
public static Single confirmXMPP(final String jid, String code) {
@@ -488,6 +488,16 @@ public String getApiJid() {
}
}
+ public static class XMPPCodeRequest {
+ final String jid;
+ final String type;
+
+ public XMPPCodeRequest(String jid, String type) {
+ this.jid = jid;
+ this.type = type;
+ }
+ }
+
public static class Account {
final String first_name;
final String last_name;
diff --git a/xabber/src/main/java/com/xabber/android/data/xaccount/HttpApiManager.java b/xabber/src/main/java/com/xabber/android/data/xaccount/HttpApiManager.java
index b52f991fe1..e3522e1666 100644
--- a/xabber/src/main/java/com/xabber/android/data/xaccount/HttpApiManager.java
+++ b/xabber/src/main/java/com/xabber/android/data/xaccount/HttpApiManager.java
@@ -3,6 +3,8 @@
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.xabber.android.BuildConfig;
+import com.xabber.android.data.SettingsManager;
+import com.xabber.android.data.http.ICrowdfundingApi;
import com.xabber.android.data.http.IXabberCom;
import okhttp3.OkHttpClient;
@@ -18,14 +20,22 @@
public class HttpApiManager {
public static final String XABBER_FORGOT_PASS_URL = "https://www.xabber.com/account/auth/forgot-password/";
- public static final String XABBER_EMAIL_CONFIRM_URL = "https://www.xabber.com/account/emails/confirmation/";
+ private static final String XABBER_EMAIL_CONFIRM_URL = "https://www.xabber.com/account/emails/confirmation/";
+ private static final String XABBER_DEV_EMAIL_CONFIRM_URL = "http://dev.xabber.com/account/emails/confirmation/";
public static final String XABBER_API_URL = "https://api.xabber.com/api/v2/";
+ public static final String XABBER_DEV_API_URL = "https://api.dev.xabber.com/api/v2/";
private static final String XABBER_COM_URL = "https://www.xabber.com/";
+ private static final String CROWDFUNDING_URL = "https://crowdfunding.xabber.com/api/v1/";
+ private static final String CROWDFUNDING_DEV_URL = "https://crowdfunding.dev.xabber.com/api/v1/";
+
private static IXabberApi xabberApi;
private static IXabberCom xabberCom;
+ private static ICrowdfundingApi crowdfundingApi;
+
private static Retrofit retrofit;
private static Retrofit retrofitXabberCom;
+ private static Retrofit retrofitCrowdfunding;
public static IXabberApi getXabberApi() {
if (xabberApi == null)
@@ -39,6 +49,12 @@ public static IXabberCom getXabberCom() {
return xabberCom;
}
+ public static ICrowdfundingApi getCrowdfundingApi() {
+ if (crowdfundingApi == null)
+ crowdfundingApi = getCrowdfundingRetrofit().create(ICrowdfundingApi.class);
+ return crowdfundingApi;
+ }
+
public static Retrofit getRetrofit() {
if (retrofit == null) {
@@ -59,7 +75,7 @@ public static Retrofit getRetrofit() {
.create();
retrofit = new Retrofit.Builder()
- .baseUrl(XABBER_API_URL)
+ .baseUrl(SettingsManager.useDevelopAPI() ? XABBER_DEV_API_URL : XABBER_API_URL)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.client(httpClient)
@@ -95,5 +111,37 @@ public static Retrofit getRetrofitXabberCom() {
}
return retrofitXabberCom;
}
+
+ public static String getXabberEmailConfirmUrl() {
+ return SettingsManager.useDevelopAPI() ? XABBER_DEV_EMAIL_CONFIRM_URL : XABBER_EMAIL_CONFIRM_URL;
+ }
+
+ private static Retrofit getCrowdfundingRetrofit() {
+ if (retrofitCrowdfunding == null) {
+
+ HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
+ loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
+
+ OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
+
+ // if debug enable http logging
+ if (BuildConfig.DEBUG)
+ httpClientBuilder.addInterceptor(loggingInterceptor);
+
+ OkHttpClient httpClient = httpClientBuilder.build();
+
+ Gson gson = new GsonBuilder()
+ .setLenient()
+ .create();
+
+ retrofitCrowdfunding = new Retrofit.Builder()
+ .baseUrl(SettingsManager.useDevelopAPI() ? CROWDFUNDING_DEV_URL : CROWDFUNDING_URL)
+ .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
+ .addConverterFactory(GsonConverterFactory.create(gson))
+ .client(httpClient)
+ .build();
+ }
+ return retrofitCrowdfunding;
+ }
}
diff --git a/xabber/src/main/java/com/xabber/android/data/xaccount/HttpConfirmIq.java b/xabber/src/main/java/com/xabber/android/data/xaccount/HttpConfirmIq.java
new file mode 100644
index 0000000000..beb9ea9771
--- /dev/null
+++ b/xabber/src/main/java/com/xabber/android/data/xaccount/HttpConfirmIq.java
@@ -0,0 +1,49 @@
+package com.xabber.android.data.xaccount;
+
+import org.jivesoftware.smack.packet.IQ;
+
+public class HttpConfirmIq extends IQ {
+
+ public static final String NAMESPACE = "http://jabber.org/protocol/http-auth";
+ public static final String ELEMENT = "confirm";
+ public static final String PROP_ID = "id";
+ public static final String PROP_URL = "url";
+ public static final String PROP_METHOD = "method";
+
+ private String id;
+ private String method;
+ protected String url;
+
+ public HttpConfirmIq() {
+ super(ELEMENT, NAMESPACE);
+ }
+
+ @Override
+ protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
+ return null;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getMethod() {
+ return method;
+ }
+
+ public void setMethod(String method) {
+ this.method = method;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+}
diff --git a/xabber/src/main/java/com/xabber/android/data/xaccount/HttpConfirmIqProvider.java b/xabber/src/main/java/com/xabber/android/data/xaccount/HttpConfirmIqProvider.java
new file mode 100644
index 0000000000..47a5babbe8
--- /dev/null
+++ b/xabber/src/main/java/com/xabber/android/data/xaccount/HttpConfirmIqProvider.java
@@ -0,0 +1,43 @@
+package com.xabber.android.data.xaccount;
+
+import android.util.Log;
+
+import org.jivesoftware.smack.provider.IQProvider;
+import org.xmlpull.v1.XmlPullParser;
+
+public class HttpConfirmIqProvider extends IQProvider {
+
+ @Override
+ public HttpConfirmIq parse(XmlPullParser parser, int initialDepth) throws Exception {
+ HttpConfirmIq httpConfirmIq = new HttpConfirmIq();
+
+ outerloop: while (true) {
+ int eventType = parser.getEventType();
+ switch (eventType) {
+ case XmlPullParser.START_TAG:
+ if (parser.getEventType() == XmlPullParser.START_TAG
+ && HttpConfirmIq.ELEMENT.equals(parser.getName())
+ && HttpConfirmIq.NAMESPACE.equals(parser.getNamespace())) {
+ try {
+ httpConfirmIq.setUrl(parser.getAttributeValue("", HttpConfirmIq.PROP_URL));
+ httpConfirmIq.setId(parser.getAttributeValue("", HttpConfirmIq.PROP_ID));
+ httpConfirmIq.setMethod(parser.getAttributeValue("", HttpConfirmIq.PROP_METHOD));
+ break outerloop;
+ } catch (Exception e) {
+ Log.d("HttpConfirmIqProvider", "error in parsing: " + e.toString());
+ break outerloop;
+ }
+ } else parser.next();
+ break;
+ case XmlPullParser.END_TAG:
+ if (parser.getDepth() == initialDepth) {
+ break outerloop;
+ }
+ break;
+ default:
+ parser.next();
+ }
+ }
+ return httpConfirmIq;
+ }
+}
diff --git a/xabber/src/main/java/com/xabber/android/data/xaccount/IXabberApi.java b/xabber/src/main/java/com/xabber/android/data/xaccount/IXabberApi.java
index f3b38429e9..610aadaf55 100644
--- a/xabber/src/main/java/com/xabber/android/data/xaccount/IXabberApi.java
+++ b/xabber/src/main/java/com/xabber/android/data/xaccount/IXabberApi.java
@@ -74,7 +74,7 @@ public interface IXabberApi {
/* Xabber API v2 */
@POST("accounts/xmpp_code_request/")
- Single requestXMPPCode(@Body AuthManager.Jid jid);
+ Single requestXMPPCode(@Body AuthManager.XMPPCodeRequest request);
@POST("accounts/xmpp_auth/")
Single confirmXMPP(@Body AuthManager.CodeConfirm codeConfirm);
diff --git a/xabber/src/main/java/com/xabber/android/data/xaccount/XMPPAuthManager.java b/xabber/src/main/java/com/xabber/android/data/xaccount/XMPPAuthManager.java
index eb88a5e973..cccaa4f962 100644
--- a/xabber/src/main/java/com/xabber/android/data/xaccount/XMPPAuthManager.java
+++ b/xabber/src/main/java/com/xabber/android/data/xaccount/XMPPAuthManager.java
@@ -4,7 +4,6 @@
import com.xabber.android.data.Application;
import com.xabber.android.data.NetworkException;
-import com.xabber.android.data.SettingsManager;
import com.xabber.android.data.account.AccountItem;
import com.xabber.android.data.account.AccountManager;
import com.xabber.android.data.connection.ConnectionItem;
@@ -19,8 +18,6 @@
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smack.packet.Message;
-import org.jivesoftware.smack.packet.StandardExtensionElement;
import org.jivesoftware.smack.packet.Stanza;
import org.jxmpp.stringprep.XmppStringprepException;
@@ -36,8 +33,7 @@
public class XMPPAuthManager implements OnPacketListener, OnConnectedListener {
private static final String LOG_TAG = XMPPAuthManager.class.getSimpleName();
- private static final String EXTENSION_NAMESPACE = "http://jabber.org/protocol/http-auth";
- private static final String ATTRIBUTE_ID = "id";
+ private static final String URL_AUTH = "https://www.xabber.com/account/auth/login/";
private static XMPPAuthManager instance;
@@ -62,17 +58,13 @@ public boolean isXabberServiceMessage(String stanzaId) {
@Override
public void onStanza(ConnectionItem connection, Stanza packet) {
- if (packet instanceof Message && ((Message) packet).getType() == Message.Type.headline) {
- Message message = (Message) packet;
+ if (packet instanceof HttpConfirmIq && URL_AUTH.equals(((HttpConfirmIq) packet).getUrl())) {
+ HttpConfirmIq httpConfirmIq = (HttpConfirmIq) packet;
- String apiJid = message.getFrom().toString();
- String clientJid = message.getTo().toString();
- String requestId = message.getStanzaId();
- String code = null;
-
- StandardExtensionElement extensionElement = (StandardExtensionElement)
- message.getExtension(EXTENSION_NAMESPACE);
- if (extensionElement != null) code = extensionElement.getAttributeValue(ATTRIBUTE_ID);
+ String apiJid = packet.getFrom().toString();
+ String clientJid = packet.getTo().toString();
+ String requestId = packet.getStanzaId();
+ String code = httpConfirmIq.getId();
if (requestId != null && code != null)
onRequestReceived(new Request(requestId, clientJid, apiJid, code));
diff --git a/xabber/src/main/java/com/xabber/android/data/xaccount/XabberAccountManager.java b/xabber/src/main/java/com/xabber/android/data/xaccount/XabberAccountManager.java
index 6094a57da6..fde7aff50a 100644
--- a/xabber/src/main/java/com/xabber/android/data/xaccount/XabberAccountManager.java
+++ b/xabber/src/main/java/com/xabber/android/data/xaccount/XabberAccountManager.java
@@ -66,6 +66,7 @@ public class XabberAccountManager implements OnLoadListener {
private int lastOrderChangeTimestamp;
private CompositeSubscription compositeSubscription = new CompositeSubscription();
+ private CompositeSubscription updateSettingsSubscriptions = new CompositeSubscription();
public static XabberAccountManager getInstance() {
if (instance == null)
@@ -240,28 +241,33 @@ public void updateAccountInfo() {
public void updateAccountSettings() {
List list = createSettingsList();
if (list != null && list.size() > 0) {
- Subscription updateSettingsSubscription = AuthManager.patchClientSettings(list)
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(new Action1>() {
- @Override
- public void call(List s) {
- Log.d(LOG_TAG, "XMPP accounts loading from net: successfully");
- }
- }, new Action1() {
- @Override
- public void call(Throwable throwable) {
- Log.d(LOG_TAG, "XMPP accounts loading from net: error: " + throwable.toString());
-
- // invalid token
- String message = RetrofitErrorConverter.throwableToHttpError(throwable);
- if (message != null && message.equals("Invalid token")) {
- // logout from deleted account
- onInvalidToken();
+ // prevents simultaneous calls
+ if (!updateSettingsSubscriptions.hasSubscriptions()) {
+ Subscription updateSettingsSubscription = AuthManager.patchClientSettings(list)
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(new Action1>() {
+ @Override
+ public void call(List s) {
+ Log.d(LOG_TAG, "XMPP accounts loading from net: successfully");
+ updateSettingsSubscriptions.clear();
}
- }
- });
- compositeSubscription.add(updateSettingsSubscription);
+ }, new Action1() {
+ @Override
+ public void call(Throwable throwable) {
+ Log.d(LOG_TAG, "XMPP accounts loading from net: error: " + throwable.toString());
+
+ // invalid token
+ String message = RetrofitErrorConverter.throwableToHttpError(throwable);
+ if (message != null && message.equals("Invalid token")) {
+ // logout from deleted account
+ onInvalidToken();
+ }
+ updateSettingsSubscriptions.clear();
+ }
+ });
+ updateSettingsSubscriptions.add(updateSettingsSubscription);
+ }
}
}
@@ -516,7 +522,9 @@ public void updateLocalAccount(XMPPAccountSettings account) {
} else if (accountJid != null && !account.isDeleted()) {
AccountManager.getInstance().setOrder(accountJid, account.getOrder());
AccountManager.getInstance().setTimestamp(accountJid, account.getTimestamp());
- AccountManager.getInstance().setColor(accountJid, ColorManager.getInstance().convertColorNameToIndex(account.getColor()));
+ if (account.getColor() != null)
+ AccountManager.getInstance().setColor(accountJid,
+ ColorManager.getInstance().convertColorNameToIndex(account.getColor()));
AccountManager.getInstance().onAccountChanged(accountJid);
// delete existing account
diff --git a/xabber/src/main/java/com/xabber/android/presentation/mvp/contactlist/ContactListPresenter.java b/xabber/src/main/java/com/xabber/android/presentation/mvp/contactlist/ContactListPresenter.java
index 46c19459a6..d831703b19 100644
--- a/xabber/src/main/java/com/xabber/android/presentation/mvp/contactlist/ContactListPresenter.java
+++ b/xabber/src/main/java/com/xabber/android/presentation/mvp/contactlist/ContactListPresenter.java
@@ -1,6 +1,5 @@
package com.xabber.android.presentation.mvp.contactlist;
-import android.text.TextUtils;
import android.view.ContextMenu;
import android.view.View;
@@ -12,17 +11,21 @@
import com.xabber.android.data.account.CommonState;
import com.xabber.android.data.account.listeners.OnAccountChangedListener;
import com.xabber.android.data.database.messagerealm.MessageItem;
+import com.xabber.android.data.database.realm.CrowdfundingMessage;
import com.xabber.android.data.entity.AccountJid;
import com.xabber.android.data.entity.UserJid;
import com.xabber.android.data.extension.blocking.BlockingManager;
import com.xabber.android.data.extension.muc.MUCManager;
import com.xabber.android.data.extension.muc.RoomChat;
import com.xabber.android.data.extension.muc.RoomContact;
+import com.xabber.android.data.http.CrowdfundingManager;
import com.xabber.android.data.message.AbstractChat;
import com.xabber.android.data.message.ChatContact;
+import com.xabber.android.data.message.CrowdfundingChat;
import com.xabber.android.data.message.MessageManager;
import com.xabber.android.data.message.NewMessageEvent;
import com.xabber.android.data.roster.AbstractContact;
+import com.xabber.android.data.roster.CrowdfundingContact;
import com.xabber.android.data.roster.GroupManager;
import com.xabber.android.data.roster.OnContactChangedListener;
import com.xabber.android.data.roster.RosterContact;
@@ -36,6 +39,7 @@
import com.xabber.android.presentation.ui.contactlist.viewobjects.ChatVO;
import com.xabber.android.presentation.ui.contactlist.viewobjects.ChatWithButtonVO;
import com.xabber.android.presentation.ui.contactlist.viewobjects.ContactVO;
+import com.xabber.android.presentation.ui.contactlist.viewobjects.CrowdfundingChatVO;
import com.xabber.android.presentation.ui.contactlist.viewobjects.ExtContactVO;
import com.xabber.android.presentation.ui.contactlist.viewobjects.GroupVO;
import com.xabber.android.presentation.ui.contactlist.viewobjects.ToolbarVO;
@@ -47,6 +51,7 @@
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
+import org.jxmpp.stringprep.XmppStringprepException;
import java.util.ArrayList;
import java.util.Collection;
@@ -119,6 +124,13 @@ public void onItemClick(IFlexible item) {
} else if (item instanceof ButtonVO) {
ButtonVO button = (ButtonVO) item;
if (view != null) view.onButtonItemClick(button);
+ } else if (item instanceof CrowdfundingChatVO) {
+ if (view != null) {
+ AccountJid accountJid = CrowdfundingChat.getDefaultAccount();
+ UserJid userJid = CrowdfundingChat.getDefaultUser();
+ if (accountJid != null && userJid != null)
+ view.onContactClick(RosterManager.getInstance().getAbstractContact(accountJid, userJid));
+ }
}
}
@@ -364,6 +376,11 @@ public void update() {
// Remove empty groups, sort and apply structure.
items.clear();
items.add(new ToolbarVO(Application.getInstance().getApplicationContext(), this, currentChatsState));
+
+ // set hasVisibleContacts as true if have crowdfunding message
+ CrowdfundingMessage message = CrowdfundingManager.getInstance().getLastNotDelayedMessageFromRealm();
+ if (message != null) hasVisibleContacts = true;
+
if (hasVisibleContacts) {
if (currentChatsState == ChatListState.recent) {
@@ -371,7 +388,9 @@ public void update() {
// add recent chats
int i = 0;
for (AbstractContact contact : chatsGroup.getAbstractContacts()) {
- if (i == MAX_RECENT_ITEMS - 1) {
+ if (contact instanceof CrowdfundingContact) {
+ items.add(CrowdfundingChatVO.convert((CrowdfundingContact) contact));
+ } else if (i == MAX_RECENT_ITEMS - 1) {
if (getAllChatsSize() > MAX_RECENT_ITEMS)
items.add(ChatWithButtonVO.convert(contact, this));
else items.add(ChatVO.convert(contact, this, null));
@@ -380,14 +399,7 @@ public void update() {
}
if (showAccounts) {
- //boolean isFirst = items.isEmpty();
for (AccountConfiguration rosterAccount : accounts.values()) {
-// if (isFirst) {
-// isFirst = false;
-// } else {
-// items.add(new TopAccountSeparatorVO());
-// }
-
if (rosterAccount.getTotal() != 0) {
if (showGroups) {
createContactListWithAccountsAndGroups(items, rosterAccount, showEmptyGroups, comparator);
@@ -409,8 +421,13 @@ public void update() {
createContactList(items, contacts, comparator);
}
}
- } else
- items.addAll(ChatVO.convert(chatsGroup.getAbstractContacts(), this, null));
+ } else {
+ for (AbstractContact contact : chatsGroup.getAbstractContacts()) {
+ if (contact instanceof CrowdfundingContact)
+ items.add(CrowdfundingChatVO.convert((CrowdfundingContact) contact));
+ else items.add(ChatVO.convert(contact, this, null));
+ }
+ }
}
} else { // Search
final ArrayList baseEntities = getSearchResults(rosterContacts, comparator, abstractChats);
@@ -452,7 +469,7 @@ private GroupConfiguration getChatsGroup(Collection chats, ChatLis
for (AbstractChat abstractChat : chats) {
MessageItem lastMessage = abstractChat.getLastMessage();
- if (lastMessage != null && !TextUtils.isEmpty(lastMessage.getText())) {
+ if (lastMessage != null) {
AccountItem accountItem = AccountManager.getInstance().getAccount(abstractChat.getAccount());
if (accountItem != null && accountItem.isEnabled()) {
int unread = abstractChat.getUnreadMessageCount();
@@ -473,16 +490,36 @@ private GroupConfiguration getChatsGroup(Collection chats, ChatLis
}
}
}
- EventBus.getDefault().post(new UpdateUnreadCountEvent(unreadMessageCount));
- Collections.sort(newChats, ChatComparator.CHAT_COMPARATOR);
+ // crowdfunding chat
+ int unreadCount = CrowdfundingManager.getInstance().getUnreadMessageCount();
+ CrowdfundingMessage message = CrowdfundingManager.getInstance().getLastNotDelayedMessageFromRealm();
+ if (message != null) {
+ switch (state) {
+ case unread:
+ if (unreadCount > 0) newChats.add(CrowdfundingChat.createCrowdfundingChat(unreadCount, message));
+ break;
+ case archived:
+ break;
+ default:
+ // recent
+ newChats.add(CrowdfundingChat.createCrowdfundingChat(unreadCount, message));
+ break;
+ }
+ }
+ unreadMessageCount += unreadCount;
+
+ EventBus.getDefault().post(new UpdateUnreadCountEvent(unreadMessageCount));
+ Collections.sort(newChats, ChatComparator.CHAT_COMPARATOR);
chatsGroup.setNotEmpty();
int itemsCount = 0;
for (AbstractChat chat : newChats) {
if (itemsCount < MAX_RECENT_ITEMS || state != ChatListState.recent) {
- chatsGroup.addAbstractContact(RosterManager.getInstance()
+ if (chat instanceof CrowdfundingChat)
+ chatsGroup.addAbstractContact(new CrowdfundingContact((CrowdfundingChat) chat));
+ else chatsGroup.addAbstractContact(RosterManager.getInstance()
.getBestContact(chat.getAccount(), chat.getUser()));
chatsGroup.increment(true);
itemsCount++;
diff --git a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/ContactListFragment.java b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/ContactListFragment.java
index 569a174eb2..d9603df4fa 100644
--- a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/ContactListFragment.java
+++ b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/ContactListFragment.java
@@ -20,6 +20,7 @@
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;
+import android.widget.ImageView;
import android.widget.TextView;
import com.xabber.android.R;
@@ -52,6 +53,7 @@
import com.xabber.android.ui.activity.ContactListActivity;
import com.xabber.android.ui.activity.StatusEditActivity;
import com.xabber.android.ui.adapter.contactlist.ContactListState;
+import com.xabber.android.ui.color.ColorManager;
import com.xabber.android.ui.helper.ContextMenuHelper;
import java.util.ArrayList;
@@ -83,6 +85,7 @@ public class ContactListFragment extends Fragment implements ContactListView,
private LinearLayoutManager linearLayoutManager;
private View placeholderView;
private TextView tvPlaceholderMessage;
+ private ImageView placeholderImage;
/**
* View with information shown on empty contact list.
*/
@@ -96,7 +99,7 @@ public class ContactListFragment extends Fragment implements ContactListView,
/**
* Image view with disconnected icon.
*/
- private View disconnectedView;
+ private ImageView disconnectedView;
/**
* View with help text.
@@ -163,10 +166,13 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
coordinatorLayout = (CoordinatorLayout) view.findViewById(R.id.coordinatorLayout);
placeholderView = view.findViewById(R.id.placeholderView);
tvPlaceholderMessage = (TextView) view.findViewById(R.id.tvPlaceholderMessage);
+ placeholderImage = view.findViewById(R.id.placeholderImage);
+ ColorManager.setGrayScaleFilter(placeholderImage);
infoView = view.findViewById(R.id.info);
connectedView = infoView.findViewById(R.id.connected);
disconnectedView = infoView.findViewById(R.id.disconnected);
+ ColorManager.setGrayScaleFilter(disconnectedView);
textView = (TextView) infoView.findViewById(R.id.text);
buttonView = (Button) infoView.findViewById(R.id.button);
animation = AnimationUtils.loadAnimation(getActivity(), R.anim.connection);
diff --git a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ChatVO.java b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ChatVO.java
index 51cdec4611..e42015ce8a 100644
--- a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ChatVO.java
+++ b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ChatVO.java
@@ -41,12 +41,12 @@ public ChatVO(int accountColorIndicator, int accountColorIndicatorBack, boolean
boolean mute, NotificationState.NotificationMode notificationMode, String messageText,
boolean isOutgoing, Date time, int messageStatus, String messageOwner,
boolean archived, String lastActivity, ContactClickListener listener,
- @Nullable IsCurrentChatListener currentChatListener) {
+ @Nullable IsCurrentChatListener currentChatListener, int forwardedCount) {
super(accountColorIndicator, accountColorIndicatorBack, showOfflineShadow, name, status,
statusId, statusLevel, avatar, mucIndicatorLevel, userJid, accountJid,
unreadCount, mute, notificationMode, messageText, isOutgoing, time, messageStatus,
- messageOwner, archived, lastActivity, listener);
+ messageOwner, archived, lastActivity, listener, forwardedCount);
this.currentChatListener = currentChatListener;
}
@@ -63,7 +63,7 @@ public static ChatVO convert(AbstractContact contact, ContactClickListener liste
contactVO.isMute(), contactVO.getNotificationMode(), contactVO.getMessageText(),
contactVO.isOutgoing(), contactVO.getTime(), contactVO.getMessageStatus(),
contactVO.getMessageOwner(), contactVO.isArchived(), contactVO.getLastActivity(),
- contactVO.listener, currentChatListener);
+ contactVO.listener, currentChatListener, contactVO.forwardedCount);
}
public static ArrayList convert(Collection contacts,
diff --git a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ChatWithButtonVO.java b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ChatWithButtonVO.java
index 9bc50c8c2d..12ac94d1ee 100644
--- a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ChatWithButtonVO.java
+++ b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ChatWithButtonVO.java
@@ -22,12 +22,12 @@ public ChatWithButtonVO(int accountColorIndicator, int accountColorIndicatorBack
int mucIndicatorLevel, UserJid userJid, AccountJid accountJid, int unreadCount,
boolean mute, NotificationState.NotificationMode notificationMode, String messageText,
boolean isOutgoing, Date time, int messageStatus, String messageOwner,
- boolean archived, String lastActivity, ContactClickListener listener) {
+ boolean archived, String lastActivity, ContactClickListener listener, int forwardedCount) {
super(accountColorIndicator, accountColorIndicatorBack, showOfflineShadow, name, status,
statusId, statusLevel, avatar, mucIndicatorLevel, userJid, accountJid,
unreadCount, mute, notificationMode, messageText, isOutgoing, time, messageStatus,
- messageOwner, archived, lastActivity, listener);
+ messageOwner, archived, lastActivity, listener, forwardedCount);
}
public static ChatWithButtonVO convert(AbstractContact contact, ContactClickListener listener) {
@@ -41,7 +41,7 @@ public static ChatWithButtonVO convert(AbstractContact contact, ContactClickList
contactVO.isMute(), contactVO.getNotificationMode(), contactVO.getMessageText(),
contactVO.isOutgoing(), contactVO.getTime(), contactVO.getMessageStatus(),
contactVO.getMessageOwner(), contactVO.isArchived(), contactVO.getLastActivity(),
- contactVO.listener);
+ contactVO.listener, contactVO.forwardedCount);
}
public static ChatWithButtonVO convert(ChatVO chat) {
@@ -53,7 +53,8 @@ public static ChatWithButtonVO convert(ChatVO chat) {
chat.getUserJid(), chat.getAccountJid(), chat.getUnreadCount(),
chat.isMute(), chat.getNotificationMode(), chat.getMessageText(),
chat.isOutgoing(), chat.getTime(), chat.getMessageStatus(),
- chat.getMessageOwner(), chat.isArchived(), chat.getLastActivity(), chat.listener);
+ chat.getMessageOwner(), chat.isArchived(), chat.getLastActivity(), chat.listener,
+ chat.forwardedCount);
}
@Override
diff --git a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ContactVO.java b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ContactVO.java
index 1a6b11f60d..1b337760b4 100644
--- a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ContactVO.java
+++ b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/ContactVO.java
@@ -20,6 +20,7 @@
import android.widget.TextView;
import com.xabber.android.R;
+import com.xabber.android.data.Application;
import com.xabber.android.data.SettingsManager;
import com.xabber.android.data.account.AccountItem;
import com.xabber.android.data.account.AccountManager;
@@ -75,6 +76,7 @@ public class ContactVO extends AbstractFlexibleItem {
private final String messageOwner;
private final String lastActivity;
protected boolean archived;
+ protected int forwardedCount;
protected final ContactClickListener listener;
@@ -90,7 +92,7 @@ protected ContactVO(int accountColorIndicator, int accountColorIndicatorBack,
int mucIndicatorLevel, UserJid userJid, AccountJid accountJid, int unreadCount,
boolean mute, NotificationState.NotificationMode notificationMode, String messageText,
boolean isOutgoing, Date time, int messageStatus, String messageOwner,
- boolean archived, String lastActivity, ContactClickListener listener) {
+ boolean archived, String lastActivity, ContactClickListener listener, int forwardedCount) {
this.id = UUID.randomUUID().toString();
this.accountColorIndicator = accountColorIndicator;
this.accountColorIndicatorBack = accountColorIndicatorBack;
@@ -114,6 +116,7 @@ protected ContactVO(int accountColorIndicator, int accountColorIndicatorBack,
this.archived = archived;
this.lastActivity = lastActivity;
this.listener = listener;
+ this.forwardedCount = forwardedCount;
}
public static ContactVO convert(AbstractContact contact, ContactClickListener listener) {
@@ -127,6 +130,7 @@ public static ContactVO convert(AbstractContact contact, ContactClickListener li
Date time = null;
int messageStatus = 0;
int unreadCount = 0;
+ int forwardedCount = 0;
String messageOwner = null;
AccountItem accountItem = AccountManager.getInstance().getAccount(contact.getAccount());
@@ -201,6 +205,9 @@ public static ContactVO convert(AbstractContact contact, ContactClickListener li
messageStatus = 5;
}
}
+
+ // forwarded
+ if (lastMessage.haveForwardedMessages()) forwardedCount = lastMessage.getForwardedIds().size();
}
if (!isOutgoing) unreadCount = chat.getUnreadMessageCount();
@@ -217,7 +224,7 @@ public static ContactVO convert(AbstractContact contact, ContactClickListener li
showOfflineShadow, name, statusText, statusId,
statusLevel, avatar, mucIndicatorLevel, contact.getUser(), contact.getAccount(),
unreadCount, !chat.notifyAboutMessage(), mode, messageText, isOutgoing, time,
- messageStatus, messageOwner, chat.isArchived(), lastActivity, listener);
+ messageStatus, messageOwner, chat.isArchived(), lastActivity, listener, forwardedCount);
}
public static ArrayList convert(Collection contacts, ContactClickListener listener) {
diff --git a/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/CrowdfundingChatVO.java b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/CrowdfundingChatVO.java
new file mode 100644
index 0000000000..37fd91332f
--- /dev/null
+++ b/xabber/src/main/java/com/xabber/android/presentation/ui/contactlist/viewobjects/CrowdfundingChatVO.java
@@ -0,0 +1,117 @@
+package com.xabber.android.presentation.ui.contactlist.viewobjects;
+
+import android.content.Context;
+import android.text.Html;
+import android.view.View;
+import android.widget.TextView;
+
+import com.xabber.android.R;
+import com.xabber.android.data.extension.file.FileManager;
+import com.xabber.android.data.filedownload.FileCategory;
+import com.xabber.android.data.roster.CrowdfundingContact;
+import com.xabber.android.ui.color.ColorManager;
+import com.xabber.android.utils.StringUtils;
+
+import java.util.Date;
+import java.util.List;
+import java.util.UUID;
+
+import eu.davidea.flexibleadapter.FlexibleAdapter;
+import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
+import eu.davidea.viewholders.FlexibleViewHolder;
+
+public class CrowdfundingChatVO extends AbstractFlexibleItem {
+
+ private final String id;
+ private final Date time;
+ private final int unreadCount;
+ private final String messageText;
+ private int accountColorIndicator;
+ private int accountColorIndicatorBack;
+
+ public CrowdfundingChatVO(String messageText, Date time, int unreadCount,
+ int accountColorIndicator, int accountColorIndicatorBack) {
+ this.id = UUID.randomUUID().toString();
+ this.time = time;
+ this.unreadCount = unreadCount;
+ this.messageText = messageText;
+ this.accountColorIndicator = accountColorIndicator;
+ this.accountColorIndicatorBack = accountColorIndicatorBack;
+ }
+
+ public static CrowdfundingChatVO convert(CrowdfundingContact contact) {
+ int unreadCount = contact.getUnreadCount();
+ int accountColorIndicator = ColorManager.getInstance().getAccountPainter().getDefaultMainColor();
+ int accountColorIndicatorBack = ColorManager.getInstance().getAccountPainter().getDefaultIndicatorBackColor();
+ return new CrowdfundingChatVO(contact.getLastMessageText(), contact.getLastMessageTime(), unreadCount,
+ accountColorIndicator, accountColorIndicatorBack);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof CrowdfundingChatVO) {
+ CrowdfundingChatVO inItem = (CrowdfundingChatVO) o;
+ return this.id.equals(inItem.id);
+ }
+ return false;
+ }
+
+ @Override
+ public int getLayoutRes() {
+ return R.layout.item_crowdfunding_chat_in_contact_list;
+ }
+
+ @Override
+ public ViewHolder createViewHolder(View view, FlexibleAdapter adapter) {
+ return new ViewHolder(view, adapter);
+ }
+
+ @Override
+ public void bindViewHolder(FlexibleAdapter adapter, ViewHolder holder, int position, List