Unverified Commit 94c28569 authored by Rafael Kellermann Streit's avatar Rafael Kellermann Streit Committed by GitHub

Merge pull request #678 from RocketChat/develop

[RELEASE] Merge develop into master
parents 5bbd3f7f 449e639e
...@@ -21,9 +21,10 @@ android { ...@@ -21,9 +21,10 @@ android {
} }
} }
dependencies { dependencies {
compile project(':log-wrapper') api project(':log-wrapper')
compile extraDependencies.okHTTP implementation extraDependencies.okHTTP
compile extraDependencies.rxJava implementation extraDependencies.rxJava
compile extraDependencies.boltTask implementation extraDependencies.rxKotlin
compile supportDependencies.annotation implementation extraDependencies.boltTask
implementation supportDependencies.annotation
} }
\ No newline at end of file
...@@ -84,7 +84,11 @@ public class DDPClient { ...@@ -84,7 +84,11 @@ public class DDPClient {
} }
public void close() { public void close() {
impl.close(REASON_CLOSED_BY_USER, "closed by DDPClient#close()"); close(REASON_CLOSED_BY_USER);
}
public void close(int reason) {
impl.close(reason, "closed by DDPClient#close()");
} }
/** /**
......
...@@ -28,7 +28,7 @@ public class DDPClientImpl { ...@@ -28,7 +28,7 @@ public class DDPClientImpl {
private CompositeDisposable disposables; private CompositeDisposable disposables;
private String currentSession; private String currentSession;
public DDPClientImpl(DDPClient self, OkHttpClient client) { /* package */ DDPClientImpl(DDPClient self, OkHttpClient client) {
websocket = new RxWebSocket(client); websocket = new RxWebSocket(client);
this.client = self; this.client = self;
} }
...@@ -65,8 +65,8 @@ public class DDPClientImpl { ...@@ -65,8 +65,8 @@ public class DDPClientImpl {
sendMessage("connect", sendMessage("connect",
json -> (TextUtils.isEmpty(session) ? json : json.put("session", DDPClientImpl.this.currentSession)) json -> (TextUtils.isEmpty(session) ? json : json.put("session", DDPClientImpl.this.currentSession))
.put( .put(
"version", "pre2") "version", "1")
.put("support", new JSONArray().put("pre2").put("pre1")), .put("support", new JSONArray().put("1").put("pre2").put("pre1")),
task), task),
RCLog::e RCLog::e
) )
...@@ -95,7 +95,13 @@ public class DDPClientImpl { ...@@ -95,7 +95,13 @@ public class DDPClientImpl {
disposables.clear(); disposables.clear();
} }
}, },
err -> task.trySetError(new DDPClientCallback.Connect.Timeout(client)) err -> {
if (err instanceof TimeoutException) {
task.trySetError(new Exception("Your connection seems off…"));
} else {
task.trySetError(new Exception("Ooops. Something's up!"));
}
}
) )
); );
...@@ -107,7 +113,7 @@ public class DDPClientImpl { ...@@ -107,7 +113,7 @@ public class DDPClientImpl {
} }
} }
public Maybe<DDPClientCallback.Base> ping(@Nullable final String id) { /* package */ Maybe<DDPClientCallback.Base> ping(@Nullable final String id) {
final boolean requested = (TextUtils.isEmpty(id)) ? final boolean requested = (TextUtils.isEmpty(id)) ?
sendMessage("ping", null) : sendMessage("ping", null) :
...@@ -145,7 +151,7 @@ public class DDPClientImpl { ...@@ -145,7 +151,7 @@ public class DDPClientImpl {
} }
} }
public void ping(final TaskCompletionSource<DDPClientCallback.Ping> task, /* package */void ping(final TaskCompletionSource<DDPClientCallback.Ping> task,
@Nullable final String id) { @Nullable final String id) {
final boolean requested = (TextUtils.isEmpty(id)) ? final boolean requested = (TextUtils.isEmpty(id)) ?
...@@ -175,7 +181,13 @@ public class DDPClientImpl { ...@@ -175,7 +181,13 @@ public class DDPClientImpl {
disposables.clear(); disposables.clear();
} }
}, },
err -> task.trySetError(new DDPClientCallback.Ping.Timeout(client)) err -> {
if (err instanceof TimeoutException) {
task.trySetError(new Exception("Your connection seems off…"));
} else {
task.trySetError(new Exception("Ooops. Something's up!"));
}
}
) )
); );
...@@ -185,7 +197,9 @@ public class DDPClientImpl { ...@@ -185,7 +197,9 @@ public class DDPClientImpl {
} }
} }
public void sub(final TaskCompletionSource<DDPSubscription.Ready> task, String name, /* package */
void sub(final TaskCompletionSource<DDPSubscription.Ready> task, String name,
JSONArray params, String id) { JSONArray params, String id) {
final boolean requested = final boolean requested =
sendMessage("sub", json -> json.put("id", id).put("name", name).put("params", params)); sendMessage("sub", json -> json.put("id", id).put("name", name).put("params", params));
...@@ -220,7 +234,13 @@ public class DDPClientImpl { ...@@ -220,7 +234,13 @@ public class DDPClientImpl {
} }
} }
}, },
RCLog::e err -> {
if (err instanceof TimeoutException) {
task.trySetError(new Exception("Your connection seems off…"));
} else {
task.trySetError(new Exception("Ooops. Something's up!"));
}
}
) )
); );
...@@ -230,7 +250,7 @@ public class DDPClientImpl { ...@@ -230,7 +250,7 @@ public class DDPClientImpl {
} }
} }
public void unsub(final TaskCompletionSource<DDPSubscription.NoSub> task, /* package */ void unsub(final TaskCompletionSource<DDPSubscription.NoSub> task,
@Nullable final String id) { @Nullable final String id) {
final boolean requested = sendMessage("unsub", json -> json.put("id", id)); final boolean requested = sendMessage("unsub", json -> json.put("id", id));
...@@ -254,6 +274,11 @@ public class DDPClientImpl { ...@@ -254,6 +274,11 @@ public class DDPClientImpl {
} }
}, },
err -> { err -> {
if (err instanceof TimeoutException) {
task.trySetError(new Exception("Your connection seems off…"));
} else {
task.trySetError(new Exception("Ooops. Something's up!"));
}
} }
) )
); );
...@@ -264,7 +289,7 @@ public class DDPClientImpl { ...@@ -264,7 +289,7 @@ public class DDPClientImpl {
} }
} }
public void rpc(final TaskCompletionSource<DDPClientCallback.RPC> task, String method, /* package */ void rpc(final TaskCompletionSource<DDPClientCallback.RPC> task, String method,
JSONArray params, String id, long timeoutMs) { JSONArray params, String id, long timeoutMs) {
final boolean requested = final boolean requested =
sendMessage("method", sendMessage("method",
...@@ -297,7 +322,9 @@ public class DDPClientImpl { ...@@ -297,7 +322,9 @@ public class DDPClientImpl {
}, },
err -> { err -> {
if (err instanceof TimeoutException) { if (err instanceof TimeoutException) {
task.trySetError(new DDPClientCallback.RPC.Timeout(client)); task.trySetError(new Exception("Your connection seems off…"));
} else {
task.trySetError(new Exception("Ooops. Something's up!"));
} }
} }
) )
...@@ -336,7 +363,7 @@ public class DDPClientImpl { ...@@ -336,7 +363,7 @@ public class DDPClientImpl {
); );
} }
public Flowable<DDPSubscription.Event> getDDPSubscription() { /* package */ Flowable<DDPSubscription.Event> getDDPSubscription() {
String[] targetMsgs = {"added", "changed", "removed", "addedBefore", "movedBefore"}; String[] targetMsgs = {"added", "changed", "removed", "addedBefore", "movedBefore"};
return flowable.filter(callback -> callback instanceof RxWebSocketCallback.Message) return flowable.filter(callback -> callback instanceof RxWebSocketCallback.Message)
.map(callback -> ((RxWebSocketCallback.Message) callback).responseBodyString) .map(callback -> ((RxWebSocketCallback.Message) callback).responseBodyString)
...@@ -379,13 +406,13 @@ public class DDPClientImpl { ...@@ -379,13 +406,13 @@ public class DDPClientImpl {
}); });
} }
public void unsubscribeBaseListeners() { /* package */ void unsubscribeBaseListeners() {
if (disposables.size() > 0 || !disposables.isDisposed()) { if (disposables.size() > 0 || !disposables.isDisposed()) {
disposables.clear(); disposables.clear();
} }
} }
public Task<RxWebSocketCallback.Close> getOnCloseCallback() { /* package */ Task<RxWebSocketCallback.Close> getOnCloseCallback() {
TaskCompletionSource<RxWebSocketCallback.Close> task = new TaskCompletionSource<>(); TaskCompletionSource<RxWebSocketCallback.Close> task = new TaskCompletionSource<>();
flowable.filter(callback -> callback instanceof RxWebSocketCallback.Close) flowable.filter(callback -> callback instanceof RxWebSocketCallback.Close)
......
...@@ -3,7 +3,8 @@ apply plugin: 'io.fabric' ...@@ -3,7 +3,8 @@ apply plugin: 'io.fabric'
repositories { repositories {
maven { url 'https://maven.fabric.io/public' } maven { url 'https://maven.fabric.io/public' }
maven { url 'https://github.com/uPhyca/stetho-realm/raw/master/maven-repo' } // maven { url 'https://github.com/uPhyca/stetho-realm/raw/master/maven-repo' }
maven { url 'https://github.com/WickeDev/stetho-realm/raw/master/maven-repo' }
} }
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
...@@ -20,8 +21,8 @@ android { ...@@ -20,8 +21,8 @@ android {
applicationId "chat.rocket.android" applicationId "chat.rocket.android"
minSdkVersion 16 minSdkVersion 16
targetSdkVersion rootProject.ext.targetSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 54 versionCode 58
versionName "1.0.31" versionName "1.1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
multiDexEnabled true multiDexEnabled true
...@@ -97,10 +98,9 @@ play { ...@@ -97,10 +98,9 @@ play {
track = "${track}" track = "${track}"
} }
ext { ext {
playLibVersion = '11.6.0'
stethoVersion = '1.5.0' stethoVersion = '1.5.0'
stethoOkhttp3Version = '1.5.0' stethoOkhttp3Version = '1.5.0'
stethoRealmVersion = '2.1.0' stethoRealmVersion = '2.2.2'
rxbindingVersion = '2.0.0' rxbindingVersion = '2.0.0'
rxlifecycleVersion = '2.1.0' rxlifecycleVersion = '2.1.0'
icepickVersion = '3.2.0' icepickVersion = '3.2.0'
...@@ -108,43 +108,49 @@ ext { ...@@ -108,43 +108,49 @@ ext {
} }
dependencies { dependencies {
compile project(':android-ddp') api project(':android-ddp')
compile project(':rocket-chat-android-widgets') api project(':rocket-chat-android-widgets')
compile project(':persistence-realm') api project(':persistence-realm')
compile extraDependencies.okHTTP implementation extraDependencies.okHTTP
compile extraDependencies.rxJava implementation extraDependencies.rxJava
compile extraDependencies.boltTask implementation extraDependencies.rxKotlin
compile supportDependencies.multidex implementation extraDependencies.boltTask
compile supportDependencies.designSupportLibrary implementation supportDependencies.multidex
compile supportDependencies.annotation implementation supportDependencies.designSupportLibrary
compile rxbindingDependencies.rxBinding implementation supportDependencies.annotation
compile rxbindingDependencies.rxBindingSupport implementation rxbindingDependencies.rxBinding
compile rxbindingDependencies.rxBindingAppcompact implementation rxbindingDependencies.rxBindingSupport
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$rootProject.ext.kotlinVersion" implementation rxbindingDependencies.rxBindingAppcompact
compile "com.google.firebase:firebase-core:$playLibVersion" api "org.jetbrains.kotlin:kotlin-stdlib-jre8:$rootProject.ext.kotlinVersion"
compile "com.google.firebase:firebase-crash:$playLibVersion" implementation "com.google.firebase:firebase-core:$rootProject.ext.playLibVersion"
compile "com.google.android.gms:play-services-gcm:$playLibVersion" implementation "com.google.firebase:firebase-crash:$rootProject.ext.playLibVersion"
compile "com.trello.rxlifecycle2:rxlifecycle:$rxlifecycleVersion" implementation "com.google.android.gms:play-services-gcm:$rootProject.ext.playLibVersion"
compile "com.trello.rxlifecycle2:rxlifecycle-android:$rxlifecycleVersion" implementation "com.trello.rxlifecycle2:rxlifecycle:$rxlifecycleVersion"
compile "com.trello.rxlifecycle2:rxlifecycle-components:$rxlifecycleVersion" implementation "com.trello.rxlifecycle2:rxlifecycle-android:$rxlifecycleVersion"
compile 'nl.littlerobots.rxlint:rxlint:1.2' implementation "com.trello.rxlifecycle2:rxlifecycle-components:$rxlifecycleVersion"
compile "frankiesardo:icepick:$icepickVersion" implementation 'nl.littlerobots.rxlint:rxlint:1.2'
implementation "frankiesardo:icepick:$icepickVersion"
annotationProcessor "frankiesardo:icepick-processor:$icepickVersion" annotationProcessor "frankiesardo:icepick-processor:$icepickVersion"
compile "com.github.hotchemi:permissionsdispatcher:$permissionsdispatcherVersion" implementation "com.github.hotchemi:permissionsdispatcher:$permissionsdispatcherVersion"
annotationProcessor "com.github.hotchemi:permissionsdispatcher-processor:$permissionsdispatcherVersion" annotationProcessor "com.github.hotchemi:permissionsdispatcher-processor:$permissionsdispatcherVersion"
compile('com.crashlytics.sdk.android:crashlytics:2.6.8@aar') { implementation('com.crashlytics.sdk.android:crashlytics:2.6.8@aar') {
transitive = true; transitive = true;
} }
debugCompile "com.facebook.stetho:stetho:$stethoVersion" implementation(extraDependencies.crouton) {
exclude group: 'com.android.support', module: 'support-v4'
}
implementation extraDependencies.androidJob
implementation extraDependencies.jstate
debugImplementation "com.facebook.stetho:stetho:$stethoVersion"
debugCompile "com.facebook.stetho:stetho-okhttp3:$stethoOkhttp3Version" debugCompile "com.facebook.stetho:stetho-okhttp3:$stethoOkhttp3Version"
debugCompile "com.uphyca:stetho_realm:$stethoRealmVersion" debugCompile "com.uphyca:stetho_realm:$stethoRealmVersion"
debugCompile "com.tspoon.traceur:traceur:1.0.1" debugCompile "com.tspoon.traceur:traceur:1.0.1"
testCompile 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
testCompile 'org.robolectric:robolectric:3.3' testImplementation 'org.robolectric:robolectric:3.3'
testCompile "org.jetbrains.kotlin:kotlin-test:$rootProject.ext.kotlinVersion" testImplementation "org.jetbrains.kotlin:kotlin-test:$rootProject.ext.kotlinVersion"
testCompile "org.jetbrains.kotlin:kotlin-test-junit:$rootProject.ext.kotlinVersion" testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$rootProject.ext.kotlinVersion"
testCompile "org.jetbrains.kotlin:kotlin-reflect:$rootProject.ext.kotlinVersion" testImplementation "org.jetbrains.kotlin:kotlin-reflect:$rootProject.ext.kotlinVersion"
testCompile "com.nhaarman:mockito-kotlin:1.5.0" testImplementation "com.nhaarman:mockito-kotlin:1.5.0"
testCompile 'org.amshove.kluent:kluent:1.14' testImplementation 'org.amshove.kluent:kluent:1.14'
} }
apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.gms.google-services'
package chat.rocket.android.helper package chat.rocket.android.helper
import android.content.Context
import chat.rocket.android.RocketChatCache
import chat.rocket.android.api.rest.CookieInterceptor import chat.rocket.android.api.rest.CookieInterceptor
import chat.rocket.android.api.rest.DefaultCookieProvider import chat.rocket.android.api.rest.DefaultCookieProvider
import com.facebook.stetho.okhttp3.StethoInterceptor import com.facebook.stetho.okhttp3.StethoInterceptor
...@@ -24,17 +22,18 @@ object OkHttpHelper { ...@@ -24,17 +22,18 @@ object OkHttpHelper {
return httpClientForUploadFile ?: throw AssertionError("httpClientForUploadFile set to null by another thread") return httpClientForUploadFile ?: throw AssertionError("httpClientForUploadFile set to null by another thread")
} }
fun getClientForDownloadFile(context: Context): OkHttpClient { fun getClientForDownloadFile(): OkHttpClient {
if(httpClientForDownloadFile == null) { if (httpClientForDownloadFile == null) {
httpClientForDownloadFile = OkHttpClient.Builder() httpClientForDownloadFile = OkHttpClient.Builder()
.addNetworkInterceptor(StethoInterceptor()) .addNetworkInterceptor(StethoInterceptor())
.followRedirects(true) .followRedirects(true)
.followSslRedirects(true) .followSslRedirects(true)
.addInterceptor(CookieInterceptor(DefaultCookieProvider(RocketChatCache(context)))) .addInterceptor(CookieInterceptor(DefaultCookieProvider()))
.build() .build()
} }
return httpClientForDownloadFile ?: throw AssertionError("httpClientForDownloadFile set to null by another thread") return httpClientForDownloadFile ?: throw AssertionError("httpClientForDownloadFile set to null by another thread")
} }
/** /**
* Returns the OkHttpClient instance for WebSocket connection. * Returns the OkHttpClient instance for WebSocket connection.
* @return The OkHttpClient WebSocket connection instance. * @return The OkHttpClient WebSocket connection instance.
......
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="chat.rocket.android"> package="chat.rocket.android">
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK"/> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.VIBRATE"/> <uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.VIBRATE" />
<permission <permission
android:name="chat.rocket.android.permission.C2D_MESSAGE" android:name="chat.rocket.android.permission.C2D_MESSAGE"
android:protectionLevel="signature"/> android:protectionLevel="signature" />
<uses-permission android:name="chat.rocket.android.permission.C2D_MESSAGE"/> <uses-permission android:name="chat.rocket.android.permission.C2D_MESSAGE" />
<application <application
android:name=".RocketChatApplication" android:name=".RocketChatApplication"
...@@ -26,39 +27,40 @@ ...@@ -26,39 +27,40 @@
android:configChanges="orientation|screenSize" android:configChanges="orientation|screenSize"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
android:name=".activity.room.RoomActivity" android:name=".activity.room.RoomActivity"
android:configChanges="orientation|screenSize" android:configChanges="orientation|screenSize"
android:windowSoftInputMode="adjustResize"/> android:windowSoftInputMode="adjustResize" />
<activity <activity
android:name=".activity.AddServerActivity" android:name=".activity.AddServerActivity"
android:configChanges="orientation|screenSize" android:configChanges="orientation|screenSize"
android:windowSoftInputMode="adjustResize" android:launchMode="singleTop"
android:launchMode="singleTop"/> android:windowSoftInputMode="adjustResize" />
<activity <activity
android:name=".activity.LoginActivity" android:name=".activity.LoginActivity"
android:configChanges="orientation|screenSize" android:configChanges="orientation|screenSize"
android:windowSoftInputMode="adjustResize"/> android:windowSoftInputMode="adjustResize" />
<service android:name=".service.RocketChatService"/> <service android:name=".service.RocketChatService" />
<receiver <receiver
android:name="com.google.android.gms.gcm.GcmReceiver" android:name="com.google.android.gms.gcm.GcmReceiver"
android:exported="true" android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND"> android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter> <intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE"/> <action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION"/> <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="chat.rocket.android"/>
<category android:name="chat.rocket.android" />
</intent-filter> </intent-filter>
</receiver> </receiver>
...@@ -67,8 +69,8 @@ ...@@ -67,8 +69,8 @@
android:exported="true" android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND"> android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter> <intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE"/> <action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="chat.rocket.android"/> <category android:name="chat.rocket.android" />
</intent-filter> </intent-filter>
</receiver> </receiver>
...@@ -76,7 +78,8 @@ ...@@ -76,7 +78,8 @@
android:name="com.google.firebase.iid.FirebaseInstanceIdInternalReceiver" android:name="com.google.firebase.iid.FirebaseInstanceIdInternalReceiver"
android:exported="false" /> android:exported="false" />
<service android:name="com.google.firebase.iid.FirebaseInstanceIdService" <service
android:name="com.google.firebase.iid.FirebaseInstanceIdService"
android:exported="true"> android:exported="true">
<intent-filter android:priority="-500"> <intent-filter android:priority="-500">
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" /> <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
...@@ -87,7 +90,7 @@ ...@@ -87,7 +90,7 @@
android:name=".push.gcm.GCMIntentService" android:name=".push.gcm.GCMIntentService"
android:exported="false"> android:exported="false">
<intent-filter> <intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE"/> <action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter> </intent-filter>
</service> </service>
...@@ -95,14 +98,16 @@ ...@@ -95,14 +98,16 @@
android:name=".push.gcm.GcmInstanceIDListenerService" android:name=".push.gcm.GcmInstanceIDListenerService"
android:exported="false"> android:exported="false">
<intent-filter> <intent-filter>
<action android:name="com.google.android.gms.iid.InstanceID"/> <action android:name="com.google.android.gms.iid.InstanceID" />
</intent-filter> </intent-filter>
</service> </service>
<receiver android:name=".push.PushManager$DeleteReceiver" <receiver
android:name=".push.PushManager$DeleteReceiver"
android:exported="false" /> android:exported="false" />
<receiver android:name=".push.PushManager$ReplyReceiver" <receiver
android:name=".push.PushManager$ReplyReceiver"
android:exported="false" /> android:exported="false" />
<meta-data <meta-data
......
package chat.rocket.android
import chat.rocket.android.extensions.printStackTraceOnDebug
import chat.rocket.android.service.KeepAliveJob
import unquietcode.tools.esm.EnumStateMachine
import unquietcode.tools.esm.TransitionException
object ConnectionStatusManager {
enum class State {
OFFLINE, CONNECTING, ONLINE
}
private const val DEBUG = false
private val DEFAULT_CALLBACK = object : TransitionCallback {
override fun onTransitioned(success: Boolean) {
}
}
private val stateMachine: EnumStateMachine<State>
init {
stateMachine = EnumStateMachine(State.OFFLINE)
stateMachine.addTransitions(State.OFFLINE, State.CONNECTING)
stateMachine.addTransitions(State.CONNECTING, State.ONLINE, State.OFFLINE)
stateMachine.addTransitions(State.ONLINE, State.OFFLINE)
}
@Synchronized
fun transitionCount() = stateMachine.transitionCount()
@Synchronized
fun currentState() = stateMachine.currentState()
@Synchronized
fun setOnline(callback: TransitionCallback = DEFAULT_CALLBACK) {
KeepAliveJob.cancelPendingJobRequests()
tryTransitionTo(State.ONLINE, callback)
}
@Synchronized
fun setOnline() {
KeepAliveJob.cancelPendingJobRequests()
tryTransitionTo(State.ONLINE, DEFAULT_CALLBACK)
}
@Synchronized
fun setConnecting(callback: TransitionCallback = DEFAULT_CALLBACK) {
KeepAliveJob.cancelPendingJobRequests()
tryTransitionTo(State.CONNECTING, callback)
}
@Synchronized
fun setConnecting() {
KeepAliveJob.cancelPendingJobRequests()
tryTransitionTo(State.CONNECTING, DEFAULT_CALLBACK)
}
@Synchronized
fun setConnectionError(callback: TransitionCallback = DEFAULT_CALLBACK) {
KeepAliveJob.schedule()
tryTransitionTo(State.OFFLINE, callback)
}
@Synchronized
fun setConnectionError() {
KeepAliveJob.schedule()
tryTransitionTo(State.OFFLINE, DEFAULT_CALLBACK)
}
@Synchronized
fun setOffline() {
stateMachine.reset()
}
private fun tryTransitionTo(newState: State, callback: TransitionCallback) {
try {
stateMachine.transition(newState)
callback.onTransitioned(true)
} catch (e: TransitionException) {
if (DEBUG) {
e.printStackTraceOnDebug()
}
callback.onTransitioned(false)
}
}
interface TransitionCallback {
fun onTransitioned(success: Boolean)
}
}
\ No newline at end of file
...@@ -5,6 +5,7 @@ import android.support.multidex.MultiDexApplication; ...@@ -5,6 +5,7 @@ import android.support.multidex.MultiDexApplication;
import android.support.v7.app.AppCompatDelegate; import android.support.v7.app.AppCompatDelegate;
import com.crashlytics.android.Crashlytics; import com.crashlytics.android.Crashlytics;
import com.evernote.android.job.JobManager;
import java.util.List; import java.util.List;
...@@ -34,6 +35,8 @@ public class RocketChatApplication extends MultiDexApplication { ...@@ -34,6 +35,8 @@ public class RocketChatApplication extends MultiDexApplication {
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
RocketChatCache.INSTANCE.initialize(this);
JobManager.create(this).addJobCreator(new RocketChatJobCreator());
DDPClient.initialize(OkHttpHelper.INSTANCE.getClientForWebSocket()); DDPClient.initialize(OkHttpHelper.INSTANCE.getClientForWebSocket());
Fabric.with(this, new Crashlytics()); Fabric.with(this, new Crashlytics());
...@@ -44,7 +47,7 @@ public class RocketChatApplication extends MultiDexApplication { ...@@ -44,7 +47,7 @@ public class RocketChatApplication extends MultiDexApplication {
RealmStore.put(serverInfo.getHostname()); RealmStore.put(serverInfo.getHostname());
} }
RocketChatWidgets.initialize(this, OkHttpHelper.INSTANCE.getClientForDownloadFile(this)); RocketChatWidgets.initialize(this, OkHttpHelper.INSTANCE.getClientForDownloadFile());
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
...@@ -57,7 +60,7 @@ public class RocketChatApplication extends MultiDexApplication { ...@@ -57,7 +60,7 @@ public class RocketChatApplication extends MultiDexApplication {
if (BuildConfig.DEBUG) { if (BuildConfig.DEBUG) {
e.printStackTrace(); e.printStackTrace();
} }
Logger.report(e); Logger.INSTANCE.report(e);
}); });
instance = this; instance = this;
......
package chat.rocket.android;
import android.content.Context;
import android.content.SharedPreferences;
import com.hadisatrio.optional.Optional;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import chat.rocket.android.helper.Logger;
import chat.rocket.android.helper.TextUtils;
import chat.rocket.android.log.RCLog;
import chat.rocket.core.utils.Pair;
import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import io.reactivex.annotations.NonNull;
import io.reactivex.annotations.Nullable;
import okhttp3.HttpUrl;
/**
* sharedpreference-based cache.
*/
public class RocketChatCache {
private static final String KEY_SELECTED_SERVER_HOSTNAME = "KEY_SELECTED_SERVER_HOSTNAME";
private static final String KEY_SELECTED_SITE_URL = "KEY_SELECTED_SITE_URL";
private static final String KEY_SELECTED_SITE_NAME = "KEY_SELECTED_SITE_NAME";
private static final String KEY_SELECTED_ROOM_ID = "KEY_SELECTED_ROOM_ID";
private static final String KEY_PUSH_ID = "KEY_PUSH_ID";
private static final String KEY_HOSTNAME_LIST = "KEY_HOSTNAME_LIST";
private Context context;
public RocketChatCache(Context context) {
this.context = context.getApplicationContext();
}
public String getSelectedServerHostname() {
return getString(KEY_SELECTED_SERVER_HOSTNAME, null);
}
public void setSelectedServerHostname(String hostname) {
String newHostname = null;
if (hostname != null) {
newHostname = hostname.toLowerCase();
}
setString(KEY_SELECTED_SERVER_HOSTNAME, newHostname);
}
public void addHostSiteName(@NonNull String currentHostname, @NonNull String siteName) {
try {
String hostSiteNamesJson = getHostSiteNamesJson();
JSONObject jsonObject = (hostSiteNamesJson == null) ?
new JSONObject() : new JSONObject(hostSiteNamesJson);
jsonObject.put(currentHostname, siteName);
setString(KEY_SELECTED_SITE_NAME, jsonObject.toString());
} catch (JSONException e) {
RCLog.e(e);
}
}
public @NonNull String getHostSiteName(@NonNull String host) {
if (host.startsWith("http")) {
HttpUrl url = HttpUrl.parse(host);
if (url != null) {
host = url.host();
}
}
try {
String hostSiteNamesJson = getHostSiteNamesJson();
JSONObject jsonObject = (hostSiteNamesJson == null) ?
new JSONObject() : new JSONObject(hostSiteNamesJson);
host = getSiteUrlFor(host);
return jsonObject.optString(host);
} catch (JSONException e) {
RCLog.e(e);
}
return "";
}
private @Nullable String getHostSiteNamesJson() {
return getString(KEY_SELECTED_SITE_NAME, null);
}
public void addHostnameSiteUrl(@Nullable String hostnameAlias, @NonNull String currentHostname) {
String alias = null;
if (hostnameAlias != null) {
alias = hostnameAlias.toLowerCase();
}
try {
String selectedHostnameAliasJson = getLoginHostnamesJson();
JSONObject jsonObject = selectedHostnameAliasJson == null ?
new JSONObject() : new JSONObject(selectedHostnameAliasJson);
jsonObject.put(alias, currentHostname);
setString(KEY_SELECTED_SITE_URL, jsonObject.toString());
} catch (JSONException e) {
RCLog.e(e);
}
}
public @Nullable String getSiteUrlFor(String hostname) {
try {
String selectedServerHostname = getSelectedServerHostname();
if (getLoginHostnamesJson() == null || getLoginHostnamesJson().isEmpty()) {
return null;
}
return new JSONObject(getLoginHostnamesJson())
.optString(hostname, selectedServerHostname);
} catch (JSONException e) {
RCLog.e(e);
}
return null;
}
private @Nullable String getLoginHostnamesJson() {
return getString(KEY_SELECTED_SITE_URL, null);
}
public void addHostname(@NonNull String hostname, @Nullable String hostnameAvatarUri, String siteName) {
String hostnameList = getString(KEY_HOSTNAME_LIST, null);
try {
JSONObject json;
if (hostnameList == null) {
json = new JSONObject();
} else {
json = new JSONObject(hostnameList);
}
JSONObject serverInfoJson = new JSONObject();
serverInfoJson.put("avatar", hostnameAvatarUri);
serverInfoJson.put("sitename", siteName);
// Replace server avatar uri if exists.
json.put(hostname, hostnameAvatarUri == null ? JSONObject.NULL : serverInfoJson);
setString(KEY_HOSTNAME_LIST, json.toString());
} catch (JSONException e) {
RCLog.e(e);
}
}
public List<Pair<String, Pair<String, String>>> getServerList() {
String json = getString(KEY_HOSTNAME_LIST, null);
if (json == null) {
return Collections.emptyList();
}
try {
JSONObject jsonObj = new JSONObject(json);
List<Pair<String, Pair<String, String>>> serverList = new ArrayList<>();
for (Iterator<String> iter = jsonObj.keys(); iter.hasNext();) {
String hostname = iter.next();
JSONObject serverInfoJson = jsonObj.getJSONObject(hostname);
serverList.add(new Pair<>(hostname, new Pair<>(
"http://" + hostname + "/" + serverInfoJson.getString("avatar"),
serverInfoJson.getString("sitename"))));
}
return serverList;
} catch (JSONException e) {
RCLog.e(e);
}
return Collections.emptyList();
}
public void removeHostname(String hostname) {
String json = getString(KEY_HOSTNAME_LIST, null);
if (TextUtils.isEmpty(json)) {
return;
}
try {
JSONObject jsonObj = new JSONObject(json);
jsonObj.remove(hostname);
String result = jsonObj.length() == 0 ? null : jsonObj.toString();
setString(KEY_HOSTNAME_LIST, result);
} catch (JSONException e) {
RCLog.e(e);
}
}
@Nullable
public String getFirstLoggedHostnameIfAny() {
String json = getString(KEY_HOSTNAME_LIST, null);
if (json != null) {
try {
JSONObject jsonObj = new JSONObject(json);
if (jsonObj.length() > 0 && jsonObj.keys().hasNext()) {
// Returns the first hostname on the list.
return jsonObj.keys().next();
}
} catch (JSONException e) {
RCLog.e(e);
}
}
return null;
}
public String getSelectedRoomId() {
try {
JSONObject jsonObject = getSelectedRoomIdJsonObject();
return jsonObject.optString(getSelectedServerHostname(), null);
} catch (JSONException e) {
RCLog.e(e);
Logger.report(e);
}
return null;
}
public void setSelectedRoomId(String roomId) {
try {
JSONObject jsonObject = getSelectedRoomIdJsonObject();
jsonObject.put(getSelectedServerHostname(), roomId);
setString(KEY_SELECTED_ROOM_ID, jsonObject.toString());
} catch (JSONException e) {
RCLog.e(e);
Logger.report(e);
}
}
private JSONObject getSelectedRoomIdJsonObject() throws JSONException {
String json = getString(KEY_SELECTED_ROOM_ID, null);
if (json == null) {
return new JSONObject();
}
return new JSONObject(json);
}
public String getOrCreatePushId() {
SharedPreferences preferences = getSharedPreferences();
if (!preferences.contains(KEY_PUSH_ID)) {
// generates one and save
String newId = UUID.randomUUID().toString().replace("-", "");
preferences.edit()
.putString(KEY_PUSH_ID, newId)
.apply();
return newId;
}
return preferences.getString(KEY_PUSH_ID, null);
}
public Flowable<Optional<String>> getSelectedServerHostnamePublisher() {
return getValuePublisher(KEY_SELECTED_SERVER_HOSTNAME);
}
public Flowable<Optional<String>> getSelectedRoomIdPublisher() {
return getValuePublisher(KEY_SELECTED_ROOM_ID)
.filter(Optional::isPresent)
.map(Optional::get)
.map(roomValue -> Optional.ofNullable(new JSONObject(roomValue).optString(getSelectedServerHostname(), null)));
}
private SharedPreferences getSharedPreferences() {
return context.getSharedPreferences("cache", Context.MODE_PRIVATE);
}
private SharedPreferences.Editor getEditor() {
return getSharedPreferences().edit();
}
public String getString(String key, String defaultValue) {
return getSharedPreferences().getString(key, defaultValue);
}
private void setString(String key, String value) {
getEditor().putString(key, value).apply();
}
private Flowable<Optional<String>> getValuePublisher(final String key) {
return Flowable.create(emitter -> {
SharedPreferences.OnSharedPreferenceChangeListener
listener = (sharedPreferences, changedKey) -> {
if (key.equals(changedKey) && !emitter.isCancelled()) {
String value = getString(key, null);
emitter.onNext(Optional.ofNullable(value));
}
};
emitter.setCancellable(() -> getSharedPreferences()
.unregisterOnSharedPreferenceChangeListener(listener));
getSharedPreferences().registerOnSharedPreferenceChangeListener(listener);
}, BackpressureStrategy.LATEST);
}
public void removeSelectedRoomId(String currentHostname) {
try {
JSONObject selectedRoomIdJsonObject = getSelectedRoomIdJsonObject();
selectedRoomIdJsonObject.remove(currentHostname);
String result = selectedRoomIdJsonObject.length() == 0 ?
null : selectedRoomIdJsonObject.toString();
setString(KEY_SELECTED_ROOM_ID, result);
} catch (JSONException e) {
Logger.report(e);
RCLog.e(e);
}
}
}
This diff is collapsed.
package chat.rocket.android
import chat.rocket.android.service.KeepAliveJob
import com.evernote.android.job.Job
import com.evernote.android.job.JobCreator
class RocketChatJobCreator : JobCreator {
override fun create(tag: String): Job? {
when (tag) {
KeepAliveJob.TAG -> return KeepAliveJob()
else -> return null
}
}
}
\ No newline at end of file
...@@ -24,10 +24,11 @@ import io.reactivex.schedulers.Schedulers; ...@@ -24,10 +24,11 @@ import io.reactivex.schedulers.Schedulers;
import okhttp3.HttpUrl; import okhttp3.HttpUrl;
abstract class AbstractAuthedActivity extends AbstractFragmentActivity { abstract class AbstractAuthedActivity extends AbstractFragmentActivity {
@State protected String hostname; @State
@State protected String roomId; protected String hostname;
@State
protected String roomId;
private RocketChatCache rocketChatCache;
private CompositeDisposable compositeDisposable = new CompositeDisposable(); private CompositeDisposable compositeDisposable = new CompositeDisposable();
private boolean isNotification; private boolean isNotification;
...@@ -36,13 +37,11 @@ abstract class AbstractAuthedActivity extends AbstractFragmentActivity { ...@@ -36,13 +37,11 @@ abstract class AbstractAuthedActivity extends AbstractFragmentActivity {
protected void onCreate(@Nullable Bundle savedInstanceState) { protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
rocketChatCache = new RocketChatCache(this);
if (savedInstanceState == null) { if (savedInstanceState == null) {
handleIntent(getIntent()); handleIntent(getIntent());
} }
updateHostnameIfNeeded(rocketChatCache.getSelectedServerHostname()); updateHostnameIfNeeded(RocketChatCache.INSTANCE.getSelectedServerHostname());
} }
@Override @Override
...@@ -61,16 +60,16 @@ abstract class AbstractAuthedActivity extends AbstractFragmentActivity { ...@@ -61,16 +60,16 @@ abstract class AbstractAuthedActivity extends AbstractFragmentActivity {
HttpUrl url = HttpUrl.parse(hostname); HttpUrl url = HttpUrl.parse(hostname);
if (url != null) { if (url != null) {
String hostnameFromPush = url.host(); String hostnameFromPush = url.host();
String loginHostname = rocketChatCache.getSiteUrlFor(hostnameFromPush); String loginHostname = RocketChatCache.INSTANCE.getSiteUrlFor(hostnameFromPush);
rocketChatCache.setSelectedServerHostname(loginHostname); RocketChatCache.INSTANCE.setSelectedServerHostname(loginHostname);
if (intent.hasExtra(PushManager.EXTRA_ROOM_ID)) { if (intent.hasExtra(PushManager.EXTRA_ROOM_ID)) {
rocketChatCache.setSelectedRoomId(intent.getStringExtra(PushManager.EXTRA_ROOM_ID)); RocketChatCache.INSTANCE.setSelectedRoomId(intent.getStringExtra(PushManager.EXTRA_ROOM_ID));
} }
} }
PushManager.INSTANCE.clearNotificationsByHost(hostname); PushManager.INSTANCE.clearNotificationsByHost(hostname);
} else { } else {
updateHostnameIfNeeded(rocketChatCache.getSelectedServerHostname()); updateHostnameIfNeeded(RocketChatCache.INSTANCE.getSelectedServerHostname());
} }
if (intent.hasExtra(PushManager.EXTRA_NOT_ID) && intent.hasExtra(PushManager.EXTRA_HOSTNAME)) { if (intent.hasExtra(PushManager.EXTRA_NOT_ID) && intent.hasExtra(PushManager.EXTRA_HOSTNAME)) {
...@@ -80,7 +79,7 @@ abstract class AbstractAuthedActivity extends AbstractFragmentActivity { ...@@ -80,7 +79,7 @@ abstract class AbstractAuthedActivity extends AbstractFragmentActivity {
HttpUrl url = HttpUrl.parse(hostname); HttpUrl url = HttpUrl.parse(hostname);
if (url != null) { if (url != null) {
String hostnameFromPush = url.host(); String hostnameFromPush = url.host();
String loginHostname = rocketChatCache.getSiteUrlFor(hostnameFromPush); String loginHostname = RocketChatCache.INSTANCE.getSiteUrlFor(hostnameFromPush);
PushManager.INSTANCE.clearNotificationsByHostAndNotificationId(loginHostname, notificationId); PushManager.INSTANCE.clearNotificationsByHostAndNotificationId(loginHostname, notificationId);
} else { } else {
PushManager.INSTANCE.clearNotificationsByNotificationId(notificationId); PushManager.INSTANCE.clearNotificationsByNotificationId(notificationId);
...@@ -93,14 +92,14 @@ abstract class AbstractAuthedActivity extends AbstractFragmentActivity { ...@@ -93,14 +92,14 @@ abstract class AbstractAuthedActivity extends AbstractFragmentActivity {
if (hostname == null) { if (hostname == null) {
if (newHostname != null && assertServerRealmStoreExists(newHostname)) { if (newHostname != null && assertServerRealmStoreExists(newHostname)) {
updateHostname(newHostname); updateHostname(newHostname);
updateRoomIdIfNeeded(rocketChatCache.getSelectedRoomId()); updateRoomIdIfNeeded(RocketChatCache.INSTANCE.getSelectedRoomId());
} else { } else {
recoverFromHostnameError(); recoverFromHostnameError();
} }
} else { } else {
if (hostname.equals(newHostname)) { if (hostname.equals(newHostname)) {
updateHostname(newHostname); updateHostname(newHostname);
updateRoomIdIfNeeded(rocketChatCache.getSelectedRoomId()); updateRoomIdIfNeeded(RocketChatCache.INSTANCE.getSelectedRoomId());
return; return;
} }
...@@ -135,8 +134,8 @@ abstract class AbstractAuthedActivity extends AbstractFragmentActivity { ...@@ -135,8 +134,8 @@ abstract class AbstractAuthedActivity extends AbstractFragmentActivity {
// just connect to the first available // just connect to the first available
final ServerInfo serverInfo = serverInfoList.get(0); final ServerInfo serverInfo = serverInfoList.get(0);
rocketChatCache.setSelectedServerHostname(serverInfo.getHostname()); RocketChatCache.INSTANCE.setSelectedServerHostname(serverInfo.getHostname());
rocketChatCache.setSelectedRoomId(null); RocketChatCache.INSTANCE.setSelectedRoomId(null);
} }
private void updateRoomIdIfNeeded(String newRoomId) { private void updateRoomIdIfNeeded(String newRoomId) {
...@@ -159,7 +158,7 @@ abstract class AbstractAuthedActivity extends AbstractFragmentActivity { ...@@ -159,7 +158,7 @@ abstract class AbstractAuthedActivity extends AbstractFragmentActivity {
RealmRoom room = RealmStore.get(hostname).executeTransactionForRead(realm -> RealmRoom room = RealmStore.get(hostname).executeTransactionForRead(realm ->
realm.where(RealmRoom.class).equalTo(RealmRoom.ROOM_ID, roomId).findFirst()); realm.where(RealmRoom.class).equalTo(RealmRoom.ROOM_ID, roomId).findFirst());
if (room == null) { if (room == null) {
rocketChatCache.setSelectedRoomId(null); RocketChatCache.INSTANCE.setSelectedRoomId(null);
return false; return false;
} }
return true; return true;
...@@ -184,8 +183,8 @@ abstract class AbstractAuthedActivity extends AbstractFragmentActivity { ...@@ -184,8 +183,8 @@ abstract class AbstractAuthedActivity extends AbstractFragmentActivity {
ConnectivityManager.getInstance(getApplicationContext()).keepAliveServer(); ConnectivityManager.getInstance(getApplicationContext()).keepAliveServer();
if (isNotification) { if (isNotification) {
updateHostnameIfNeeded(rocketChatCache.getSelectedServerHostname()); updateHostnameIfNeeded(RocketChatCache.INSTANCE.getSelectedServerHostname());
updateRoomIdIfNeeded(rocketChatCache.getSelectedRoomId()); updateRoomIdIfNeeded(RocketChatCache.INSTANCE.getSelectedRoomId());
isNotification = false; isNotification = false;
} }
} }
...@@ -204,26 +203,26 @@ abstract class AbstractAuthedActivity extends AbstractFragmentActivity { ...@@ -204,26 +203,26 @@ abstract class AbstractAuthedActivity extends AbstractFragmentActivity {
private void subscribeToConfigChanges() { private void subscribeToConfigChanges() {
compositeDisposable.add( compositeDisposable.add(
rocketChatCache.getSelectedServerHostnamePublisher() RocketChatCache.INSTANCE.getSelectedServerHostnamePublisher()
.map(Optional::get) .map(Optional::get)
.distinctUntilChanged() .distinctUntilChanged()
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe( .subscribe(
this::updateHostnameIfNeeded, this::updateHostnameIfNeeded,
Logger::report Logger.INSTANCE::report
) )
); );
compositeDisposable.add( compositeDisposable.add(
rocketChatCache.getSelectedRoomIdPublisher() RocketChatCache.INSTANCE.getSelectedRoomIdPublisher()
.filter(Optional::isPresent) .filter(Optional::isPresent)
.map(Optional::get) .map(Optional::get)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe( .subscribe(
this::updateRoomIdIfNeeded, this::updateRoomIdIfNeeded,
Logger::report Logger.INSTANCE::report
) )
); );
} }
......
...@@ -8,6 +8,7 @@ import android.support.v4.app.Fragment; ...@@ -8,6 +8,7 @@ import android.support.v4.app.Fragment;
import chat.rocket.android.R; import chat.rocket.android.R;
import chat.rocket.android.fragment.server_config.LoginFragment; import chat.rocket.android.fragment.server_config.LoginFragment;
import chat.rocket.android.fragment.server_config.RetryLoginFragment; import chat.rocket.android.fragment.server_config.RetryLoginFragment;
import chat.rocket.android.helper.BackStackHelper;
import chat.rocket.android.service.ConnectivityManager; import chat.rocket.android.service.ConnectivityManager;
import chat.rocket.core.interactors.SessionInteractor; import chat.rocket.core.interactors.SessionInteractor;
import chat.rocket.persistence.realm.repositories.RealmSessionRepository; import chat.rocket.persistence.realm.repositories.RealmSessionRepository;
...@@ -89,4 +90,17 @@ public class LoginActivity extends AbstractFragmentActivity implements LoginCont ...@@ -89,4 +90,17 @@ public class LoginActivity extends AbstractFragmentActivity implements LoginCont
finish(); finish();
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out); overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
} }
@Override
protected boolean onBackPress() {
if (BackStackHelper.FRAGMENT_TAG.equals("internal")) {
super.onBackPress();
BackStackHelper.FRAGMENT_TAG = "login";
} else if (BackStackHelper.FRAGMENT_TAG.equals("login")) {
LoginFragment loginFragment = (LoginFragment) getSupportFragmentManager()
.findFragmentById(getLayoutContainerForFragment());
loginFragment.goBack();
}
return true;
}
} }
...@@ -66,7 +66,7 @@ public class LoginPresenter extends BasePresenter<LoginContract.View> ...@@ -66,7 +66,7 @@ public class LoginPresenter extends BasePresenter<LoginContract.View>
view.closeView(); view.closeView();
} }
}, },
Logger::report Logger.INSTANCE::report
); );
addSubscription(subscription); addSubscription(subscription);
......
...@@ -40,6 +40,6 @@ public interface MainContract { ...@@ -40,6 +40,6 @@ public interface MainContract {
void loadSignedInServers(String hostname); void loadSignedInServers(String hostname);
void beforeLogoutCleanUp(); void prepareToLogout();
} }
} }
...@@ -28,6 +28,7 @@ import chat.rocket.core.models.Session; ...@@ -28,6 +28,7 @@ import chat.rocket.core.models.Session;
import chat.rocket.core.models.User; import chat.rocket.core.models.User;
import chat.rocket.core.repositories.PublicSettingRepository; import chat.rocket.core.repositories.PublicSettingRepository;
import chat.rocket.core.utils.Pair; import chat.rocket.core.utils.Pair;
import hugo.weaving.DebugLog;
import io.reactivex.Flowable; import io.reactivex.Flowable;
import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable; import io.reactivex.disposables.Disposable;
...@@ -40,7 +41,6 @@ public class MainPresenter extends BasePresenter<MainContract.View> ...@@ -40,7 +41,6 @@ public class MainPresenter extends BasePresenter<MainContract.View>
private final SessionInteractor sessionInteractor; private final SessionInteractor sessionInteractor;
private final MethodCallHelper methodCallHelper; private final MethodCallHelper methodCallHelper;
private final ConnectivityManagerApi connectivityManagerApi; private final ConnectivityManagerApi connectivityManagerApi;
private final RocketChatCache rocketChatCache;
private final PublicSettingRepository publicSettingRepository; private final PublicSettingRepository publicSettingRepository;
public MainPresenter(RoomInteractor roomInteractor, public MainPresenter(RoomInteractor roomInteractor,
...@@ -48,13 +48,12 @@ public class MainPresenter extends BasePresenter<MainContract.View> ...@@ -48,13 +48,12 @@ public class MainPresenter extends BasePresenter<MainContract.View>
SessionInteractor sessionInteractor, SessionInteractor sessionInteractor,
MethodCallHelper methodCallHelper, MethodCallHelper methodCallHelper,
ConnectivityManagerApi connectivityManagerApi, ConnectivityManagerApi connectivityManagerApi,
RocketChatCache rocketChatCache, PublicSettingRepository publicSettingRepository) { PublicSettingRepository publicSettingRepository) {
this.roomInteractor = roomInteractor; this.roomInteractor = roomInteractor;
this.canCreateRoomInteractor = canCreateRoomInteractor; this.canCreateRoomInteractor = canCreateRoomInteractor;
this.sessionInteractor = sessionInteractor; this.sessionInteractor = sessionInteractor;
this.methodCallHelper = methodCallHelper; this.methodCallHelper = methodCallHelper;
this.connectivityManagerApi = connectivityManagerApi; this.connectivityManagerApi = connectivityManagerApi;
this.rocketChatCache = rocketChatCache;
this.publicSettingRepository = publicSettingRepository; this.publicSettingRepository = publicSettingRepository;
} }
...@@ -96,12 +95,13 @@ public class MainPresenter extends BasePresenter<MainContract.View> ...@@ -96,12 +95,13 @@ public class MainPresenter extends BasePresenter<MainContract.View>
subscribeToNetworkChanges(); subscribeToNetworkChanges();
subscribeToUnreadCount(); subscribeToUnreadCount();
subscribeToSession(); subscribeToSession();
setUserOnline();
} }
@Override @Override
public void release() { public void release() {
if (RocketChatCache.INSTANCE.getSessionToken() != null) {
setUserAway(); setUserAway();
}
super.release(); super.release();
} }
...@@ -119,7 +119,7 @@ public class MainPresenter extends BasePresenter<MainContract.View> ...@@ -119,7 +119,7 @@ public class MainPresenter extends BasePresenter<MainContract.View>
view.showHome(); view.showHome();
} }
}, },
Logger::report Logger.INSTANCE::report
); );
addSubscription(subscription); addSubscription(subscription);
...@@ -133,8 +133,9 @@ public class MainPresenter extends BasePresenter<MainContract.View> ...@@ -133,8 +133,9 @@ public class MainPresenter extends BasePresenter<MainContract.View>
addSubscription(subscription); addSubscription(subscription);
} }
@DebugLog
@Override @Override
public void beforeLogoutCleanUp() { public void prepareToLogout() {
clearSubscriptions(); clearSubscriptions();
} }
...@@ -155,13 +156,13 @@ public class MainPresenter extends BasePresenter<MainContract.View> ...@@ -155,13 +156,13 @@ public class MainPresenter extends BasePresenter<MainContract.View>
String logoUrl = (jsonObject.has("url")) ? String logoUrl = (jsonObject.has("url")) ?
jsonObject.optString("url") : jsonObject.optString("defaultUrl"); jsonObject.optString("url") : jsonObject.optString("defaultUrl");
String siteName = serverInfoPair.second; String siteName = serverInfoPair.second;
rocketChatCache.addHostname(hostname.toLowerCase(), logoUrl, siteName); RocketChatCache.INSTANCE.addHostname(hostname.toLowerCase(), logoUrl, siteName);
return rocketChatCache.getServerList(); return RocketChatCache.INSTANCE.getServerList();
} }
private void openRoom() { private void openRoom() {
String hostname = rocketChatCache.getSelectedServerHostname(); String hostname = RocketChatCache.INSTANCE.getSelectedServerHostname();
String roomId = rocketChatCache.getSelectedRoomId(); String roomId = RocketChatCache.INSTANCE.getSelectedRoomId();
if (roomId == null || roomId.length() == 0) { if (roomId == null || roomId.length() == 0) {
view.showHome(); view.showHome();
...@@ -181,7 +182,7 @@ public class MainPresenter extends BasePresenter<MainContract.View> ...@@ -181,7 +182,7 @@ public class MainPresenter extends BasePresenter<MainContract.View>
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe( .subscribe(
pair -> view.showUnreadCount(pair.first, pair.second), pair -> view.showUnreadCount(pair.first, pair.second),
Logger::report Logger.INSTANCE::report
); );
addSubscription(subscription); addSubscription(subscription);
...@@ -209,10 +210,11 @@ public class MainPresenter extends BasePresenter<MainContract.View> ...@@ -209,10 +210,11 @@ public class MainPresenter extends BasePresenter<MainContract.View>
view.showConnecting(); view.showConnecting();
return; return;
} }
// TODO: Should we remove below and above calls to view?
view.showConnectionOk(); // view.showConnectionOk();
RocketChatCache.INSTANCE.setSessionToken(session.getToken());
}, },
Logger::report Logger.INSTANCE::report
); );
addSubscription(subscription); addSubscription(subscription);
...@@ -225,17 +227,21 @@ public class MainPresenter extends BasePresenter<MainContract.View> ...@@ -225,17 +227,21 @@ public class MainPresenter extends BasePresenter<MainContract.View>
.subscribe( .subscribe(
connectivity -> { connectivity -> {
if (connectivity.state == ServerConnectivity.STATE_CONNECTED) { if (connectivity.state == ServerConnectivity.STATE_CONNECTED) {
view.showConnectionOk(); //TODO: notify almost connected or something like that.
view.refreshRoom(); // view.showConnectionOk();
} else if (connectivity.state == ServerConnectivity.STATE_DISCONNECTED) { } else if (connectivity.state == ServerConnectivity.STATE_DISCONNECTED) {
if (connectivity.code == DDPClient.REASON_NETWORK_ERROR) { if (connectivity.code == DDPClient.REASON_NETWORK_ERROR) {
view.showConnectionError(); view.showConnectionError();
} }
} else if (connectivity.state == ServerConnectivity.STATE_SESSION_ESTABLISHED) {
setUserOnline();
view.refreshRoom();
view.showConnectionOk();
} else { } else {
view.showConnecting(); view.showConnecting();
} }
}, },
Logger::report RCLog::e
); );
addSubscription(disposable); addSubscription(disposable);
......
...@@ -7,6 +7,7 @@ import org.json.JSONArray; ...@@ -7,6 +7,7 @@ import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import java.util.Iterator;
import java.util.UUID; import java.util.UUID;
import bolts.Continuation; import bolts.Continuation;
...@@ -14,6 +15,7 @@ import bolts.Task; ...@@ -14,6 +15,7 @@ import bolts.Task;
import chat.rocket.android.RocketChatCache; import chat.rocket.android.RocketChatCache;
import chat.rocket.android.helper.CheckSum; import chat.rocket.android.helper.CheckSum;
import chat.rocket.android.helper.TextUtils; import chat.rocket.android.helper.TextUtils;
import chat.rocket.android.log.RCLog;
import chat.rocket.android.service.ConnectivityManager; import chat.rocket.android.service.ConnectivityManager;
import chat.rocket.android_ddp.DDPClient; import chat.rocket.android_ddp.DDPClient;
import chat.rocket.android_ddp.DDPClientCallback; import chat.rocket.android_ddp.DDPClientCallback;
...@@ -32,11 +34,12 @@ import chat.rocket.persistence.realm.models.ddp.RealmSpotlightUser; ...@@ -32,11 +34,12 @@ import chat.rocket.persistence.realm.models.ddp.RealmSpotlightUser;
import chat.rocket.persistence.realm.models.internal.MethodCall; import chat.rocket.persistence.realm.models.internal.MethodCall;
import chat.rocket.persistence.realm.models.internal.RealmSession; import chat.rocket.persistence.realm.models.internal.RealmSession;
import hugo.weaving.DebugLog; import hugo.weaving.DebugLog;
import io.realm.RealmQuery;
import okhttp3.HttpUrl; import okhttp3.HttpUrl;
/** /**
* Utility class for creating/handling MethodCall or RPC. * Utility class for creating/handling MethodCall or RPC.
* * <p>
* TODO: separate method into several manager classes (SubscriptionManager, MessageManager, ...). * TODO: separate method into several manager classes (SubscriptionManager, MessageManager, ...).
*/ */
public class MethodCallHelper { public class MethodCallHelper {
...@@ -115,7 +118,7 @@ public class MethodCallHelper { ...@@ -115,7 +118,7 @@ public class MethodCallHelper {
} else if (exception instanceof DDPClientCallback.RPC.Timeout) { } else if (exception instanceof DDPClientCallback.RPC.Timeout) {
return Task.forError(new MethodCall.Timeout()); return Task.forError(new MethodCall.Timeout());
} else if (exception instanceof DDPClientCallback.Closed) { } else if (exception instanceof DDPClientCallback.Closed) {
return Task.forError(new Exception("Oops, your connection seems off...")); return Task.forError(new Exception(exception.getMessage()));
} else { } else {
return Task.forError(exception); return Task.forError(exception);
} }
...@@ -299,6 +302,27 @@ public class MethodCallHelper { ...@@ -299,6 +302,27 @@ public class MethodCallHelper {
realm.delete(RealmRoom.class); realm.delete(RealmRoom.class);
realm.createOrUpdateAllFromJson( realm.createOrUpdateAllFromJson(
RealmRoom.class, result); RealmRoom.class, result);
JSONObject openedRooms = RocketChatCache.INSTANCE.getOpenedRooms();
RealmQuery<RealmRoom> query = realm.where(RealmRoom.class);
Iterator<String> keys = openedRooms.keys();
while (keys.hasNext()) {
String rid = keys.next();
RealmRoom realmRoom = query.equalTo(RealmRoom.ID, rid).findFirst();
if (realmRoom == null) {
RocketChatCache.INSTANCE.removeOpenedRoom(rid);
} else {
loadMissedMessages(rid, realmRoom.getLastSeen())
.continueWithTask(task1 -> {
if (task1.isFaulted()) {
Exception error = task1.getError();
RCLog.e(error);
}
return null;
});
}
}
return null; return null;
}); });
} catch (JSONException exception) { } catch (JSONException exception) {
...@@ -307,6 +331,32 @@ public class MethodCallHelper { ...@@ -307,6 +331,32 @@ public class MethodCallHelper {
}); });
} }
public Task<JSONArray> loadMissedMessages(final String roomId, final long timestamp) {
return call("loadMissedMessages", TIMEOUT_MS, () -> new JSONArray()
.put(roomId)
.put(timestamp > 0 ? new JSONObject().put("$date", timestamp) : JSONObject.NULL)
).onSuccessTask(CONVERT_TO_JSON_ARRAY)
.onSuccessTask(task -> {
JSONArray result = task.getResult();
for (int i = 0; i < result.length(); i++) {
RealmMessage.customizeJson(result.getJSONObject(i));
}
return realmHelper.executeTransaction(realm -> {
if (timestamp == 0) {
realm.where(RealmMessage.class)
.equalTo("rid", roomId)
.equalTo("syncstate", SyncState.SYNCED)
.findAll().deleteAllFromRealm();
}
if (result.length() > 0) {
realm.createOrUpdateAllFromJson(RealmMessage.class, result);
}
return null;
}).onSuccessTask(_task -> Task.forResult(result));
});
}
/** /**
* Load messages for room. * Load messages for room.
*/ */
...@@ -406,7 +456,7 @@ public class MethodCallHelper { ...@@ -406,7 +456,7 @@ public class MethodCallHelper {
.put("_id", messageID); .put("_id", messageID);
return deleteMessage(messageJson); return deleteMessage(messageJson);
} catch(JSONException exception) { } catch (JSONException exception) {
return Task.forError(exception); return Task.forError(exception);
} }
} }
...@@ -458,9 +508,8 @@ public class MethodCallHelper { ...@@ -458,9 +508,8 @@ public class MethodCallHelper {
HttpUrl httpSiteUrl = HttpUrl.parse(siteUrl); HttpUrl httpSiteUrl = HttpUrl.parse(siteUrl);
if (httpSiteUrl != null) { if (httpSiteUrl != null) {
String host = httpSiteUrl.host(); String host = httpSiteUrl.host();
RocketChatCache rocketChatCache = new RocketChatCache(context); RocketChatCache.INSTANCE.addSiteUrl(host, currentHostname);
rocketChatCache.addHostnameSiteUrl(host, currentHostname); RocketChatCache.INSTANCE.addSiteName(currentHostname, siteName);
rocketChatCache.addHostSiteName(currentHostname, siteName);
} }
} }
......
...@@ -8,11 +8,6 @@ import chat.rocket.persistence.realm.models.internal.RealmSession; ...@@ -8,11 +8,6 @@ import chat.rocket.persistence.realm.models.internal.RealmSession;
public class DefaultCookieProvider implements CookieProvider { public class DefaultCookieProvider implements CookieProvider {
private RocketChatCache rocketChatCache;
public DefaultCookieProvider(RocketChatCache rocketChatCache) {
this.rocketChatCache = rocketChatCache;
}
@Override @Override
public String getHostname() { public String getHostname() {
...@@ -44,6 +39,6 @@ public class DefaultCookieProvider implements CookieProvider { ...@@ -44,6 +39,6 @@ public class DefaultCookieProvider implements CookieProvider {
} }
private String getHostnameFromCache() { private String getHostnameFromCache() {
return rocketChatCache.getSelectedServerHostname(); return RocketChatCache.INSTANCE.getSelectedServerHostname();
} }
} }
package chat.rocket.android.api.rest package chat.rocket.android.api.rest
import chat.rocket.android.R
import chat.rocket.android.RocketChatApplication
import chat.rocket.android.helper.UrlHelper import chat.rocket.android.helper.UrlHelper
import chat.rocket.android.push.gcm.GcmPushHelper
import chat.rocket.core.models.Room import chat.rocket.core.models.Room
import com.google.android.gms.gcm.GoogleCloudMessaging
import com.google.android.gms.iid.InstanceID
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.MediaType
import okhttp3.Request import okhttp3.Request
import okhttp3.RequestBody
import org.json.JSONObject
import java.io.IOException
/** /**
* Helper class for dealing with Rest API calls. * Helper class for dealing with Rest API calls.
...@@ -139,6 +148,30 @@ object RestApiHelper { ...@@ -139,6 +148,30 @@ object RestApiHelper {
.build() .build()
} }
fun getRequestForPushTokenRegistration(hostname: String,
token: String,
userId: String): Request {
val parsedHttpUrl = HttpUrl.parse(getEndpointUrlForPushToken(hostname))
?.newBuilder()
?.build()
val json = JSONObject()
.put("type", "gcm")
.put("appName", "main")
.put("value", GcmPushHelper.getGcmToken())
val requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"),
json.toString())
return Request.Builder()
.url(parsedHttpUrl)
.post(requestBody)
.addHeader("X-Auth-Token", token)
.addHeader("X-User-Id", userId)
.addHeader("Content-Type", "application/json")
.build()
}
/** /**
* Returns a Rest API endpoint URL for favorite or pinned messages accordingly with the room type and the server hostname. * Returns a Rest API endpoint URL for favorite or pinned messages accordingly with the room type and the server hostname.
* *
...@@ -169,6 +202,9 @@ object RestApiHelper { ...@@ -169,6 +202,9 @@ object RestApiHelper {
fun getEndpointUrlForMemberList(roomType: String, hostname: String): String = fun getEndpointUrlForMemberList(roomType: String, hostname: String): String =
UrlHelper.getSafeHostname(hostname) + getRestApiUrlForMemberList(roomType) UrlHelper.getSafeHostname(hostname) + getRestApiUrlForMemberList(roomType)
fun getEndpointUrlForPushToken(hostname: String): String =
UrlHelper.getSafeHostname(hostname) + getRestApiUrlForPushToken()
/** /**
* Returns the correspondent Rest API URL accordingly with the room type to get its favorite or pinned messages. * Returns the correspondent Rest API URL accordingly with the room type to get its favorite or pinned messages.
* *
...@@ -216,4 +252,21 @@ object RestApiHelper { ...@@ -216,4 +252,21 @@ object RestApiHelper {
} }
return restApiUrl return restApiUrl
} }
/**
* Returns the correspondent Rest API URL for registration/deletion of Gcm Registration token.
*/
fun getRestApiUrlForPushToken(): String {
return "/api/v1/push.token"
}
@Throws(IOException::class)
private fun getGcmToken(senderId: String): String {
return InstanceID.getInstance(RocketChatApplication.getInstance())
.getToken(senderId, GoogleCloudMessaging.INSTANCE_ID_SCOPE, null)
}
private fun getSenderId(): String {
return RocketChatApplication.getInstance().getString(R.string.gcm_sender_id)
}
} }
\ No newline at end of file
package chat.rocket.android.extensions
import chat.rocket.android.BuildConfig
fun Throwable.printStackTraceOnDebug() {
if (BuildConfig.DEBUG) {
this.printStackTrace()
}
}
\ No newline at end of file
...@@ -7,7 +7,7 @@ public interface InputHostnameContract { ...@@ -7,7 +7,7 @@ public interface InputHostnameContract {
interface View extends BaseContract.View { interface View extends BaseContract.View {
void showLoader(); void showLoader();
void hideLoader(); void hideLoader(Boolean isValidServerUrl);
void showInvalidServerError(); void showInvalidServerError();
......
...@@ -6,12 +6,12 @@ import android.support.annotation.Nullable; ...@@ -6,12 +6,12 @@ import android.support.annotation.Nullable;
import android.support.constraint.ConstraintLayout; import android.support.constraint.ConstraintLayout;
import android.support.design.widget.Snackbar; import android.support.design.widget.Snackbar;
import android.view.View; import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.TextView; import android.widget.TextView;
import chat.rocket.android.BuildConfig; import chat.rocket.android.BuildConfig;
import chat.rocket.android.LaunchUtil; import chat.rocket.android.LaunchUtil;
import chat.rocket.android.R; import chat.rocket.android.R;
import chat.rocket.android.RocketChatCache;
import chat.rocket.android.fragment.AbstractFragment; import chat.rocket.android.fragment.AbstractFragment;
import chat.rocket.android.helper.TextUtils; import chat.rocket.android.helper.TextUtils;
import chat.rocket.android.service.ConnectivityManager; import chat.rocket.android.service.ConnectivityManager;
...@@ -25,14 +25,15 @@ public class InputHostnameFragment extends AbstractFragment implements InputHost ...@@ -25,14 +25,15 @@ public class InputHostnameFragment extends AbstractFragment implements InputHost
private ConstraintLayout container; private ConstraintLayout container;
private View waitingView; private View waitingView;
public InputHostnameFragment() {} public InputHostnameFragment() {
}
@Override @Override
public void onCreate(@Nullable Bundle savedInstanceState) { public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
Context appContext = getContext().getApplicationContext(); Context appContext = getContext().getApplicationContext();
presenter = new InputHostnamePresenter(new RocketChatCache(appContext), ConnectivityManager.getInstance(appContext)); presenter = new InputHostnamePresenter(ConnectivityManager.getInstance(appContext));
} }
@Override @Override
...@@ -50,14 +51,22 @@ public class InputHostnameFragment extends AbstractFragment implements InputHost ...@@ -50,14 +51,22 @@ public class InputHostnameFragment extends AbstractFragment implements InputHost
} }
private void setupVersionInfo() { private void setupVersionInfo() {
TextView versionInfoView = (TextView) rootView.findViewById(R.id.version_info); TextView versionInfoView = rootView.findViewById(R.id.version_info);
versionInfoView.setText(getString(R.string.version_info_text, BuildConfig.VERSION_NAME)); versionInfoView.setText(getString(R.string.version_info_text, BuildConfig.VERSION_NAME));
} }
private void handleConnect() { private void handleConnect() {
hideSoftKeyboard();
presenter.connectTo(getHostname()); presenter.connectTo(getHostname());
} }
private void hideSoftKeyboard() {
InputMethodManager inputManager = (InputMethodManager)
getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
inputManager.hideSoftInputFromWindow(getActivity().getCurrentFocus().getWindowToken(),
InputMethodManager.HIDE_NOT_ALWAYS);
}
@Override @Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState); super.onViewCreated(view, savedInstanceState);
...@@ -87,10 +96,12 @@ public class InputHostnameFragment extends AbstractFragment implements InputHost ...@@ -87,10 +96,12 @@ public class InputHostnameFragment extends AbstractFragment implements InputHost
} }
@Override @Override
public void hideLoader() { public void hideLoader(Boolean isValidServerUrl) {
if(!isValidServerUrl) {
waitingView.setVisibility(View.GONE); waitingView.setVisibility(View.GONE);
container.setVisibility(View.VISIBLE); container.setVisibility(View.VISIBLE);
} }
}
@Override @Override
public void showInvalidServerError() { public void showInvalidServerError() {
......
...@@ -14,11 +14,10 @@ import io.reactivex.android.schedulers.AndroidSchedulers; ...@@ -14,11 +14,10 @@ import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable; import io.reactivex.disposables.Disposable;
public class InputHostnamePresenter extends BasePresenter<InputHostnameContract.View> implements InputHostnameContract.Presenter { public class InputHostnamePresenter extends BasePresenter<InputHostnameContract.View> implements InputHostnameContract.Presenter {
private final RocketChatCache rocketChatCache;
private final ConnectivityManagerApi connectivityManager; private final ConnectivityManagerApi connectivityManager;
private boolean isValidServerUrl;
public InputHostnamePresenter(RocketChatCache rocketChatCache, ConnectivityManagerApi connectivityManager) { public InputHostnamePresenter(ConnectivityManagerApi connectivityManager) {
this.rocketChatCache = rocketChatCache;
this.connectivityManager = connectivityManager; this.connectivityManager = connectivityManager;
} }
...@@ -37,24 +36,25 @@ public class InputHostnamePresenter extends BasePresenter<InputHostnameContract. ...@@ -37,24 +36,25 @@ public class InputHostnamePresenter extends BasePresenter<InputHostnameContract.
final Disposable subscription = ServerPolicyHelper.isApiVersionValid(validationHelper) final Disposable subscription = ServerPolicyHelper.isApiVersionValid(validationHelper)
.subscribeOn(AndroidSchedulers.from(BackgroundLooper.get())) .subscribeOn(AndroidSchedulers.from(BackgroundLooper.get()))
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.doOnTerminate(() -> view.hideLoader()) .doOnTerminate(() -> view.hideLoader(isValidServerUrl))
.subscribe( .subscribe(
serverValidation -> { serverValidation -> {
if (serverValidation.isValid()) { if (serverValidation.isValid()) {
isValidServerUrl=true;
onServerValid(hostname, serverValidation.usesSecureConnection()); onServerValid(hostname, serverValidation.usesSecureConnection());
} else { } else {
view.showInvalidServerError(); view.showInvalidServerError();
} }
}, },
throwable -> { throwable -> {
Logger.report(throwable); Logger.INSTANCE.report(throwable);
view.showConnectionError(); view.showConnectionError();
}); });
addSubscription(subscription); addSubscription(subscription);
} }
private void onServerValid(String hostname, boolean usesSecureConnection) { private void onServerValid(String hostname, boolean usesSecureConnection) {
rocketChatCache.setSelectedServerHostname(hostname); RocketChatCache.INSTANCE.setSelectedServerHostname(hostname);
String server = hostname.replace("/", "."); String server = hostname.replace("/", ".");
connectivityManager.addOrUpdateServer(server, server, !usesSecureConnection); connectivityManager.addOrUpdateServer(server, server, !usesSecureConnection);
......
...@@ -11,7 +11,7 @@ import chat.rocket.android.fragment.AbstractFragment; ...@@ -11,7 +11,7 @@ import chat.rocket.android.fragment.AbstractFragment;
import chat.rocket.android.widget.RoomToolbar; import chat.rocket.android.widget.RoomToolbar;
import chat.rocket.core.models.User; import chat.rocket.core.models.User;
abstract class AbstractChatRoomFragment extends AbstractFragment { public abstract class AbstractChatRoomFragment extends AbstractFragment {
private RoomToolbar roomToolbar; private RoomToolbar roomToolbar;
@Nullable @Nullable
......
package chat.rocket.android.fragment.chatroom;
import chat.rocket.android.R;
public class HomeFragment extends AbstractChatRoomFragment {
public HomeFragment() {}
@Override
protected int getLayout() {
return R.layout.fragment_home;
}
@Override
protected void onSetupView() {
setToolbarTitle(getText(R.string.home_fragment_title));
}
}
\ No newline at end of file
package chat.rocket.android.fragment.chatroom
import chat.rocket.android.R
class HomeFragment : AbstractChatRoomFragment() {
override fun getLayout(): Int {
return R.layout.fragment_home
}
override fun onSetupView() {
setToolbarTitle(getText(R.string.home_fragment_title))
}
}
\ No newline at end of file
package chat.rocket.android.fragment.chatroom;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import java.util.List;
import chat.rocket.android.shared.BaseContract;
import chat.rocket.android.widget.AbsoluteUrl;
import chat.rocket.core.models.Message;
import chat.rocket.core.models.Room;
import chat.rocket.core.models.User;
public interface RoomContract {
interface View extends BaseContract.View {
void setupWith(RocketChatAbsoluteUrl rocketChatAbsoluteUrl);
void render(Room room);
void showUserStatus(User user);
void updateHistoryState(boolean hasNext, boolean isLoaded);
void onMessageSendSuccessfully();
void disableMessageInput();
void enableMessageInput();
void showUnreadCount(int count);
void showMessages(List<Message> messages);
void showMessageSendFailure(Message message);
void showMessageDeleteFailure(Message message);
void autoloadImages();
void manualLoadImages();
void onReply(AbsoluteUrl absoluteUrl, String markdown, Message message);
void onCopy(String message);
void showMessageActions(Message message);
}
interface Presenter extends BaseContract.Presenter<View> {
void loadMessages();
void loadMoreMessages();
void onMessageSelected(@Nullable Message message);
void onMessageTap(@Nullable Message message);
void sendMessage(String messageText);
void resendMessage(@NonNull Message message);
void updateMessage(@NonNull Message message, String content);
void deleteMessage(@NonNull Message message);
void onUnreadCount();
void onMarkAsRead();
void refreshRoom();
void replyMessage(@NonNull Message message, boolean justQuote);
void acceptMessageDeleteFailure(Message message);
}
}
package chat.rocket.android.fragment.chatroom
import chat.rocket.android.shared.BaseContract
import chat.rocket.android.widget.AbsoluteUrl
import chat.rocket.core.models.Message
import chat.rocket.core.models.Room
import chat.rocket.core.models.User
interface RoomContract {
interface View : BaseContract.View {
fun setupWith(rocketChatAbsoluteUrl: RocketChatAbsoluteUrl)
fun render(room: Room)
fun showUserStatus(user: User)
fun updateHistoryState(hasNext: Boolean, isLoaded: Boolean)
fun onMessageSendSuccessfully()
fun disableMessageInput()
fun enableMessageInput()
fun showUnreadCount(count: Int)
fun showMessages(messages: List<Message>)
fun showMessageSendFailure(message: Message)
fun showMessageDeleteFailure(message: Message)
fun autoloadImages()
fun manualLoadImages()
fun onReply(absoluteUrl: AbsoluteUrl, markdown: String, message: Message)
fun onCopy(message: String)
fun showMessageActions(message: Message)
}
interface Presenter : BaseContract.Presenter<View> {
fun loadMessages()
fun loadMoreMessages()
fun onMessageSelected(message: Message?)
fun onMessageTap(message: Message?)
fun sendMessage(messageText: String)
fun resendMessage(message: Message)
fun updateMessage(message: Message, content: String)
fun deleteMessage(message: Message)
fun onUnreadCount()
fun onMarkAsRead()
fun refreshRoom()
fun replyMessage(message: Message, justQuote: Boolean)
fun acceptMessageDeleteFailure(message: Message)
fun loadMissedMessages()
}
}
...@@ -131,7 +131,7 @@ public class RoomFragment extends AbstractChatRoomFragment implements ...@@ -131,7 +131,7 @@ public class RoomFragment extends AbstractChatRoomFragment implements
private MethodCallHelper methodCallHelper; private MethodCallHelper methodCallHelper;
private AbsoluteUrlHelper absoluteUrlHelper; private AbsoluteUrlHelper absoluteUrlHelper;
private Message edittingMessage = null; private Message editingMessage = null;
private RoomToolbar toolbar; private RoomToolbar toolbar;
...@@ -344,7 +344,7 @@ public class RoomFragment extends AbstractChatRoomFragment implements ...@@ -344,7 +344,7 @@ public class RoomFragment extends AbstractChatRoomFragment implements
optionalPane.ifPresent(pane -> pane.setPanelSlideListener(new SlidingPaneLayout.PanelSlideListener() { optionalPane.ifPresent(pane -> pane.setPanelSlideListener(new SlidingPaneLayout.PanelSlideListener() {
@Override @Override
public void onPanelSlide(View view, float v) { public void onPanelSlide(@NonNull View view, float v) {
messageFormManager.enableComposingText(false); messageFormManager.enableComposingText(false);
sidebarFragment.clearSearchViewFocus(); sidebarFragment.clearSearchViewFocus();
//Ref: ActionBarDrawerToggle#setProgress //Ref: ActionBarDrawerToggle#setProgress
...@@ -352,12 +352,12 @@ public class RoomFragment extends AbstractChatRoomFragment implements ...@@ -352,12 +352,12 @@ public class RoomFragment extends AbstractChatRoomFragment implements
} }
@Override @Override
public void onPanelOpened(View view) { public void onPanelOpened(@NonNull View view) {
toolbar.setNavigationIconVerticalMirror(true); toolbar.setNavigationIconVerticalMirror(true);
} }
@Override @Override
public void onPanelClosed(View view) { public void onPanelClosed(@NonNull View view) {
messageFormManager.enableComposingText(true); messageFormManager.enableComposingText(true);
toolbar.setNavigationIconVerticalMirror(false); toolbar.setNavigationIconVerticalMirror(false);
subPane.closePane(); subPane.closePane();
...@@ -487,8 +487,8 @@ public class RoomFragment extends AbstractChatRoomFragment implements ...@@ -487,8 +487,8 @@ public class RoomFragment extends AbstractChatRoomFragment implements
@Override @Override
public boolean onBackPressed() { public boolean onBackPressed() {
if (edittingMessage != null) { if (editingMessage != null) {
edittingMessage = null; editingMessage = null;
messageFormManager.clearComposingText(); messageFormManager.clearComposingText();
} }
return false; return false;
...@@ -540,22 +540,22 @@ public class RoomFragment extends AbstractChatRoomFragment implements ...@@ -540,22 +540,22 @@ public class RoomFragment extends AbstractChatRoomFragment implements
inputContentInfo.releasePermission(); inputContentInfo.releasePermission();
} catch (Exception e) { } catch (Exception e) {
RCLog.e(e); RCLog.e(e);
Logger.report(e); Logger.INSTANCE.report(e);
} }
return true; return true;
} }
private void sendMessage(String messageText) { private void sendMessage(String messageText) {
if (edittingMessage == null) { if (editingMessage == null) {
presenter.sendMessage(messageText); presenter.sendMessage(messageText);
} else { } else {
presenter.updateMessage(edittingMessage, messageText); presenter.updateMessage(editingMessage, messageText);
} }
} }
@Override @Override
public void setupWith(RocketChatAbsoluteUrl rocketChatAbsoluteUrl) { public void setupWith(@NonNull RocketChatAbsoluteUrl rocketChatAbsoluteUrl) {
if (rocketChatAbsoluteUrl != null) { if (rocketChatAbsoluteUrl != null) {
token = rocketChatAbsoluteUrl.getToken(); token = rocketChatAbsoluteUrl.getToken();
userId = rocketChatAbsoluteUrl.getUserId(); userId = rocketChatAbsoluteUrl.getUserId();
...@@ -564,7 +564,7 @@ public class RoomFragment extends AbstractChatRoomFragment implements ...@@ -564,7 +564,7 @@ public class RoomFragment extends AbstractChatRoomFragment implements
} }
@Override @Override
public void render(Room room) { public void render(@NonNull Room room) {
roomType = room.getType(); roomType = room.getType();
setToolbarTitle(room.getName()); setToolbarTitle(room.getName());
...@@ -589,7 +589,7 @@ public class RoomFragment extends AbstractChatRoomFragment implements ...@@ -589,7 +589,7 @@ public class RoomFragment extends AbstractChatRoomFragment implements
} }
@Override @Override
public void showUserStatus(User user) { public void showUserStatus(@NonNull User user) {
showToolbarUserStatuslIcon(user.getStatus()); showToolbarUserStatuslIcon(user.getStatus());
} }
...@@ -610,7 +610,7 @@ public class RoomFragment extends AbstractChatRoomFragment implements ...@@ -610,7 +610,7 @@ public class RoomFragment extends AbstractChatRoomFragment implements
public void onMessageSendSuccessfully() { public void onMessageSendSuccessfully() {
scrollToLatestMessage(); scrollToLatestMessage();
messageFormManager.onMessageSend(); messageFormManager.onMessageSend();
edittingMessage = null; editingMessage = null;
} }
@Override @Override
...@@ -629,15 +629,16 @@ public class RoomFragment extends AbstractChatRoomFragment implements ...@@ -629,15 +629,16 @@ public class RoomFragment extends AbstractChatRoomFragment implements
} }
@Override @Override
public void showMessages(List<Message> messages) { public void showMessages(@NonNull List<? extends Message> messages) {
if (messageListAdapter == null) { if (messageListAdapter == null) {
return; return;
} }
messageListAdapter.updateData(messages);
messageListAdapter.updateData((List<Message>) messages);
} }
@Override @Override
public void showMessageSendFailure(Message message) { public void showMessageSendFailure(@NonNull Message message) {
new AlertDialog.Builder(getContext()) new AlertDialog.Builder(getContext())
.setPositiveButton(R.string.resend, .setPositiveButton(R.string.resend,
(dialog, which) -> presenter.resendMessage(message)) (dialog, which) -> presenter.resendMessage(message))
...@@ -648,7 +649,7 @@ public class RoomFragment extends AbstractChatRoomFragment implements ...@@ -648,7 +649,7 @@ public class RoomFragment extends AbstractChatRoomFragment implements
} }
@Override @Override
public void showMessageDeleteFailure(Message message) { public void showMessageDeleteFailure(@NonNull Message message) {
new AlertDialog.Builder(getContext()) new AlertDialog.Builder(getContext())
.setTitle(getContext().getString(R.string.failed_to_delete)) .setTitle(getContext().getString(R.string.failed_to_delete))
.setMessage(getContext().getString(R.string.failed_to_delete_message)) .setMessage(getContext().getString(R.string.failed_to_delete_message))
...@@ -667,12 +668,12 @@ public class RoomFragment extends AbstractChatRoomFragment implements ...@@ -667,12 +668,12 @@ public class RoomFragment extends AbstractChatRoomFragment implements
} }
@Override @Override
public void onReply(AbsoluteUrl absoluteUrl, String markdown, Message message) { public void onReply(@NonNull AbsoluteUrl absoluteUrl, @NonNull String markdown, @NonNull Message message) {
messageFormManager.setReply(absoluteUrl, markdown, message); messageFormManager.setReply(absoluteUrl, markdown, message);
} }
@Override @Override
public void onCopy(String message) { public void onCopy(@NonNull String message) {
RocketChatApplication context = RocketChatApplication.getInstance(); RocketChatApplication context = RocketChatApplication.getInstance();
ClipboardManager clipboardManager = ClipboardManager clipboardManager =
(ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
...@@ -680,7 +681,7 @@ public class RoomFragment extends AbstractChatRoomFragment implements ...@@ -680,7 +681,7 @@ public class RoomFragment extends AbstractChatRoomFragment implements
} }
@Override @Override
public void showMessageActions(Message message) { public void showMessageActions(@NonNull Message message) {
Activity context = getActivity(); Activity context = getActivity();
if (context != null && context instanceof MainActivity) { if (context != null && context instanceof MainActivity) {
MessagePopup.take(message) MessagePopup.take(message)
...@@ -694,7 +695,7 @@ public class RoomFragment extends AbstractChatRoomFragment implements ...@@ -694,7 +695,7 @@ public class RoomFragment extends AbstractChatRoomFragment implements
} }
private void onEditMessage(Message message) { private void onEditMessage(Message message) {
edittingMessage = message; editingMessage = message;
messageFormManager.setEditMessage(message.getMessage()); messageFormManager.setEditMessage(message.getMessage());
} }
...@@ -716,7 +717,7 @@ public class RoomFragment extends AbstractChatRoomFragment implements ...@@ -716,7 +717,7 @@ public class RoomFragment extends AbstractChatRoomFragment implements
} }
} }
public void loadMessages() { public void loadMissedMessages() {
presenter.loadMessages(); presenter.loadMissedMessages();
} }
} }
\ No newline at end of file
...@@ -6,11 +6,17 @@ import android.support.v4.util.Pair; ...@@ -6,11 +6,17 @@ import android.support.v4.util.Pair;
import com.hadisatrio.optional.Optional; import com.hadisatrio.optional.Optional;
import org.json.JSONException;
import org.json.JSONObject;
import chat.rocket.android.BackgroundLooper; import chat.rocket.android.BackgroundLooper;
import chat.rocket.android.RocketChatApplication;
import chat.rocket.android.RocketChatCache;
import chat.rocket.android.api.MethodCallHelper; import chat.rocket.android.api.MethodCallHelper;
import chat.rocket.android.helper.AbsoluteUrlHelper; import chat.rocket.android.helper.AbsoluteUrlHelper;
import chat.rocket.android.helper.LogIfError; import chat.rocket.android.helper.LogIfError;
import chat.rocket.android.helper.Logger; import chat.rocket.android.helper.Logger;
import chat.rocket.android.log.RCLog;
import chat.rocket.android.service.ConnectivityManagerApi; import chat.rocket.android.service.ConnectivityManagerApi;
import chat.rocket.android.shared.BasePresenter; import chat.rocket.android.shared.BasePresenter;
import chat.rocket.core.SyncState; import chat.rocket.core.SyncState;
...@@ -21,6 +27,7 @@ import chat.rocket.core.models.Settings; ...@@ -21,6 +27,7 @@ import chat.rocket.core.models.Settings;
import chat.rocket.core.models.User; import chat.rocket.core.models.User;
import chat.rocket.core.repositories.RoomRepository; import chat.rocket.core.repositories.RoomRepository;
import chat.rocket.core.repositories.UserRepository; import chat.rocket.core.repositories.UserRepository;
import io.reactivex.Flowable;
import io.reactivex.Single; import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable; import io.reactivex.disposables.Disposable;
...@@ -37,7 +44,7 @@ public class RoomPresenter extends BasePresenter<RoomContract.View> ...@@ -37,7 +44,7 @@ public class RoomPresenter extends BasePresenter<RoomContract.View>
private final ConnectivityManagerApi connectivityManagerApi; private final ConnectivityManagerApi connectivityManagerApi;
private Room currentRoom; private Room currentRoom;
public RoomPresenter(String roomId, /* package */RoomPresenter(String roomId,
UserRepository userRepository, UserRepository userRepository,
MessageInteractor messageInteractor, MessageInteractor messageInteractor,
RoomRepository roomRepository, RoomRepository roomRepository,
...@@ -66,7 +73,6 @@ public class RoomPresenter extends BasePresenter<RoomContract.View> ...@@ -66,7 +73,6 @@ public class RoomPresenter extends BasePresenter<RoomContract.View>
getRoomHistoryStateInfo(); getRoomHistoryStateInfo();
getMessages(); getMessages();
getUserPreferences(); getUserPreferences();
getAbsoluteUrl();
} }
@Override @Override
...@@ -77,11 +83,11 @@ public class RoomPresenter extends BasePresenter<RoomContract.View> ...@@ -77,11 +83,11 @@ public class RoomPresenter extends BasePresenter<RoomContract.View>
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe( .subscribe(
success -> { success -> {
if (success) { if (!success) {
connectivityManagerApi.keepAliveServer(); connectivityManagerApi.keepAliveServer();
} }
}, },
Logger::report Logger.INSTANCE::report
); );
addSubscription(subscription); addSubscription(subscription);
...@@ -89,18 +95,17 @@ public class RoomPresenter extends BasePresenter<RoomContract.View> ...@@ -89,18 +95,17 @@ public class RoomPresenter extends BasePresenter<RoomContract.View>
@Override @Override
public void loadMoreMessages() { public void loadMoreMessages() {
final Disposable subscription = getSingleRoom() final Disposable subscription = getSingleRoom()
.flatMap(messageInteractor::loadMoreMessages) .flatMap(messageInteractor::loadMoreMessages)
.subscribeOn(AndroidSchedulers.from(BackgroundLooper.get())) .subscribeOn(AndroidSchedulers.from(BackgroundLooper.get()))
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe( .subscribe(
success -> { success -> {
if (success) { if (!success) {
connectivityManagerApi.keepAliveServer(); connectivityManagerApi.keepAliveServer();
} }
}, },
Logger::report Logger.INSTANCE::report
); );
addSubscription(subscription); addSubscription(subscription);
...@@ -135,7 +140,7 @@ public class RoomPresenter extends BasePresenter<RoomContract.View> ...@@ -135,7 +140,7 @@ public class RoomPresenter extends BasePresenter<RoomContract.View>
@Override @Override
public void replyMessage(@NonNull Message message, boolean justQuote) { public void replyMessage(@NonNull Message message, boolean justQuote) {
this.absoluteUrlHelper.getRocketChatAbsoluteUrl() final Disposable subscription = this.absoluteUrlHelper.getRocketChatAbsoluteUrl()
.cache() .cache()
.subscribeOn(AndroidSchedulers.from(BackgroundLooper.get())) .subscribeOn(AndroidSchedulers.from(BackgroundLooper.get()))
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
...@@ -147,8 +152,10 @@ public class RoomPresenter extends BasePresenter<RoomContract.View> ...@@ -147,8 +152,10 @@ public class RoomPresenter extends BasePresenter<RoomContract.View>
view.onReply(absoluteUrl, buildReplyOrQuoteMarkdown(baseUrl, message, justQuote), message); view.onReply(absoluteUrl, buildReplyOrQuoteMarkdown(baseUrl, message, justQuote), message);
} }
}, },
Logger::report Logger.INSTANCE::report
); );
addSubscription(subscription);
} }
public void acceptMessageDeleteFailure(Message message) { public void acceptMessageDeleteFailure(Message message) {
...@@ -160,6 +167,23 @@ public class RoomPresenter extends BasePresenter<RoomContract.View> ...@@ -160,6 +167,23 @@ public class RoomPresenter extends BasePresenter<RoomContract.View>
addSubscription(subscription); addSubscription(subscription);
} }
@Override
public void loadMissedMessages() {
RocketChatApplication appContext = RocketChatApplication.getInstance();
JSONObject openedRooms = RocketChatCache.INSTANCE.getOpenedRooms();
if (openedRooms.has(roomId)) {
try {
JSONObject room = openedRooms.getJSONObject(roomId);
String rid = room.optString("rid");
long ls = room.optLong("ls");
methodCallHelper.loadMissedMessages(rid, ls)
.continueWith(new LogIfError());
} catch (JSONException e) {
RCLog.e(e);
}
}
}
private String buildReplyOrQuoteMarkdown(String baseUrl, Message message, boolean justQuote) { private String buildReplyOrQuoteMarkdown(String baseUrl, Message message, boolean justQuote) {
if (currentRoom == null || message.getUser() == null) { if (currentRoom == null || message.getUser() == null) {
return ""; return "";
...@@ -193,7 +217,7 @@ public class RoomPresenter extends BasePresenter<RoomContract.View> ...@@ -193,7 +217,7 @@ public class RoomPresenter extends BasePresenter<RoomContract.View>
}, },
throwable -> { throwable -> {
view.enableMessageInput(); view.enableMessageInput();
Logger.report(throwable); Logger.INSTANCE.report(throwable);
} }
); );
...@@ -227,7 +251,7 @@ public class RoomPresenter extends BasePresenter<RoomContract.View> ...@@ -227,7 +251,7 @@ public class RoomPresenter extends BasePresenter<RoomContract.View>
}, },
throwable -> { throwable -> {
view.enableMessageInput(); view.enableMessageInput();
Logger.report(throwable); Logger.INSTANCE.report(throwable);
} }
); );
...@@ -253,7 +277,7 @@ public class RoomPresenter extends BasePresenter<RoomContract.View> ...@@ -253,7 +277,7 @@ public class RoomPresenter extends BasePresenter<RoomContract.View>
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe( .subscribe(
count -> view.showUnreadCount(count), count -> view.showUnreadCount(count),
Logger::report Logger.INSTANCE::report
); );
addSubscription(subscription); addSubscription(subscription);
...@@ -271,7 +295,7 @@ public class RoomPresenter extends BasePresenter<RoomContract.View> ...@@ -271,7 +295,7 @@ public class RoomPresenter extends BasePresenter<RoomContract.View>
.subscribe( .subscribe(
room -> methodCallHelper.readMessages(room.getRoomId()) room -> methodCallHelper.readMessages(room.getRoomId())
.continueWith(new LogIfError()), .continueWith(new LogIfError()),
Logger::report Logger.INSTANCE::report
); );
addSubscription(subscription); addSubscription(subscription);
...@@ -288,7 +312,7 @@ public class RoomPresenter extends BasePresenter<RoomContract.View> ...@@ -288,7 +312,7 @@ public class RoomPresenter extends BasePresenter<RoomContract.View>
.map(Optional::get) .map(Optional::get)
.subscribeOn(AndroidSchedulers.from(BackgroundLooper.get())) .subscribeOn(AndroidSchedulers.from(BackgroundLooper.get()))
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(this::processRoom, Logger::report); .subscribe(this::processRoom, Logger.INSTANCE::report);
addSubscription(subscription); addSubscription(subscription);
} }
...@@ -308,7 +332,7 @@ public class RoomPresenter extends BasePresenter<RoomContract.View> ...@@ -308,7 +332,7 @@ public class RoomPresenter extends BasePresenter<RoomContract.View>
.map(Optional::get) .map(Optional::get)
.subscribeOn(AndroidSchedulers.from(BackgroundLooper.get())) .subscribeOn(AndroidSchedulers.from(BackgroundLooper.get()))
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(view::showUserStatus, Logger::report); .subscribe(view::showUserStatus, Logger.INSTANCE::report);
addSubscription(disposable); addSubscription(disposable);
} }
...@@ -327,22 +351,33 @@ public class RoomPresenter extends BasePresenter<RoomContract.View> ...@@ -327,22 +351,33 @@ public class RoomPresenter extends BasePresenter<RoomContract.View>
syncState == SyncState.SYNCED || syncState == SyncState.FAILED syncState == SyncState.SYNCED || syncState == SyncState.FAILED
); );
}, },
Logger::report Logger.INSTANCE::report
); );
addSubscription(subscription); addSubscription(subscription);
} }
private void getMessages() { private void getMessages() {
final Disposable subscription = roomRepository.getById(roomId) final Disposable subscription = Flowable.zip(roomRepository.getById(roomId),
absoluteUrlHelper.getRocketChatAbsoluteUrl().toFlowable().cache(), Pair::new)
.subscribeOn(AndroidSchedulers.from(BackgroundLooper.get()))
.observeOn(AndroidSchedulers.mainThread())
.map(pair -> {
view.setupWith(pair.second.orNull());
return pair.first;
})
.filter(Optional::isPresent) .filter(Optional::isPresent)
.map(Optional::get) .map(Optional::get)
.map(room -> {
RocketChatCache.INSTANCE.addOpenedRoom(room.getRoomId(), room.getLastSeen());
return room;
})
.flatMap(messageInteractor::getAllFrom) .flatMap(messageInteractor::getAllFrom)
.subscribeOn(AndroidSchedulers.from(BackgroundLooper.get())) .subscribeOn(AndroidSchedulers.from(BackgroundLooper.get()))
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe( .subscribe(
messages -> view.showMessages(messages), view::showMessages,
Logger::report Logger.INSTANCE::report
); );
addSubscription(subscription); addSubscription(subscription);
...@@ -367,7 +402,7 @@ public class RoomPresenter extends BasePresenter<RoomContract.View> ...@@ -367,7 +402,7 @@ public class RoomPresenter extends BasePresenter<RoomContract.View>
view.manualLoadImages(); view.manualLoadImages();
} }
}, },
Logger::report Logger.INSTANCE::report
); );
addSubscription(subscription); addSubscription(subscription);
...@@ -379,7 +414,7 @@ public class RoomPresenter extends BasePresenter<RoomContract.View> ...@@ -379,7 +414,7 @@ public class RoomPresenter extends BasePresenter<RoomContract.View>
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe( .subscribe(
it -> view.setupWith(it.orNull()), it -> view.setupWith(it.orNull()),
Logger::report Logger.INSTANCE::report
); );
addSubscription(subscription); addSubscription(subscription);
......
...@@ -91,9 +91,7 @@ public class MessageOptionsDialogFragment extends BottomSheetDialogFragment { ...@@ -91,9 +91,7 @@ public class MessageOptionsDialogFragment extends BottomSheetDialogFragment {
} }
private void setUpDialog(final BottomSheetDialog bottomSheetDialog, String messageId) { private void setUpDialog(final BottomSheetDialog bottomSheetDialog, String messageId) {
RocketChatCache cache = new RocketChatCache(bottomSheetDialog.getContext()); String hostname = RocketChatCache.INSTANCE.getSelectedServerHostname();
String hostname = cache.getSelectedServerHostname();
EditMessageInteractor editMessageInteractor = getEditMessageInteractor(hostname); EditMessageInteractor editMessageInteractor = getEditMessageInteractor(hostname);
...@@ -132,7 +130,7 @@ public class MessageOptionsDialogFragment extends BottomSheetDialogFragment { ...@@ -132,7 +130,7 @@ public class MessageOptionsDialogFragment extends BottomSheetDialogFragment {
((TextView) bottomSheetDialog.findViewById(R.id.message_options_info)) ((TextView) bottomSheetDialog.findViewById(R.id.message_options_info))
.setText(R.string.message_options_no_message_info); .setText(R.string.message_options_no_message_info);
Logger.report(throwable); Logger.INSTANCE.report(throwable);
} }
); );
......
...@@ -23,13 +23,14 @@ import java.sql.Timestamp ...@@ -23,13 +23,14 @@ import java.sql.Timestamp
* Created by Filipe de Lima Brito (filipedelimabrito@gmail.com) on 9/22/17. * Created by Filipe de Lima Brito (filipedelimabrito@gmail.com) on 9/22/17.
*/ */
class RoomListPresenter(val context: Context, val view: RoomListContract.View) : RoomListContract.Presenter { class RoomListPresenter(val context: Context, val view: RoomListContract.View) : RoomListContract.Presenter {
private lateinit var TAG: String
override fun requestPinnedMessages(roomId: String, override fun requestPinnedMessages(roomId: String,
roomType: String, roomType: String,
hostname: String, hostname: String,
token: String, token: String,
userId: String, userId: String,
offset: Int) { offset: Int) {
TAG = "pinned"
view.showWaitingView(true) view.showWaitingView(true)
OkHttpHelper.getClient() OkHttpHelper.getClient()
.newCall(RestApiHelper.getRequestForPinnedMessages(roomId, .newCall(RestApiHelper.getRequestForPinnedMessages(roomId,
...@@ -53,7 +54,7 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) : ...@@ -53,7 +54,7 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) :
if (response.isSuccessful) { if (response.isSuccessful) {
val result = response.body()?.string() val result = response.body()?.string()
if (result != null) { if (result != null) {
handleMessagesJson(result, true) handleMessagesJson(result, true, TAG)
} }
} else { } else {
showErrorMessage(response.message()) showErrorMessage(response.message())
...@@ -68,6 +69,7 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) : ...@@ -68,6 +69,7 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) :
token: String, token: String,
userId: String, userId: String,
offset: Int) { offset: Int) {
TAG = "favorite"
view.showWaitingView(true) view.showWaitingView(true)
OkHttpHelper.getClient() OkHttpHelper.getClient()
.newCall(RestApiHelper.getRequestForFavoriteMessages(roomId, .newCall(RestApiHelper.getRequestForFavoriteMessages(roomId,
...@@ -91,7 +93,7 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) : ...@@ -91,7 +93,7 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) :
if (response.isSuccessful) { if (response.isSuccessful) {
val result = response.body()?.string() val result = response.body()?.string()
if (result != null) { if (result != null) {
handleMessagesJson(result, false) handleMessagesJson(result, false, TAG)
} }
} else { } else {
showErrorMessage(response.message()) showErrorMessage(response.message())
...@@ -180,7 +182,7 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) : ...@@ -180,7 +182,7 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) :
OkHttpHelper.getClient().dispatcher().cancelAll() OkHttpHelper.getClient().dispatcher().cancelAll()
} }
private fun handleMessagesJson(json: String, isPinnedMessage: Boolean) { private fun handleMessagesJson(json: String, isPinnedMessage: Boolean, TAG: String) {
try { try {
val jSONObject = JSONObject(json) val jSONObject = JSONObject(json)
val messagesJSONArray = jSONObject.getJSONArray("messages") val messagesJSONArray = jSONObject.getJSONArray("messages")
...@@ -204,7 +206,10 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) : ...@@ -204,7 +206,10 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) :
} }
if (dataSet.isEmpty() && !hasItem) { if (dataSet.isEmpty() && !hasItem) {
if (TAG.equals("favorite"))
showEmptyViewMessage(context.getString(R.string.fragment_room_list_no_favorite_message_to_show)) showEmptyViewMessage(context.getString(R.string.fragment_room_list_no_favorite_message_to_show))
else if (TAG.equals("pinned"))
showEmptyViewMessage(context.getString(R.string.fragment_room_list_no_pinned_message_to_show))
} else { } else {
if (dataSet.isNotEmpty()) { if (dataSet.isNotEmpty()) {
hasItem = true hasItem = true
......
...@@ -37,7 +37,7 @@ public class OAuthPresenter extends BasePresenter<OAuthContract.View> ...@@ -37,7 +37,7 @@ public class OAuthPresenter extends BasePresenter<OAuthContract.View>
view.close(); view.close();
} }
}, },
Logger::report Logger.INSTANCE::report
) )
); );
} }
......
...@@ -6,9 +6,10 @@ import android.support.v4.app.Fragment; ...@@ -6,9 +6,10 @@ import android.support.v4.app.Fragment;
import chat.rocket.android.R; import chat.rocket.android.R;
import chat.rocket.android.fragment.AbstractFragment; import chat.rocket.android.fragment.AbstractFragment;
import chat.rocket.android.helper.BackStackHelper;
import chat.rocket.android.helper.TextUtils; import chat.rocket.android.helper.TextUtils;
abstract class AbstractServerConfigFragment extends AbstractFragment { public abstract class AbstractServerConfigFragment extends AbstractFragment {
public static final String KEY_HOSTNAME = "hostname"; public static final String KEY_HOSTNAME = "hostname";
protected String hostname; protected String hostname;
...@@ -36,6 +37,7 @@ abstract class AbstractServerConfigFragment extends AbstractFragment { ...@@ -36,6 +37,7 @@ abstract class AbstractServerConfigFragment extends AbstractFragment {
} }
protected void showFragmentWithBackStack(Fragment fragment) { protected void showFragmentWithBackStack(Fragment fragment) {
BackStackHelper.FRAGMENT_TAG = "internal";
getFragmentManager().beginTransaction() getFragmentManager().beginTransaction()
.add(R.id.content, fragment) .add(R.id.content, fragment)
.addToBackStack(null) .addToBackStack(null)
......
package chat.rocket.android.fragment.server_config; package chat.rocket.android.fragment.server_config;
import android.content.Context;
import java.util.List; import java.util.List;
import chat.rocket.android.shared.BaseContract; import chat.rocket.android.shared.BaseContract;
...@@ -13,15 +16,23 @@ public interface LoginContract { ...@@ -13,15 +16,23 @@ public interface LoginContract {
void hideLoader(); void hideLoader();
void showErrorInUsernameEditText();
void showErrorInPasswordEditText();
void showError(String message); void showError(String message);
void showLoginServices(List<LoginServiceConfiguration> loginServiceList); void showLoginServices(List<LoginServiceConfiguration> loginServiceList);
void showTwoStepAuth(); void showTwoStepAuth();
void goBack();
} }
interface Presenter extends BaseContract.Presenter<View> { interface Presenter extends BaseContract.Presenter<View> {
void login(String username, String password); void login(String username, String password);
void goBack(Context ctx);
} }
} }
package chat.rocket.android.fragment.server_config;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.constraint.ConstraintLayout;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import java.util.HashMap;
import java.util.List;
import chat.rocket.android.R;
import chat.rocket.android.api.MethodCallHelper;
import chat.rocket.android.layouthelper.oauth.OAuthProviderInfo;
import chat.rocket.android.log.RCLog;
import chat.rocket.core.models.LoginServiceConfiguration;
import chat.rocket.persistence.realm.repositories.RealmLoginServiceConfigurationRepository;
import chat.rocket.persistence.realm.repositories.RealmPublicSettingRepository;
/**
* Login screen.
*/
public class LoginFragment extends AbstractServerConfigFragment implements LoginContract.View {
private LoginContract.Presenter presenter;
private ConstraintLayout container;
private View waitingView;
private TextView txtUsername;
private TextView txtPasswd;
@Override
protected int getLayout() {
return R.layout.fragment_login;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
presenter = new LoginPresenter(
new RealmLoginServiceConfigurationRepository(hostname),
new RealmPublicSettingRepository(hostname),
new MethodCallHelper(getContext(), hostname)
);
}
@Override
protected void onSetupView() {
container = rootView.findViewById(R.id.container);
Button btnEmail = rootView.findViewById(R.id.btn_login_with_email);
Button btnUserRegistration = rootView.findViewById(R.id.btn_user_registration);
txtUsername = rootView.findViewById(R.id.editor_username);
txtPasswd = rootView.findViewById(R.id.editor_passwd);
waitingView = rootView.findViewById(R.id.waiting);
btnEmail.setOnClickListener(view ->
presenter.login(txtUsername.getText().toString(), txtPasswd.getText().toString()));
btnUserRegistration.setOnClickListener(view ->
UserRegistrationDialogFragment.create(hostname, txtUsername.getText().toString(), txtPasswd.getText().toString())
.show(getFragmentManager(), "UserRegistrationDialogFragment"));
}
@Override
public void showLoader() {
container.setVisibility(View.GONE);
waitingView.setVisibility(View.VISIBLE);
}
@Override
public void hideLoader() {
waitingView.setVisibility(View.GONE);
container.setVisibility(View.VISIBLE);
}
@Override
public void showError(String message) {
Snackbar.make(rootView, message, Snackbar.LENGTH_SHORT).show();
}
@Override
public void showLoginServices(List<LoginServiceConfiguration> loginServiceList) {
HashMap<String, View> viewMap = new HashMap<>();
HashMap<String, Boolean> supportedMap = new HashMap<>();
for (OAuthProviderInfo info : OAuthProviderInfo.LIST) {
viewMap.put(info.serviceName, rootView.findViewById(info.buttonId));
supportedMap.put(info.serviceName, false);
}
for (LoginServiceConfiguration authProvider : loginServiceList) {
for (OAuthProviderInfo info : OAuthProviderInfo.LIST) {
if (!supportedMap.get(info.serviceName)
&& info.serviceName.equals(authProvider.getService())) {
supportedMap.put(info.serviceName, true);
viewMap.get(info.serviceName).setOnClickListener(view -> {
Fragment fragment = null;
try {
fragment = info.fragmentClass.newInstance();
} catch (Exception exception) {
RCLog.w(exception, "failed to build new Fragment");
}
if (fragment != null) {
Bundle args = new Bundle();
args.putString("hostname", hostname);
fragment.setArguments(args);
showFragmentWithBackStack(fragment);
}
});
viewMap.get(info.serviceName).setVisibility(View.VISIBLE);
}
}
}
for (OAuthProviderInfo info : OAuthProviderInfo.LIST) {
if (!supportedMap.get(info.serviceName)) {
viewMap.get(info.serviceName).setVisibility(View.GONE);
}
}
}
@Override
public void showTwoStepAuth() {
showFragmentWithBackStack(TwoStepAuthFragment.create(
hostname, txtUsername.getText().toString(), txtPasswd.getText().toString()
));
}
@Override
public void onResume() {
super.onResume();
presenter.bindView(this);
}
@Override
public void onPause() {
presenter.release();
super.onPause();
}
}
package chat.rocket.android.fragment.server_config
import android.os.Bundle
import android.support.constraint.ConstraintLayout
import android.support.design.widget.Snackbar
import android.support.design.widget.TextInputLayout
import android.support.v4.app.Fragment
import android.text.TextUtils
import android.view.View
import android.widget.Button
import android.widget.TextView
import chat.rocket.android.R
import chat.rocket.android.api.MethodCallHelper
import chat.rocket.android.layouthelper.oauth.OAuthProviderInfo
import chat.rocket.android.log.RCLog
import chat.rocket.core.models.LoginServiceConfiguration
import chat.rocket.persistence.realm.repositories.RealmLoginServiceConfigurationRepository
import chat.rocket.persistence.realm.repositories.RealmPublicSettingRepository
import com.jakewharton.rxbinding2.widget.RxTextView
import java.util.*
/**
* Login screen.
*/
class LoginFragment : AbstractServerConfigFragment(), LoginContract.View {
private lateinit var presenter: LoginContract.Presenter
private lateinit var container: ConstraintLayout
private lateinit var waitingView: View
private lateinit var txtUsername: TextView
private lateinit var txtPasswd: TextView
private lateinit var textInputUsername: TextInputLayout
private lateinit var textInputPassword: TextInputLayout
override fun getLayout(): Int {
return R.layout.fragment_login
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
presenter = LoginPresenter(
RealmLoginServiceConfigurationRepository(hostname),
RealmPublicSettingRepository(hostname),
MethodCallHelper(context, hostname)
)
}
override fun onSetupView() {
container = rootView.findViewById(R.id.container)
val btnEmail = rootView.findViewById<Button>(R.id.btn_login_with_email)
val btnUserRegistration = rootView.findViewById<Button>(R.id.btn_user_registration)
txtUsername = rootView.findViewById(R.id.editor_username)
txtPasswd = rootView.findViewById(R.id.editor_passwd)
textInputUsername = rootView.findViewById(R.id.text_input_username)
textInputPassword = rootView.findViewById(R.id.text_input_passwd)
setUpRxBinders()
waitingView = rootView.findViewById(R.id.waiting)
btnEmail.setOnClickListener { _ -> presenter.login(txtUsername.text.toString(), txtPasswd.text.toString()) }
btnUserRegistration.setOnClickListener { _ ->
UserRegistrationDialogFragment.create(hostname, txtUsername.text.toString(), txtPasswd.text.toString())
.show(fragmentManager!!, "UserRegistrationDialogFragment")
}
}
fun setUpRxBinders() {
RxTextView.textChanges(txtUsername).subscribe { text ->
if (!TextUtils.isEmpty(text) && textInputUsername.isErrorEnabled)
textInputUsername.setErrorEnabled(false)
}
RxTextView.textChanges(txtPasswd).subscribe { text ->
if (!TextUtils.isEmpty(text) && textInputPassword.isErrorEnabled)
textInputPassword.setErrorEnabled(false)
}
}
override fun showLoader() {
container.visibility = View.GONE
waitingView.visibility = View.VISIBLE
}
override fun showErrorInUsernameEditText() {
textInputUsername.setErrorEnabled(true);
textInputUsername.setError("Enter a Username")
}
override fun showErrorInPasswordEditText() {
textInputPassword.setErrorEnabled(true);
textInputPassword.setError("Enter a Password")
}
override fun hideLoader() {
waitingView.visibility = View.GONE
container.visibility = View.VISIBLE
}
override fun showError(message: String) {
Snackbar.make(rootView, message, Snackbar.LENGTH_SHORT).show()
}
override fun showLoginServices(loginServiceList: List<LoginServiceConfiguration>) {
val viewMap = HashMap<String, View>()
val supportedMap = HashMap<String, Boolean>()
for (info in OAuthProviderInfo.LIST) {
viewMap.put(info.serviceName, rootView.findViewById(info.buttonId))
supportedMap.put(info.serviceName, false)
}
for (authProvider in loginServiceList) {
for (info in OAuthProviderInfo.LIST) {
if (supportedMap[info.serviceName] == false && info.serviceName == authProvider.service) {
supportedMap.put(info.serviceName, true)
viewMap[info.serviceName]?.setOnClickListener { _ ->
var fragment: Fragment? = null
try {
fragment = info.fragmentClass.newInstance()
} catch (exception: Exception) {
RCLog.w(exception, "failed to build new Fragment")
}
fragment?.let {
val args = Bundle()
args.putString("hostname", hostname)
fragment.arguments = args
showFragmentWithBackStack(fragment)
}
}
viewMap[info.serviceName]?.visibility = View.VISIBLE
}
}
}
for (info in OAuthProviderInfo.LIST) {
if (supportedMap[info.serviceName] == false) {
viewMap[info.serviceName]?.visibility = View.GONE
}
}
}
override fun showTwoStepAuth() {
showFragmentWithBackStack(TwoStepAuthFragment.create(
hostname, txtUsername.text.toString(), txtPasswd.text.toString()
))
}
override fun onResume() {
super.onResume()
presenter.bindView(this)
}
override fun onPause() {
presenter.release()
super.onPause()
}
override fun goBack() {
presenter.goBack(context)
}
}
package chat.rocket.android.fragment.server_config;
import android.support.annotation.NonNull;
import com.hadisatrio.optional.Optional;
import bolts.Task;
import chat.rocket.android.BackgroundLooper;
import chat.rocket.android.api.MethodCallHelper;
import chat.rocket.android.api.TwoStepAuthException;
import chat.rocket.android.helper.Logger;
import chat.rocket.android.helper.TextUtils;
import chat.rocket.android.shared.BasePresenter;
import chat.rocket.core.PublicSettingsConstants;
import chat.rocket.core.models.PublicSetting;
import chat.rocket.core.repositories.LoginServiceConfigurationRepository;
import chat.rocket.core.repositories.PublicSettingRepository;
import io.reactivex.android.schedulers.AndroidSchedulers;
public class LoginPresenter extends BasePresenter<LoginContract.View>
implements LoginContract.Presenter {
private final LoginServiceConfigurationRepository loginServiceConfigurationRepository;
private final PublicSettingRepository publicSettingRepository;
private final MethodCallHelper methodCallHelper;
public LoginPresenter(LoginServiceConfigurationRepository loginServiceConfigurationRepository,
PublicSettingRepository publicSettingRepository,
MethodCallHelper methodCallHelper) {
this.loginServiceConfigurationRepository = loginServiceConfigurationRepository;
this.publicSettingRepository = publicSettingRepository;
this.methodCallHelper = methodCallHelper;
}
@Override
public void bindView(@NonNull LoginContract.View view) {
super.bindView(view);
getLoginServices();
}
@Override
public void login(String username, String password) {
if (TextUtils.isEmpty(username) || TextUtils.isEmpty(password)) {
return;
}
view.showLoader();
addSubscription(
publicSettingRepository.getById(PublicSettingsConstants.LDAP.ENABLE)
.subscribeOn(AndroidSchedulers.from(BackgroundLooper.get()))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
publicSettingOptional -> doLogin(username, password, publicSettingOptional),
Logger::report
)
);
}
private void getLoginServices() {
addSubscription(
loginServiceConfigurationRepository.getAll()
.subscribeOn(AndroidSchedulers.from(BackgroundLooper.get()))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
loginServiceConfigurations -> view.showLoginServices(loginServiceConfigurations),
Logger::report
)
);
}
private void doLogin(String username, String password, Optional<PublicSetting> optional) {
call(username, password, optional)
.continueWith(task -> {
if (task.isFaulted()) {
view.hideLoader();
final Exception error = task.getError();
if (error instanceof TwoStepAuthException) {
view.showTwoStepAuth();
} else {
view.showError(error.getMessage());
}
}
return null;
}, Task.UI_THREAD_EXECUTOR);
}
private Task<Void> call(String username, String password, Optional<PublicSetting> optional) {
if (optional.isPresent() && optional.get().getValueAsBoolean()) {
return methodCallHelper.loginWithLdap(username, password);
}
return methodCallHelper.loginWithEmail(username, password);
}
}
package chat.rocket.android.fragment.server_config
import android.content.Context
import bolts.Continuation
import bolts.Task
import chat.rocket.android.BackgroundLooper
import chat.rocket.android.LaunchUtil
import chat.rocket.android.RocketChatApplication
import chat.rocket.android.RocketChatCache
import chat.rocket.android.api.MethodCallHelper
import chat.rocket.android.api.TwoStepAuthException
import chat.rocket.android.helper.Logger
import chat.rocket.android.helper.TextUtils
import chat.rocket.android.service.ConnectivityManager
import chat.rocket.android.shared.BasePresenter
import chat.rocket.core.PublicSettingsConstants
import chat.rocket.core.models.PublicSetting
import chat.rocket.core.repositories.LoginServiceConfigurationRepository
import chat.rocket.core.repositories.PublicSettingRepository
import com.hadisatrio.optional.Optional
import io.reactivex.Completable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.rxkotlin.subscribeBy
class LoginPresenter(private val loginServiceConfigurationRepository: LoginServiceConfigurationRepository,
private val publicSettingRepository: PublicSettingRepository,
private val methodCallHelper: MethodCallHelper) : BasePresenter<LoginContract.View>(), LoginContract.Presenter {
override fun bindView(view: LoginContract.View) {
super.bindView(view)
getLoginServices()
}
override fun goBack(ctx: Context?) {
val context = RocketChatApplication.getInstance()
val hostname = RocketChatCache.getSelectedServerHostname()
hostname?.let {
ConnectivityManager.getInstance(context).removeServer(hostname)
RocketChatCache.clearSelectedHostnameReferences()
}
LaunchUtil.showMainActivity(ctx)
}
override fun login(username: String, password: String) {
//set error to edit texts
if (TextUtils.isEmpty(username) && TextUtils.isEmpty(password)) {
view.showErrorInUsernameEditText()
view.showErrorInPasswordEditText()
return
}
if (TextUtils.isEmpty(username)) {
view.showErrorInUsernameEditText()
return
}
if (TextUtils.isEmpty(password)) {
view.showErrorInPasswordEditText()
return
}
view.showLoader()
addSubscription(
publicSettingRepository.getById(PublicSettingsConstants.LDAP.ENABLE)
.subscribeOn(AndroidSchedulers.from(BackgroundLooper.get()))
.observeOn(AndroidSchedulers.mainThread())
.subscribeBy(
onSuccess = { publicSettingOptional -> doLogin(username, password, publicSettingOptional) },
onError = { Logger.report(it) }
)
)
}
private fun getLoginServices() {
addSubscription(
loginServiceConfigurationRepository.all
.subscribeOn(AndroidSchedulers.from(BackgroundLooper.get()))
.observeOn(AndroidSchedulers.mainThread())
.subscribeBy(
onNext = { loginServiceConfigurations ->
view.showLoginServices(loginServiceConfigurations);
},
onError = { Logger.report(it) }
)
)
}
private fun doLogin(username: String, password: String, optional: Optional<PublicSetting>) {
addSubscription(
Completable.create {
call(username, password, optional)
.continueWith(object : Continuation<Void, Any?> {
override fun then(task: Task<Void>?): Any? {
if (task != null && task.isFaulted()) {
view.hideLoader()
val error = task.getError()
error?.let {
if (error is TwoStepAuthException) {
view.showTwoStepAuth()
} else {
view.showError(error.message)
}
}
return Completable.complete()
}
return null
}
}, Task.UI_THREAD_EXECUTOR)
}.subscribeBy(
onError = {
view.showError(it.message)
}
)
)
}
private fun call(username: String, password: String, optional: Optional<PublicSetting>): Task<Void> {
return if (optional.isPresent && optional.get().valueAsBoolean) {
methodCallHelper.loginWithLdap(username, password)
} else methodCallHelper.loginWithEmail(username, password)
}
}
...@@ -52,7 +52,7 @@ public class RetryLoginPresenter extends BasePresenter<RetryLoginContract.View> ...@@ -52,7 +52,7 @@ public class RetryLoginPresenter extends BasePresenter<RetryLoginContract.View>
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe( .subscribe(
this::onSession, this::onSession,
Logger::report Logger.INSTANCE::report
) )
); );
} }
......
...@@ -4,14 +4,17 @@ import android.app.Dialog; ...@@ -4,14 +4,17 @@ import android.app.Dialog;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.design.widget.TextInputEditText;
import android.support.design.widget.TextInputLayout;
import android.support.v4.app.DialogFragment; import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.util.Patterns; import android.util.Patterns;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.jakewharton.rxbinding2.widget.RxTextView;
import chat.rocket.android.R; import chat.rocket.android.R;
import chat.rocket.android.api.MethodCallHelper; import chat.rocket.android.api.MethodCallHelper;
import chat.rocket.android.helper.TextUtils; import chat.rocket.android.helper.TextUtils;
...@@ -24,7 +27,13 @@ public class UserRegistrationDialogFragment extends DialogFragment { ...@@ -24,7 +27,13 @@ public class UserRegistrationDialogFragment extends DialogFragment {
private String username; private String username;
private String email; private String email;
private String password; private String password;
private TextInputEditText txtUsername;
private TextInputEditText txtEmail;
private TextInputEditText txtPasswd;
private TextInputLayout textInputUsername;
private TextInputLayout textInputEmail;
private TextInputLayout textInputPassword;
private View waitingView;
public UserRegistrationDialogFragment() { public UserRegistrationDialogFragment() {
super(); super();
} }
...@@ -88,9 +97,8 @@ public class UserRegistrationDialogFragment extends DialogFragment { ...@@ -88,9 +97,8 @@ public class UserRegistrationDialogFragment extends DialogFragment {
View dialog = LayoutInflater.from(getContext()) View dialog = LayoutInflater.from(getContext())
.inflate(R.layout.dialog_user_registration, null, false); .inflate(R.layout.dialog_user_registration, null, false);
final TextView txtUsername = (TextView) dialog.findViewById(R.id.editor_username); initViews(dialog);
final TextView txtEmail = (TextView) dialog.findViewById(R.id.editor_email); setUpRxBinders();
final TextView txtPasswd = (TextView) dialog.findViewById(R.id.editor_passwd);
if (!TextUtils.isEmpty(username)) { if (!TextUtils.isEmpty(username)) {
txtUsername.setText(username); txtUsername.setText(username);
...@@ -102,17 +110,19 @@ public class UserRegistrationDialogFragment extends DialogFragment { ...@@ -102,17 +110,19 @@ public class UserRegistrationDialogFragment extends DialogFragment {
txtPasswd.setText(password); txtPasswd.setText(password);
} }
final View waitingView = dialog.findViewById(R.id.waiting);
waitingView.setVisibility(View.GONE); waitingView.setVisibility(View.GONE);
dialog.findViewById(R.id.btn_register_user).setOnClickListener(view -> { dialog.findViewById(R.id.btn_register_user).setOnClickListener(registerButton -> {
view.setEnabled(false); if (checkIfEditTextsEmpty())
return;
registerButton.setEnabled(false);
registerButton.setAlpha(0.5f);
waitingView.setVisibility(View.VISIBLE); waitingView.setVisibility(View.VISIBLE);
username = txtUsername.getText().toString(); username = txtUsername.getText().toString();
email = txtEmail.getText().toString(); email = txtEmail.getText().toString();
password = txtPasswd.getText().toString(); password = txtPasswd.getText().toString();
MethodCallHelper methodCallHelper = new MethodCallHelper(getContext(), hostname); MethodCallHelper methodCallHelper = new MethodCallHelper(getContext(), hostname);
methodCallHelper.registerUser(username, email, password, password) methodCallHelper.registerUser(username, email, password, password)
.onSuccessTask(task -> methodCallHelper.loginWithEmail(email, password)) .onSuccessTask(task -> methodCallHelper.loginWithEmail(email, password))
...@@ -126,7 +136,7 @@ public class UserRegistrationDialogFragment extends DialogFragment { ...@@ -126,7 +136,7 @@ public class UserRegistrationDialogFragment extends DialogFragment {
if (task.isFaulted()) { if (task.isFaulted()) {
Exception exception = task.getError(); Exception exception = task.getError();
showError(exception.getMessage()); showError(exception.getMessage());
view.setEnabled(true); registerButton.setEnabled(true);
waitingView.setVisibility(View.GONE); waitingView.setVisibility(View.GONE);
} }
return null; return null;
...@@ -135,6 +145,51 @@ public class UserRegistrationDialogFragment extends DialogFragment { ...@@ -135,6 +145,51 @@ public class UserRegistrationDialogFragment extends DialogFragment {
return dialog; return dialog;
} }
private void initViews(View dialog) {
txtUsername = dialog.findViewById(R.id.editor_username);
txtEmail = dialog.findViewById(R.id.editor_email);
txtPasswd = dialog.findViewById(R.id.editor_passwd);
textInputEmail = dialog.findViewById(R.id.text_input_email);
textInputUsername = dialog.findViewById(R.id.text_input_username);
textInputPassword = dialog.findViewById(R.id.text_input_passwd);
waitingView = dialog.findViewById(R.id.waiting);
}
private boolean checkIfEditTextsEmpty() {
boolean check = false;
if (TextUtils.isEmpty(txtEmail.getText().toString())) {
textInputEmail.setError("Enter an email address");
textInputEmail.setErrorEnabled(true);
check = true;
}
if (TextUtils.isEmpty(txtUsername.getText().toString())) {
textInputUsername.setError("Enter a username");
textInputUsername.setErrorEnabled(true);
check = true;
}
if (TextUtils.isEmpty(txtPasswd.getText().toString())) {
textInputPassword.setError("Enter a password");
textInputPassword.setErrorEnabled(true);
check = true;
}
return check;
}
private void setUpRxBinders() {
RxTextView.textChanges(txtUsername).subscribe(text -> {
if (!TextUtils.isEmpty(text) && textInputUsername.isErrorEnabled())
textInputUsername.setErrorEnabled(false);
});
RxTextView.textChanges(txtEmail).subscribe(text -> {
if (!TextUtils.isEmpty(text) && textInputEmail.isErrorEnabled())
textInputEmail.setErrorEnabled(false);
});
RxTextView.textChanges(txtPasswd).subscribe(text -> {
if (!TextUtils.isEmpty(text) && textInputPassword.isErrorEnabled())
textInputPassword.setErrorEnabled(false);
});
}
private void showError(String errMessage) { private void showError(String errMessage) {
Toast.makeText(getContext(), errMessage, Toast.LENGTH_SHORT).show(); Toast.makeText(getContext(), errMessage, Toast.LENGTH_SHORT).show();
} }
......
...@@ -25,7 +25,7 @@ public interface SidebarMainContract { ...@@ -25,7 +25,7 @@ public interface SidebarMainContract {
void show(User user); void show(User user);
void onLogoutCleanUp(); void onPreparedToLogOut();
} }
interface Presenter extends BaseContract.Presenter<View> { interface Presenter extends BaseContract.Presenter<View> {
...@@ -48,6 +48,6 @@ public interface SidebarMainContract { ...@@ -48,6 +48,6 @@ public interface SidebarMainContract {
void onLogout(Continuation<Void, Object> continuation); void onLogout(Continuation<Void, Object> continuation);
void beforeLogoutCleanUp(); void prepareToLogOut();
} }
} }
\ No newline at end of file
...@@ -22,10 +22,8 @@ import java.util.ArrayList; ...@@ -22,10 +22,8 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import bolts.Task;
import chat.rocket.android.BuildConfig; import chat.rocket.android.BuildConfig;
import chat.rocket.android.R; import chat.rocket.android.R;
import chat.rocket.android.RocketChatCache;
import chat.rocket.android.activity.MainActivity; import chat.rocket.android.activity.MainActivity;
import chat.rocket.android.api.MethodCallHelper; import chat.rocket.android.api.MethodCallHelper;
import chat.rocket.android.fragment.AbstractFragment; import chat.rocket.android.fragment.AbstractFragment;
...@@ -51,6 +49,7 @@ import chat.rocket.persistence.realm.repositories.RealmServerInfoRepository; ...@@ -51,6 +49,7 @@ import chat.rocket.persistence.realm.repositories.RealmServerInfoRepository;
import chat.rocket.persistence.realm.repositories.RealmSessionRepository; import chat.rocket.persistence.realm.repositories.RealmSessionRepository;
import chat.rocket.persistence.realm.repositories.RealmSpotlightRepository; import chat.rocket.persistence.realm.repositories.RealmSpotlightRepository;
import chat.rocket.persistence.realm.repositories.RealmUserRepository; import chat.rocket.persistence.realm.repositories.RealmUserRepository;
import hugo.weaving.DebugLog;
import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable; import io.reactivex.disposables.Disposable;
...@@ -64,7 +63,8 @@ public class SidebarMainFragment extends AbstractFragment implements SidebarMain ...@@ -64,7 +63,8 @@ public class SidebarMainFragment extends AbstractFragment implements SidebarMain
private String hostname; private String hostname;
private static final String HOSTNAME = "hostname"; private static final String HOSTNAME = "hostname";
public SidebarMainFragment() {} public SidebarMainFragment() {
}
/** /**
* build SidebarMainFragment with hostname. * build SidebarMainFragment with hostname.
...@@ -93,13 +93,11 @@ public class SidebarMainFragment extends AbstractFragment implements SidebarMain ...@@ -93,13 +93,11 @@ public class SidebarMainFragment extends AbstractFragment implements SidebarMain
new SessionInteractor(new RealmSessionRepository(hostname)) new SessionInteractor(new RealmSessionRepository(hostname))
); );
RocketChatCache rocketChatCache = new RocketChatCache(getContext().getApplicationContext());
presenter = new SidebarMainPresenter( presenter = new SidebarMainPresenter(
hostname, hostname,
new RoomInteractor(new RealmRoomRepository(hostname)), new RoomInteractor(new RealmRoomRepository(hostname)),
userRepository, userRepository,
rocketChatCache,
absoluteUrlHelper, absoluteUrlHelper,
new MethodCallHelper(getContext(), hostname), new MethodCallHelper(getContext(), hostname),
new RealmSpotlightRepository(hostname) new RealmSpotlightRepository(hostname)
...@@ -199,7 +197,7 @@ public class SidebarMainFragment extends AbstractFragment implements SidebarMain ...@@ -199,7 +197,7 @@ public class SidebarMainFragment extends AbstractFragment implements SidebarMain
public void filterRoomSidebarList(CharSequence term) { public void filterRoomSidebarList(CharSequence term) {
List<RoomSidebar> filteredRoomSidebarList = new ArrayList<>(); List<RoomSidebar> filteredRoomSidebarList = new ArrayList<>();
for (RoomSidebar roomSidebar: roomSidebarList) { for (RoomSidebar roomSidebar : roomSidebarList) {
if (roomSidebar.getRoomName().contains(term)) { if (roomSidebar.getRoomName().contains(term)) {
filteredRoomSidebarList.add(roomSidebar); filteredRoomSidebarList.add(roomSidebar);
} }
...@@ -238,7 +236,7 @@ public class SidebarMainFragment extends AbstractFragment implements SidebarMain ...@@ -238,7 +236,7 @@ public class SidebarMainFragment extends AbstractFragment implements SidebarMain
.compose(bindToLifecycle()) .compose(bindToLifecycle())
.subscribe( .subscribe(
this::showUserActionContainer, this::showUserActionContainer,
Logger::report Logger.INSTANCE::report
); );
} }
...@@ -323,17 +321,12 @@ public class SidebarMainFragment extends AbstractFragment implements SidebarMain ...@@ -323,17 +321,12 @@ public class SidebarMainFragment extends AbstractFragment implements SidebarMain
adapter.setRoomListHeaders(roomListHeaders); adapter.setRoomListHeaders(roomListHeaders);
} }
@DebugLog
@Override @Override
public void onLogoutCleanUp() { public void onPreparedToLogOut() {
Activity activity = getActivity(); final Activity activity = getActivity();
if (activity != null && activity instanceof MainActivity) { if (activity != null && activity instanceof MainActivity) {
((MainActivity) activity).onLogout(); ((MainActivity) activity).onLogout();
presenter.onLogout(task -> {
if (task.isFaulted()) {
return Task.forError(task.getError());
}
return null;
});
} }
} }
...@@ -341,12 +334,7 @@ public class SidebarMainFragment extends AbstractFragment implements SidebarMain ...@@ -341,12 +334,7 @@ public class SidebarMainFragment extends AbstractFragment implements SidebarMain
rootView.findViewById(R.id.btn_logout).setOnClickListener(view -> { rootView.findViewById(R.id.btn_logout).setOnClickListener(view -> {
closeUserActionContainer(); closeUserActionContainer();
// Clear relative data and set new hostname if any. // Clear relative data and set new hostname if any.
presenter.beforeLogoutCleanUp(); presenter.prepareToLogOut();
final Activity activity = getActivity();
if (activity != null && activity instanceof MainActivity) {
// Clear subscriptions on MainPresenter.
((MainActivity) activity).beforeLogoutCleanUp();
}
}); });
} }
......
...@@ -18,7 +18,6 @@ import chat.rocket.android.helper.LogIfError; ...@@ -18,7 +18,6 @@ import chat.rocket.android.helper.LogIfError;
import chat.rocket.android.helper.Logger; import chat.rocket.android.helper.Logger;
import chat.rocket.android.helper.TextUtils; import chat.rocket.android.helper.TextUtils;
import chat.rocket.android.service.ConnectivityManager; import chat.rocket.android.service.ConnectivityManager;
import chat.rocket.android.service.ConnectivityManagerApi;
import chat.rocket.android.shared.BasePresenter; import chat.rocket.android.shared.BasePresenter;
import chat.rocket.core.interactors.RoomInteractor; import chat.rocket.core.interactors.RoomInteractor;
import chat.rocket.core.models.Room; import chat.rocket.core.models.Room;
...@@ -33,12 +32,12 @@ import chat.rocket.persistence.realm.repositories.RealmSpotlightRepository; ...@@ -33,12 +32,12 @@ import chat.rocket.persistence.realm.repositories.RealmSpotlightRepository;
import io.reactivex.Flowable; import io.reactivex.Flowable;
import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable; import io.reactivex.disposables.Disposable;
import io.realm.Realm;
public class SidebarMainPresenter extends BasePresenter<SidebarMainContract.View> implements SidebarMainContract.Presenter { public class SidebarMainPresenter extends BasePresenter<SidebarMainContract.View> implements SidebarMainContract.Presenter {
private final String hostname; private final String hostname;
private final RoomInteractor roomInteractor; private final RoomInteractor roomInteractor;
private final UserRepository userRepository; private final UserRepository userRepository;
private final RocketChatCache rocketChatCache;
private final AbsoluteUrlHelper absoluteUrlHelper; private final AbsoluteUrlHelper absoluteUrlHelper;
private final MethodCallHelper methodCallHelper; private final MethodCallHelper methodCallHelper;
private SpotlightRepository realmSpotlightRepository; private SpotlightRepository realmSpotlightRepository;
...@@ -47,14 +46,12 @@ public class SidebarMainPresenter extends BasePresenter<SidebarMainContract.View ...@@ -47,14 +46,12 @@ public class SidebarMainPresenter extends BasePresenter<SidebarMainContract.View
public SidebarMainPresenter(String hostname, public SidebarMainPresenter(String hostname,
RoomInteractor roomInteractor, RoomInteractor roomInteractor,
UserRepository userRepository, UserRepository userRepository,
RocketChatCache rocketChatCache,
AbsoluteUrlHelper absoluteUrlHelper, AbsoluteUrlHelper absoluteUrlHelper,
MethodCallHelper methodCallHelper, MethodCallHelper methodCallHelper,
RealmSpotlightRepository realmSpotlightRepository) { RealmSpotlightRepository realmSpotlightRepository) {
this.hostname = hostname; this.hostname = hostname;
this.roomInteractor = roomInteractor; this.roomInteractor = roomInteractor;
this.userRepository = userRepository; this.userRepository = userRepository;
this.rocketChatCache = rocketChatCache;
this.absoluteUrlHelper = absoluteUrlHelper; this.absoluteUrlHelper = absoluteUrlHelper;
this.methodCallHelper = methodCallHelper; this.methodCallHelper = methodCallHelper;
this.realmSpotlightRepository = realmSpotlightRepository; this.realmSpotlightRepository = realmSpotlightRepository;
...@@ -80,14 +77,14 @@ public class SidebarMainPresenter extends BasePresenter<SidebarMainContract.View ...@@ -80,14 +77,14 @@ public class SidebarMainPresenter extends BasePresenter<SidebarMainContract.View
) )
.subscribeOn(AndroidSchedulers.from(BackgroundLooper.get())) .subscribeOn(AndroidSchedulers.from(BackgroundLooper.get()))
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(pair -> view.show(pair.first.orNull()), Logger::report); .subscribe(pair -> view.show(pair.first.orNull()), Logger.INSTANCE::report);
addSubscription(subscription); addSubscription(subscription);
} }
@Override @Override
public void onRoomSelected(RoomSidebar roomSidebar) { public void onRoomSelected(RoomSidebar roomSidebar) {
rocketChatCache.setSelectedRoomId(roomSidebar.getRoomId()); RocketChatCache.INSTANCE.setSelectedRoomId(roomSidebar.getRoomId());
} }
@Override @Override
...@@ -103,7 +100,7 @@ public class SidebarMainPresenter extends BasePresenter<SidebarMainContract.View ...@@ -103,7 +100,7 @@ public class SidebarMainPresenter extends BasePresenter<SidebarMainContract.View
methodCallHelper.createDirectMessage(username) methodCallHelper.createDirectMessage(username)
.continueWithTask(task -> { .continueWithTask(task -> {
if (task.isCompleted()) { if (task.isCompleted()) {
rocketChatCache.setSelectedRoomId(task.getResult()); RocketChatCache.INSTANCE.setSelectedRoomId(task.getResult());
} }
return null; return null;
}); });
...@@ -111,7 +108,7 @@ public class SidebarMainPresenter extends BasePresenter<SidebarMainContract.View ...@@ -111,7 +108,7 @@ public class SidebarMainPresenter extends BasePresenter<SidebarMainContract.View
methodCallHelper.joinRoom(spotlight.getId()) methodCallHelper.joinRoom(spotlight.getId())
.continueWithTask(task -> { .continueWithTask(task -> {
if (task.isCompleted()) { if (task.isCompleted()) {
rocketChatCache.setSelectedRoomId(spotlight.getId()); RocketChatCache.INSTANCE.setSelectedRoomId(spotlight.getId());
} }
return null; return null;
}); });
...@@ -142,7 +139,7 @@ public class SidebarMainPresenter extends BasePresenter<SidebarMainContract.View ...@@ -142,7 +139,7 @@ public class SidebarMainPresenter extends BasePresenter<SidebarMainContract.View
public void onLogout(Continuation<Void, Object> continuation) { public void onLogout(Continuation<Void, Object> continuation) {
methodCallHelper.logout().continueWith(task -> { methodCallHelper.logout().continueWith(task -> {
if (task.isFaulted()) { if (task.isFaulted()) {
Logger.report(task.getError()); Logger.INSTANCE.report(task.getError());
return Task.forError(task.getError()); return Task.forError(task.getError());
} }
return task.onSuccess(continuation); return task.onSuccess(continuation);
...@@ -150,21 +147,27 @@ public class SidebarMainPresenter extends BasePresenter<SidebarMainContract.View ...@@ -150,21 +147,27 @@ public class SidebarMainPresenter extends BasePresenter<SidebarMainContract.View
} }
@Override @Override
public void beforeLogoutCleanUp() { public void prepareToLogOut() {
onLogout(task -> {
if (task.isFaulted()) {
return Task.forError(task.getError());
}
clearSubscriptions(); clearSubscriptions();
String currentHostname = rocketChatCache.getSelectedServerHostname(); String currentHostname = RocketChatCache.INSTANCE.getSelectedServerHostname();
RealmHelper realmHelper = RealmStore.getOrCreate(currentHostname); RealmHelper realmHelper = RealmStore.getOrCreate(currentHostname);
realmHelper.executeTransaction(realm -> { return realmHelper.executeTransaction(realm -> {
realm.executeTransactionAsync(realmObj -> realmObj.deleteAll()); RocketChatCache.INSTANCE.removeHostname(currentHostname);
RocketChatCache.INSTANCE.removeSelectedRoomId(currentHostname);
RocketChatCache.INSTANCE.setSelectedServerHostname(RocketChatCache.INSTANCE.getFirstLoggedHostnameIfAny());
realm.executeTransactionAsync(Realm::deleteAll);
view.onPreparedToLogOut();
ConnectivityManager.getInstance(RocketChatApplication.getInstance())
.removeServer(hostname);
CookieManager.getInstance().removeAllCookie(); CookieManager.getInstance().removeAllCookie();
ConnectivityManagerApi connectivityManagerApi = ConnectivityManager.getInstance(RocketChatApplication.getInstance());
connectivityManagerApi.removeServer(currentHostname);
rocketChatCache.removeHostname(currentHostname);
rocketChatCache.removeSelectedRoomId(currentHostname);
rocketChatCache.setSelectedServerHostname(rocketChatCache.getFirstLoggedHostnameIfAny());
view.onLogoutCleanUp();
return null; return null;
}); });
});
} }
@Override @Override
...@@ -177,7 +180,7 @@ public class SidebarMainPresenter extends BasePresenter<SidebarMainContract.View ...@@ -177,7 +180,7 @@ public class SidebarMainPresenter extends BasePresenter<SidebarMainContract.View
.distinctUntilChanged() .distinctUntilChanged()
.subscribeOn(AndroidSchedulers.from(BackgroundLooper.get())) .subscribeOn(AndroidSchedulers.from(BackgroundLooper.get()))
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(this::processRooms, Logger::report); .subscribe(this::processRooms, Logger.INSTANCE::report);
addSubscription(subscription); addSubscription(subscription);
} }
...@@ -221,13 +224,13 @@ public class SidebarMainPresenter extends BasePresenter<SidebarMainContract.View ...@@ -221,13 +224,13 @@ public class SidebarMainPresenter extends BasePresenter<SidebarMainContract.View
.distinctUntilChanged() .distinctUntilChanged()
.subscribeOn(AndroidSchedulers.from(BackgroundLooper.get())) .subscribeOn(AndroidSchedulers.from(BackgroundLooper.get()))
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(this::processUsers, Logger::report); .subscribe(this::processUsers, Logger.INSTANCE::report);
addSubscription(subscription); addSubscription(subscription);
} }
private void processUsers(List<User> userList) { private void processUsers(List<User> userList) {
for (User user: userList) { for (User user : userList) {
for(RoomSidebar roomSidebar: roomSidebarList) { for (RoomSidebar roomSidebar : roomSidebarList) {
if (roomSidebar.getRoomName().equals(user.getUsername())) { if (roomSidebar.getRoomName().equals(user.getUsername())) {
roomSidebar.setUserStatus(user.getStatus()); roomSidebar.setUserStatus(user.getStatus());
} }
......
...@@ -47,7 +47,7 @@ public class AddChannelDialogFragment extends AbstractAddRoomDialogFragment { ...@@ -47,7 +47,7 @@ public class AddChannelDialogFragment extends AbstractAddRoomDialogFragment {
.compose(bindToLifecycle()) .compose(bindToLifecycle())
.subscribe( .subscribe(
buttonAddChannel::setEnabled, buttonAddChannel::setEnabled,
Logger::report Logger.INSTANCE::report
); );
buttonAddChannel.setOnClickListener(view -> createRoom()); buttonAddChannel.setOnClickListener(view -> createRoom());
......
...@@ -68,7 +68,7 @@ public class AddDirectMessageDialogFragment extends AbstractAddRoomDialogFragmen ...@@ -68,7 +68,7 @@ public class AddDirectMessageDialogFragment extends AbstractAddRoomDialogFragmen
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe( .subscribe(
this::setupView, this::setupView,
Logger::report Logger.INSTANCE::report
) )
); );
...@@ -77,7 +77,7 @@ public class AddDirectMessageDialogFragment extends AbstractAddRoomDialogFragmen ...@@ -77,7 +77,7 @@ public class AddDirectMessageDialogFragment extends AbstractAddRoomDialogFragmen
.compose(bindToLifecycle()) .compose(bindToLifecycle())
.subscribe( .subscribe(
buttonAddDirectMessage::setEnabled, buttonAddDirectMessage::setEnabled,
Logger::report Logger.INSTANCE::report
); );
buttonAddDirectMessage.setOnClickListener(view -> createRoom()); buttonAddDirectMessage.setOnClickListener(view -> createRoom());
......
package chat.rocket.android.helper;
public class BackStackHelper {
public static String FRAGMENT_TAG = "login";
}
package chat.rocket.android.helper;
import com.crashlytics.android.Crashlytics;
import com.google.firebase.crash.FirebaseCrash;
public class Logger {
public static void report(Throwable throwable) {
FirebaseCrash.report(throwable);
Crashlytics.logException(throwable);
}
}
package chat.rocket.android.helper
import chat.rocket.android.BuildConfig
import com.crashlytics.android.Crashlytics
import com.google.firebase.crash.FirebaseCrash
object Logger {
fun report(throwable: Throwable) {
if (BuildConfig.DEBUG) {
throwable.printStackTrace()
}
FirebaseCrash.report(throwable)
Crashlytics.logException(throwable)
}
}
...@@ -48,9 +48,7 @@ public class MessagePopup { ...@@ -48,9 +48,7 @@ public class MessagePopup {
} }
private void showAvailableActionsOnly(Context context) { private void showAvailableActionsOnly(Context context) {
RocketChatCache cache = new RocketChatCache(context.getApplicationContext()); String hostname = RocketChatCache.INSTANCE.getSelectedServerHostname();
String hostname = cache.getSelectedServerHostname();
EditMessageInteractor editMessageInteractor = getEditMessageInteractor(hostname); EditMessageInteractor editMessageInteractor = getEditMessageInteractor(hostname);
...@@ -102,7 +100,7 @@ public class MessagePopup { ...@@ -102,7 +100,7 @@ public class MessagePopup {
.create() .create()
.show(); .show();
}, },
Logger::report Logger.INSTANCE::report
); );
compositeDisposable.add(disposable); compositeDisposable.add(disposable);
} }
...@@ -167,7 +165,7 @@ public class MessagePopup { ...@@ -167,7 +165,7 @@ public class MessagePopup {
} }
public MessagePopup setDeleteAction(ActionListener actionListener) { public MessagePopup setDeleteAction(ActionListener actionListener) {
DELETE_ACTION_INFO.actionListener= actionListener; DELETE_ACTION_INFO.actionListener = actionListener;
return singleton; return singleton;
} }
......
...@@ -101,7 +101,7 @@ public class RoomListItemViewHolder extends RecyclerView.ViewHolder { ...@@ -101,7 +101,7 @@ public class RoomListItemViewHolder extends RecyclerView.ViewHolder {
break; break;
default: { default: {
itemView.showPrivateChannelIcon(); itemView.showPrivateChannelIcon();
Logger.report(new AssertionError("Room type doesn't satisfies the method documentation. Room type is:" + roomType)); Logger.INSTANCE.report(new AssertionError("Room type doesn't satisfies the method documentation. Room type is:" + roomType));
} }
} }
} }
......
package chat.rocket.android.push package chat.rocket.android.push
import android.annotation.SuppressLint
import android.app.Notification import android.app.Notification
import android.app.NotificationChannel import android.app.NotificationChannel
import android.app.NotificationManager import android.app.NotificationManager
...@@ -137,6 +138,7 @@ object PushManager { ...@@ -137,6 +138,7 @@ object PushManager {
return group return group
} }
@SuppressLint("NewApi")
internal fun showNotification(context: Context, lastPushMessage: PushMessage) { internal fun showNotification(context: Context, lastPushMessage: PushMessage) {
if (lastPushMessage.host == null || lastPushMessage.message == null || lastPushMessage.title == null) { if (lastPushMessage.host == null || lastPushMessage.message == null || lastPushMessage.title == null) {
return return
...@@ -202,7 +204,7 @@ object PushManager { ...@@ -202,7 +204,7 @@ object PushManager {
.setDeleteIntent(deleteIntent) .setDeleteIntent(deleteIntent)
.setMessageNotification() .setMessageNotification()
val subText = RocketChatCache(context).getHostSiteName(host) val subText = RocketChatCache.getHostSiteName(host)
if (subText.isNotEmpty()) { if (subText.isNotEmpty()) {
builder.setSubText(subText) builder.setSubText(subText)
} }
...@@ -257,6 +259,7 @@ object PushManager { ...@@ -257,6 +259,7 @@ object PushManager {
} }
} }
@SuppressLint("NewApi")
@RequiresApi(Build.VERSION_CODES.N) @RequiresApi(Build.VERSION_CODES.N)
internal fun createGroupNotificationForNougatAndAbove(context: Context, lastPushMessage: PushMessage): Notification? { internal fun createGroupNotificationForNougatAndAbove(context: Context, lastPushMessage: PushMessage): Notification? {
with(lastPushMessage) { with(lastPushMessage) {
...@@ -289,7 +292,7 @@ object PushManager { ...@@ -289,7 +292,7 @@ object PushManager {
manager.createNotificationChannel(groupChannel) manager.createNotificationChannel(groupChannel)
} }
val subText = RocketChatCache(context).getHostSiteName(host) val subText = RocketChatCache.getHostSiteName(host)
if (subText.isNotEmpty()) { if (subText.isNotEmpty()) {
builder.setSubText(subText) builder.setSubText(subText)
} }
...@@ -344,7 +347,7 @@ object PushManager { ...@@ -344,7 +347,7 @@ object PushManager {
.setContentIntent(contentIntent) .setContentIntent(contentIntent)
.setMessageNotification() .setMessageNotification()
val subText = RocketChatCache(context).getHostSiteName(host) val subText = RocketChatCache.getHostSiteName(host)
if (subText.isNotEmpty()) { if (subText.isNotEmpty()) {
builder.setSubText(subText) builder.setSubText(subText)
} }
...@@ -370,6 +373,7 @@ object PushManager { ...@@ -370,6 +373,7 @@ object PushManager {
} }
} }
@SuppressLint("NewApi")
@RequiresApi(Build.VERSION_CODES.N) @RequiresApi(Build.VERSION_CODES.N)
internal fun createSingleNotificationForNougatAndAbove(context: Context, lastPushMessage: PushMessage): Notification? { internal fun createSingleNotificationForNougatAndAbove(context: Context, lastPushMessage: PushMessage): Notification? {
val manager: NotificationManager = val manager: NotificationManager =
...@@ -404,7 +408,7 @@ object PushManager { ...@@ -404,7 +408,7 @@ object PushManager {
manager.createNotificationChannel(channel) manager.createNotificationChannel(channel)
} }
val subText = RocketChatCache(context).getHostSiteName(host) val subText = RocketChatCache.getHostSiteName(host)
if (subText.isNotEmpty()) { if (subText.isNotEmpty()) {
builder.setSubText(subText) builder.setSubText(subText)
} }
...@@ -503,6 +507,7 @@ object PushManager { ...@@ -503,6 +507,7 @@ object PushManager {
setAutoCancel(true) setAutoCancel(true)
setShowWhen(true) setShowWhen(true)
setColor(res.getColor(R.color.colorRed400, ctx.theme)) setColor(res.getColor(R.color.colorRed400, ctx.theme))
setDefaults(Notification.DEFAULT_ALL)
setSmallIcon(smallIcon) setSmallIcon(smallIcon)
}) })
return this return this
...@@ -646,7 +651,7 @@ object PushManager { ...@@ -646,7 +651,7 @@ object PushManager {
} }
val httpUrl = HttpUrl.parse(pushMessage.host) val httpUrl = HttpUrl.parse(pushMessage.host)
httpUrl?.let { httpUrl?.let {
val siteUrl = RocketChatCache(context).getSiteUrlFor(httpUrl.host()) val siteUrl = RocketChatCache.getSiteUrlFor(httpUrl.host())
if (siteUrl != null) { if (siteUrl != null) {
sendMessage(siteUrl, message, pushMessage.rid) sendMessage(siteUrl, message, pushMessage.rid)
} }
...@@ -693,7 +698,6 @@ object PushManager { ...@@ -693,7 +698,6 @@ object PushManager {
.subscribe({ _ -> .subscribe({ _ ->
// Empty // Empty
}, { throwable -> }, { throwable ->
throwable.printStackTrace()
Logger.report(throwable) Logger.report(throwable)
}) })
} }
......
package chat.rocket.android.push.gcm
import bolts.Task
import chat.rocket.android.R
import chat.rocket.android.RocketChatApplication
import chat.rocket.android.RocketChatCache
import chat.rocket.android.api.RaixPushHelper
import chat.rocket.persistence.realm.RealmHelper
import chat.rocket.persistence.realm.models.ddp.RealmUser
import com.google.android.gms.gcm.GoogleCloudMessaging
import com.google.android.gms.iid.InstanceID
import java.io.IOException
object GcmPushHelper {
fun getGcmToken(): String? = getGcmToken(getSenderId())
@Throws(IOException::class)
private fun registerGcmTokenForServer(realmHelper: RealmHelper): Task<Void> {
val gcmToken = getGcmToken(getSenderId())
val currentUser = realmHelper.executeTransactionForRead({ realm -> RealmUser.queryCurrentUser(realm).findFirst() })
val userId = if (currentUser != null) currentUser.getId() else null
val pushId = RocketChatCache.getOrCreatePushId()
return RaixPushHelper(realmHelper)
.pushUpdate(pushId!!, gcmToken, userId)
}
@Throws(IOException::class)
private fun getGcmToken(senderId: String): String {
return InstanceID.getInstance(RocketChatApplication.getInstance())
.getToken(senderId, GoogleCloudMessaging.INSTANCE_ID_SCOPE, null)
}
private fun getSenderId(): String {
return RocketChatApplication.getInstance().getString(R.string.gcm_sender_id)
}
}
\ No newline at end of file
...@@ -28,4 +28,8 @@ public interface ConnectivityManagerApi { ...@@ -28,4 +28,8 @@ public interface ConnectivityManagerApi {
int getConnectivityState(@NonNull String hostname); int getConnectivityState(@NonNull String hostname);
void resetConnectivityStateList(); void resetConnectivityStateList();
void notifySessionEstablished(String hostname);
void notifyConnecting(String hostname);
} }
package chat.rocket.android.service
import chat.rocket.android.ConnectionStatusManager
import chat.rocket.android.RocketChatApplication
import com.evernote.android.job.Job
import com.evernote.android.job.JobManager
import com.evernote.android.job.JobRequest
import java.util.concurrent.TimeUnit
class KeepAliveJob : Job() {
private val connectivityManager: ConnectivityManagerApi
companion object {
val TAG = "chat.rocket.android.service.KeepAliveJob"
fun schedule() {
JobRequest.Builder(TAG)
.setExecutionWindow(TimeUnit.SECONDS.toMillis(3L), TimeUnit.SECONDS.toMillis(10L))
.setBackoffCriteria(10L, JobRequest.BackoffPolicy.EXPONENTIAL)
.setUpdateCurrent(true)
.setRequiredNetworkType(JobRequest.NetworkType.CONNECTED)
.setRequiresCharging(false)
.setRequirementsEnforced(true)
.build()
.schedule()
}
fun cancelPendingJobRequests() {
val allJobRequests = JobManager.instance().getAllJobRequestsForTag(TAG)
allJobRequests.forEach { jobRequest ->
jobRequest.cancelAndEdit()
}
}
}
init {
val context = RocketChatApplication.getInstance()
connectivityManager = ConnectivityManager.getInstance(context)
}
override fun onRunJob(params: Params): Result {
if (ConnectionStatusManager.transitionCount() == 0L) {
return Result.SUCCESS
}
when (ConnectionStatusManager.currentState()) {
ConnectionStatusManager.State.CONNECTING, ConnectionStatusManager.State.ONLINE -> {
cancel()
}
else -> connectivityManager.keepAliveServer()
}
return Result.SUCCESS
}
}
\ No newline at end of file
...@@ -14,6 +14,7 @@ import java.util.Map; ...@@ -14,6 +14,7 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import chat.rocket.android.ConnectionStatusManager;
import chat.rocket.android.RocketChatCache; import chat.rocket.android.RocketChatCache;
import chat.rocket.android.helper.RxHelper; import chat.rocket.android.helper.RxHelper;
import chat.rocket.android.log.RCLog; import chat.rocket.android.log.RCLog;
...@@ -74,7 +75,7 @@ import io.reactivex.subjects.BehaviorSubject; ...@@ -74,7 +75,7 @@ import io.reactivex.subjects.BehaviorSubject;
@DebugLog @DebugLog
@Override @Override
public void ensureConnections() { public void ensureConnections() {
String hostname = new RocketChatCache(appContext).getSelectedServerHostname(); String hostname = RocketChatCache.INSTANCE.getSelectedServerHostname();
if (hostname == null) { if (hostname == null) {
return; return;
} }
...@@ -107,7 +108,7 @@ import io.reactivex.subjects.BehaviorSubject; ...@@ -107,7 +108,7 @@ import io.reactivex.subjects.BehaviorSubject;
public void removeServer(String hostname) { public void removeServer(String hostname) {
RealmBasedServerInfo.remove(hostname); RealmBasedServerInfo.remove(hostname);
if (serverConnectivityList.containsKey(hostname)) { if (serverConnectivityList.containsKey(hostname)) {
disconnectFromServerIfNeeded(hostname) disconnectFromServerIfNeeded(hostname, DDPClient.REASON_CLOSED_BY_USER)
.subscribe(_val -> { .subscribe(_val -> {
}, RCLog::e); }, RCLog::e);
} }
...@@ -136,6 +137,13 @@ import io.reactivex.subjects.BehaviorSubject; ...@@ -136,6 +137,13 @@ import io.reactivex.subjects.BehaviorSubject;
return list; return list;
} }
@Override
public void notifySessionEstablished(String hostname) {
serverConnectivityList.put(hostname, ServerConnectivity.STATE_SESSION_ESTABLISHED);
connectivitySubject.onNext(
new ServerConnectivity(hostname, ServerConnectivity.STATE_SESSION_ESTABLISHED));
}
@DebugLog @DebugLog
@Override @Override
public void notifyConnectionEstablished(String hostname, String session) { public void notifyConnectionEstablished(String hostname, String session) {
...@@ -200,7 +208,7 @@ import io.reactivex.subjects.BehaviorSubject; ...@@ -200,7 +208,7 @@ import io.reactivex.subjects.BehaviorSubject;
}); });
} }
private Single<Boolean> disconnectFromServerIfNeeded(String hostname) { private Single<Boolean> disconnectFromServerIfNeeded(String hostname, int reason) {
return Single.defer(() -> { return Single.defer(() -> {
final int connectivity = serverConnectivityList.get(hostname); final int connectivity = serverConnectivityList.get(hostname);
if (connectivity == ServerConnectivity.STATE_DISCONNECTED) { if (connectivity == ServerConnectivity.STATE_DISCONNECTED) {
...@@ -209,8 +217,8 @@ import io.reactivex.subjects.BehaviorSubject; ...@@ -209,8 +217,8 @@ import io.reactivex.subjects.BehaviorSubject;
if (connectivity == ServerConnectivity.STATE_CONNECTING) { if (connectivity == ServerConnectivity.STATE_CONNECTING) {
return waitForConnected(hostname) return waitForConnected(hostname)
.doOnError(err -> notifyConnectionLost(hostname, DDPClient.REASON_NETWORK_ERROR)) // .doOnError(err -> notifyConnectionLost(hostname, DDPClient.REASON_CLOSED_BY_USER))
.flatMap(_val -> disconnectFromServerIfNeeded(hostname)); .flatMap(_val -> disconnectFromServerIfNeeded(hostname, DDPClient.REASON_CLOSED_BY_USER));
} }
if (connectivity == ServerConnectivity.STATE_DISCONNECTING) { if (connectivity == ServerConnectivity.STATE_DISCONNECTING) {
...@@ -253,6 +261,7 @@ import io.reactivex.subjects.BehaviorSubject; ...@@ -253,6 +261,7 @@ import io.reactivex.subjects.BehaviorSubject;
private Single<Boolean> connectToServer(String hostname) { private Single<Boolean> connectToServer(String hostname) {
return Single.defer(() -> { return Single.defer(() -> {
if (!serverConnectivityList.containsKey(hostname)) { if (!serverConnectivityList.containsKey(hostname)) {
ConnectionStatusManager.INSTANCE.setConnectionError();
return Single.error(new IllegalArgumentException("hostname not found")); return Single.error(new IllegalArgumentException("hostname not found"));
} }
...@@ -263,8 +272,10 @@ import io.reactivex.subjects.BehaviorSubject; ...@@ -263,8 +272,10 @@ import io.reactivex.subjects.BehaviorSubject;
} }
if (serviceInterface != null) { if (serviceInterface != null) {
ConnectionStatusManager.INSTANCE.setConnecting();
return serviceInterface.ensureConnectionToServer(hostname); return serviceInterface.ensureConnectionToServer(hostname);
} else { } else {
ConnectionStatusManager.INSTANCE.setConnectionError();
return Single.error(new ThreadLooperNotPreparedException("not prepared")); return Single.error(new ThreadLooperNotPreparedException("not prepared"));
} }
}); });
...@@ -279,8 +290,11 @@ import io.reactivex.subjects.BehaviorSubject; ...@@ -279,8 +290,11 @@ import io.reactivex.subjects.BehaviorSubject;
if (serviceInterface != null) { if (serviceInterface != null) {
return serviceInterface.disconnectFromServer(hostname) return serviceInterface.disconnectFromServer(hostname)
// //after disconnection from server, remove HOSTNAME key from HashMap //after disconnection from server, remove HOSTNAME key from HashMap
.doAfterTerminate(() -> serverConnectivityList.remove(hostname)); .doAfterTerminate(() -> {
serverConnectivityList.remove(hostname);
serverConnectivityList.put(hostname, ServerConnectivity.STATE_DISCONNECTED);
});
} else { } else {
return Single.error(new IllegalStateException("not prepared")); return Single.error(new IllegalStateException("not prepared"));
} }
......
...@@ -38,7 +38,8 @@ public class RocketChatService extends Service implements ConnectivityServiceInt ...@@ -38,7 +38,8 @@ public class RocketChatService extends Service implements ConnectivityServiceInt
/** /**
* ensure RocketChatService alive. * ensure RocketChatService alive.
*/ */
/*package*/static void keepAlive(Context context) { /*package*/
static void keepAlive(Context context) {
context.startService(new Intent(context, RocketChatService.class)); context.startService(new Intent(context, RocketChatService.class));
} }
...@@ -80,7 +81,7 @@ public class RocketChatService extends Service implements ConnectivityServiceInt ...@@ -80,7 +81,7 @@ public class RocketChatService extends Service implements ConnectivityServiceInt
} }
if (currentWebSocketThread != null) { if (currentWebSocketThread != null) {
return currentWebSocketThread.terminate() return currentWebSocketThread.terminate(false)
// after disconnection from server // after disconnection from server
.doAfterTerminate(() -> { .doAfterTerminate(() -> {
currentWebSocketThread = null; currentWebSocketThread = null;
...@@ -99,14 +100,15 @@ public class RocketChatService extends Service implements ConnectivityServiceInt ...@@ -99,14 +100,15 @@ public class RocketChatService extends Service implements ConnectivityServiceInt
return Single.defer(() -> { return Single.defer(() -> {
webSocketThreadLock.acquire(); webSocketThreadLock.acquire();
int connectivityState = ConnectivityManager.getInstance(getApplicationContext()).getConnectivityState(hostname); int connectivityState = ConnectivityManager.getInstance(getApplicationContext()).getConnectivityState(hostname);
boolean isDisconnected = connectivityState != ServerConnectivity.STATE_CONNECTED; boolean isDisconnected = connectivityState < ServerConnectivity.STATE_CONNECTED;
if (currentWebSocketThread != null && existsThreadForHostname(hostname) && !isDisconnected) { if (currentWebSocketThread != null && existsThreadForHostname(hostname) && !isDisconnected) {
webSocketThreadLock.release(); webSocketThreadLock.release();
return Single.just(currentWebSocketThread); return Single.just(currentWebSocketThread);
} }
if (currentWebSocketThread != null) { if (currentWebSocketThread != null) {
return currentWebSocketThread.terminate() boolean hasFailed = existsThreadForHostname(hostname);
return currentWebSocketThread.terminate(hasFailed)
.doAfterTerminate(() -> currentWebSocketThread = null) .doAfterTerminate(() -> currentWebSocketThread = null)
.flatMap(terminated -> .flatMap(terminated ->
RocketChatWebSocketThread.getStarted(getApplicationContext(), hostname) RocketChatWebSocketThread.getStarted(getApplicationContext(), hostname)
...@@ -117,7 +119,7 @@ public class RocketChatService extends Service implements ConnectivityServiceInt ...@@ -117,7 +119,7 @@ public class RocketChatService extends Service implements ConnectivityServiceInt
.doOnError(throwable -> { .doOnError(throwable -> {
currentWebSocketThread = null; currentWebSocketThread = null;
RCLog.e(throwable); RCLog.e(throwable);
Logger.report(throwable); Logger.INSTANCE.report(throwable);
webSocketThreadLock.release(); webSocketThreadLock.release();
}) })
); );
...@@ -131,7 +133,7 @@ public class RocketChatService extends Service implements ConnectivityServiceInt ...@@ -131,7 +133,7 @@ public class RocketChatService extends Service implements ConnectivityServiceInt
.doOnError(throwable -> { .doOnError(throwable -> {
currentWebSocketThread = null; currentWebSocketThread = null;
RCLog.e(throwable); RCLog.e(throwable);
Logger.report(throwable); Logger.INSTANCE.report(throwable);
webSocketThreadLock.release(); webSocketThreadLock.release();
}); });
}); });
......
...@@ -14,6 +14,7 @@ import java.util.concurrent.TimeUnit; ...@@ -14,6 +14,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import bolts.Task; import bolts.Task;
import chat.rocket.android.ConnectionStatusManager;
import chat.rocket.android.api.MethodCallHelper; import chat.rocket.android.api.MethodCallHelper;
import chat.rocket.android.helper.LogIfError; import chat.rocket.android.helper.LogIfError;
import chat.rocket.android.helper.RxHelper; import chat.rocket.android.helper.RxHelper;
...@@ -29,7 +30,6 @@ import chat.rocket.android.service.observer.FileUploadingWithUfsObserver; ...@@ -29,7 +30,6 @@ import chat.rocket.android.service.observer.FileUploadingWithUfsObserver;
import chat.rocket.android.service.observer.GcmPushRegistrationObserver; import chat.rocket.android.service.observer.GcmPushRegistrationObserver;
import chat.rocket.android.service.observer.GetUsersOfRoomsProcedureObserver; import chat.rocket.android.service.observer.GetUsersOfRoomsProcedureObserver;
import chat.rocket.android.service.observer.LoadMessageProcedureObserver; import chat.rocket.android.service.observer.LoadMessageProcedureObserver;
import chat.rocket.android.service.observer.MethodCallObserver;
import chat.rocket.android.service.observer.NewMessageObserver; import chat.rocket.android.service.observer.NewMessageObserver;
import chat.rocket.android.service.observer.PushSettingsObserver; import chat.rocket.android.service.observer.PushSettingsObserver;
import chat.rocket.android.service.observer.SessionObserver; import chat.rocket.android.service.observer.SessionObserver;
...@@ -54,8 +54,7 @@ public class RocketChatWebSocketThread extends HandlerThread { ...@@ -54,8 +54,7 @@ public class RocketChatWebSocketThread extends HandlerThread {
LoginServiceConfigurationSubscriber.class, LoginServiceConfigurationSubscriber.class,
ActiveUsersSubscriber.class, ActiveUsersSubscriber.class,
UserDataSubscriber.class, UserDataSubscriber.class,
MethodCallObserver.class, // MethodCallObserver.class,
SessionObserver.class,
LoadMessageProcedureObserver.class, LoadMessageProcedureObserver.class,
GetUsersOfRoomsProcedureObserver.class, GetUsersOfRoomsProcedureObserver.class,
NewMessageObserver.class, NewMessageObserver.class,
...@@ -71,10 +70,10 @@ public class RocketChatWebSocketThread extends HandlerThread { ...@@ -71,10 +70,10 @@ public class RocketChatWebSocketThread extends HandlerThread {
private final String hostname; private final String hostname;
private final RealmHelper realmHelper; private final RealmHelper realmHelper;
private final ConnectivityManagerInternal connectivityManager; private final ConnectivityManagerInternal connectivityManager;
private final ArrayList<Registrable> listeners = new ArrayList<>(); private volatile ArrayList<Registrable> listeners = new ArrayList<>();
private final CompositeDisposable heartbeatDisposable = new CompositeDisposable(); private final CompositeDisposable heartbeatDisposable = new CompositeDisposable();
private final CompositeDisposable reconnectDisposable = new CompositeDisposable(); private final CompositeDisposable reconnectDisposable = new CompositeDisposable();
private boolean listenersRegistered; private volatile boolean listenersRegistered;
private RocketChatWebSocketThread(Context appContext, String hostname) { private RocketChatWebSocketThread(Context appContext, String hostname) {
super("RC_thread_" + hostname); super("RC_thread_" + hostname);
...@@ -125,21 +124,26 @@ public class RocketChatWebSocketThread extends HandlerThread { ...@@ -125,21 +124,26 @@ public class RocketChatWebSocketThread extends HandlerThread {
} }
/** /**
* terminate WebSocket thread. * Terminate WebSocket thread. If {@code hasFailed} is {@code true} it means that a connection was
* in progress but failed and got offline. If it's {@code false} means that the user explicitly
* disconnected from server either by logging out or by means of changing servers.
*
* @param hasFailed {@code true} if the termination is due to a network error, otherwise
* return false
*/ */
@DebugLog @DebugLog
/* package */ Single<Boolean> terminate() { /* package */ Single<Boolean> terminate(boolean hasFailed) {
if (isAlive()) { if (isAlive()) {
return Single.create(emitter -> { return Single.create(emitter -> new Handler(getLooper()).post(() -> {
new Handler(getLooper()).post(() -> {
RCLog.d("thread %s: terminated()", Thread.currentThread().getId()); RCLog.d("thread %s: terminated()", Thread.currentThread().getId());
unregisterListenersAndClose(); int reason = (hasFailed) ?
connectivityManager.notifyConnectionLost(hostname, DDPClient.REASON_NETWORK_ERROR : DDPClient.REASON_CLOSED_BY_USER;
DDPClient.REASON_CLOSED_BY_USER); unregisterListenersAndClose(reason);
connectivityManager.notifyConnectionLost(hostname, reason);
RocketChatWebSocketThread.super.quit(); RocketChatWebSocketThread.super.quit();
ConnectionStatusManager.INSTANCE.setOffline();
emitter.onSuccess(true); emitter.onSuccess(true);
}); }));
});
} else { } else {
connectivityManager.notifyConnectionLost(hostname, connectivityManager.notifyConnectionLost(hostname,
DDPClient.REASON_NETWORK_ERROR); DDPClient.REASON_NETWORK_ERROR);
...@@ -163,7 +167,7 @@ public class RocketChatWebSocketThread extends HandlerThread { ...@@ -163,7 +167,7 @@ public class RocketChatWebSocketThread extends HandlerThread {
@DebugLog @DebugLog
/* package */ Single<Boolean> keepAlive() { /* package */ Single<Boolean> keepAlive() {
return checkIfConnectionAlive() return checkIfConnectionAlive()
.flatMap(alive -> alive ? Single.just(true) : connectWithExponentialBackoff()); .flatMap(alive -> connectWithExponentialBackoff());
} }
@DebugLog @DebugLog
...@@ -224,7 +228,7 @@ public class RocketChatWebSocketThread extends HandlerThread { ...@@ -224,7 +228,7 @@ public class RocketChatWebSocketThread extends HandlerThread {
.onSuccessTask(task -> { .onSuccessTask(task -> {
final String newSession = task.getResult().session; final String newSession = task.getResult().session;
connectivityManager.notifyConnectionEstablished(hostname, newSession); connectivityManager.notifyConnectionEstablished(hostname, newSession);
// handling WebSocket#onClose() callback.
task.getResult().client.getOnCloseCallback().onSuccess(_task -> { task.getResult().client.getOnCloseCallback().onSuccess(_task -> {
RxWebSocketCallback.Close result = _task.getResult(); RxWebSocketCallback.Close result = _task.getResult();
if (result.code == DDPClient.REASON_NETWORK_ERROR) { if (result.code == DDPClient.REASON_NETWORK_ERROR) {
...@@ -333,8 +337,8 @@ public class RocketChatWebSocketThread extends HandlerThread { ...@@ -333,8 +337,8 @@ public class RocketChatWebSocketThread extends HandlerThread {
.findAll()); .findAll());
if (sessions != null && sessions.size() > 0) { if (sessions != null && sessions.size() > 0) {
// if we have a session try to resume it. At this point we're probably recovering from // If we have a session try to resume it. At this point we're probably recovering from
// a disconnection state // a disconnection state.
final CompositeDisposable disposables = new CompositeDisposable(); final CompositeDisposable disposables = new CompositeDisposable();
MethodCallHelper methodCall = new MethodCallHelper(realmHelper); MethodCallHelper methodCall = new MethodCallHelper(realmHelper);
disposables.add( disposables.add(
...@@ -351,7 +355,11 @@ public class RocketChatWebSocketThread extends HandlerThread { ...@@ -351,7 +355,11 @@ public class RocketChatWebSocketThread extends HandlerThread {
createObserversAndRegister(); createObserversAndRegister();
disposables.clear(); disposables.clear();
}, },
error -> logErrorAndUnsubscribe(disposables, error) error -> {
logErrorAndUnsubscribe(disposables, error);
connectivityManager.notifyConnectionLost(hostname,
DDPClient.REASON_NETWORK_ERROR);
}
) )
); );
} else { } else {
...@@ -376,6 +384,10 @@ public class RocketChatWebSocketThread extends HandlerThread { ...@@ -376,6 +384,10 @@ public class RocketChatWebSocketThread extends HandlerThread {
RCLog.w(exception, "Failed to register listeners!!"); RCLog.w(exception, "Failed to register listeners!!");
} }
} }
// Register SessionObserver late.
SessionObserver sessionObserver = new SessionObserver(appContext, hostname, realmHelper);
sessionObserver.register();
listeners.add(sessionObserver);
listenersRegistered = true; listenersRegistered = true;
startHeartBeat(); startHeartBeat();
} }
...@@ -404,9 +416,9 @@ public class RocketChatWebSocketThread extends HandlerThread { ...@@ -404,9 +416,9 @@ public class RocketChatWebSocketThread extends HandlerThread {
} }
@DebugLog @DebugLog
private void unregisterListenersAndClose() { private void unregisterListenersAndClose(int reason) {
unregisterListeners(); unregisterListeners();
DDPClient.get().close(); DDPClient.get().close(reason);
} }
@DebugLog @DebugLog
......
...@@ -5,12 +5,12 @@ package chat.rocket.android.service; ...@@ -5,12 +5,12 @@ package chat.rocket.android.service;
*/ */
public class ServerConnectivity { public class ServerConnectivity {
public static final int STATE_CONNECTED = 1; public static final int STATE_DISCONNECTED = 0;
/* package */ static final int STATE_DISCONNECTING = 1;
public static final int STATE_DISCONNECTED = 2; /* package */ static final int STATE_CONNECTING = 2;
public static final int STATE_CONNECTING = 3; public static final int STATE_CONNECTED = 3;
/*package*/ static final int STATE_DISCONNECTING = 4; public static final int STATE_SESSION_ESTABLISHED = 4;
public static final ServerConnectivity CONNECTED = new ServerConnectivity(null, STATE_CONNECTED); /* package */ static final ServerConnectivity CONNECTED = new ServerConnectivity(null, STATE_CONNECTED);
public final String hostname; public final String hostname;
public final int state; public final int state;
...@@ -46,8 +46,8 @@ public class ServerConnectivity { ...@@ -46,8 +46,8 @@ public class ServerConnectivity {
/** /**
* This exception should be thrown when connection is lost during waiting for CONNECTED. * This exception should be thrown when connection is lost during waiting for CONNECTED.
*/ */
public static class DisconnectedException extends Exception { /* package */static class DisconnectedException extends Exception {
public DisconnectedException() { /* package */DisconnectedException() {
super("Disconnected"); super("Disconnected");
} }
} }
......
package chat.rocket.android.service.internal; package chat.rocket.android.service.internal;
import android.content.Context;
import com.hadisatrio.optional.Optional; import com.hadisatrio.optional.Optional;
import chat.rocket.android.RocketChatCache; import chat.rocket.android.RocketChatCache;
...@@ -13,13 +11,11 @@ import chat.rocket.persistence.realm.models.ddp.RealmRoom; ...@@ -13,13 +11,11 @@ import chat.rocket.persistence.realm.models.ddp.RealmRoom;
import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.CompositeDisposable;
public abstract class AbstractRocketChatCacheObserver implements Registrable { public abstract class AbstractRocketChatCacheObserver implements Registrable {
private final Context context;
private final RealmHelper realmHelper; private final RealmHelper realmHelper;
private String roomId; private String roomId;
private CompositeDisposable compositeDisposable = new CompositeDisposable(); private CompositeDisposable compositeDisposable = new CompositeDisposable();
protected AbstractRocketChatCacheObserver(Context context, RealmHelper realmHelper) { protected AbstractRocketChatCacheObserver(RealmHelper realmHelper) {
this.context = context;
this.realmHelper = realmHelper; this.realmHelper = realmHelper;
} }
...@@ -47,7 +43,7 @@ public abstract class AbstractRocketChatCacheObserver implements Registrable { ...@@ -47,7 +43,7 @@ public abstract class AbstractRocketChatCacheObserver implements Registrable {
@Override @Override
public final void register() { public final void register() {
compositeDisposable.add( compositeDisposable.add(
new RocketChatCache(context) RocketChatCache.INSTANCE
.getSelectedRoomIdPublisher() .getSelectedRoomIdPublisher()
.filter(Optional::isPresent) .filter(Optional::isPresent)
.map(Optional::get) .map(Optional::get)
......
...@@ -18,7 +18,6 @@ public class StreamRoomMessageManager implements Registrable { ...@@ -18,7 +18,6 @@ public class StreamRoomMessageManager implements Registrable {
private final RealmHelper realmHelper; private final RealmHelper realmHelper;
private final AbstractRocketChatCacheObserver cacheObserver; private final AbstractRocketChatCacheObserver cacheObserver;
private final Handler handler; private final Handler handler;
private final RocketChatCache rocketChatCache;
private StreamRoomMessage streamRoomMessage; private StreamRoomMessage streamRoomMessage;
public StreamRoomMessageManager(Context context, String hostname, public StreamRoomMessageManager(Context context, String hostname,
...@@ -26,9 +25,8 @@ public class StreamRoomMessageManager implements Registrable { ...@@ -26,9 +25,8 @@ public class StreamRoomMessageManager implements Registrable {
this.context = context; this.context = context;
this.hostname = hostname; this.hostname = hostname;
this.realmHelper = realmHelper; this.realmHelper = realmHelper;
this.rocketChatCache = new RocketChatCache(context);
cacheObserver = new AbstractRocketChatCacheObserver(context, realmHelper) { cacheObserver = new AbstractRocketChatCacheObserver(realmHelper) {
@Override @Override
protected void onRoomIdUpdated(String roomId) { protected void onRoomIdUpdated(String roomId) {
unregisterStreamNotifyMessageIfNeeded(); unregisterStreamNotifyMessageIfNeeded();
...@@ -57,7 +55,7 @@ public class StreamRoomMessageManager implements Registrable { ...@@ -57,7 +55,7 @@ public class StreamRoomMessageManager implements Registrable {
@Override @Override
public void register() { public void register() {
cacheObserver.register(); cacheObserver.register();
String selectedRoomId = rocketChatCache.getSelectedRoomId(); String selectedRoomId = RocketChatCache.INSTANCE.getSelectedRoomId();
if (selectedRoomId == null) { if (selectedRoomId == null) {
return; return;
} }
......
...@@ -5,6 +5,7 @@ import android.content.Context; ...@@ -5,6 +5,7 @@ import android.content.Context;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import chat.rocket.android.RocketChatCache;
import chat.rocket.android.api.MethodCallHelper; import chat.rocket.android.api.MethodCallHelper;
import chat.rocket.android.helper.LogIfError; import chat.rocket.android.helper.LogIfError;
import chat.rocket.android.service.Registrable; import chat.rocket.android.service.Registrable;
...@@ -56,7 +57,14 @@ public class CurrentUserObserver extends AbstractModelObserver<RealmUser> { ...@@ -56,7 +57,14 @@ public class CurrentUserObserver extends AbstractModelObserver<RealmUser> {
} }
listeners = new ArrayList<>(); listeners = new ArrayList<>();
final String userId = user.getId(); String userId = user.getId();
String username = user.getUsername();
String name = user.getName();
RocketChatCache.INSTANCE.setUserId(userId);
RocketChatCache.INSTANCE.setUserUsername(username);
RocketChatCache.INSTANCE.setUserName(name);
// get and observe Room subscriptions. // get and observe Room subscriptions.
methodCall.getRoomSubscriptions().onSuccess(task -> { methodCall.getRoomSubscriptions().onSuccess(task -> {
......
...@@ -13,6 +13,7 @@ import chat.rocket.android.R; ...@@ -13,6 +13,7 @@ import chat.rocket.android.R;
import chat.rocket.android.RocketChatCache; import chat.rocket.android.RocketChatCache;
import chat.rocket.android.api.RaixPushHelper; import chat.rocket.android.api.RaixPushHelper;
import chat.rocket.android.helper.LogIfError; import chat.rocket.android.helper.LogIfError;
import chat.rocket.android.push.gcm.GcmPushHelper;
import chat.rocket.core.SyncState; import chat.rocket.core.SyncState;
import chat.rocket.persistence.realm.RealmHelper; import chat.rocket.persistence.realm.RealmHelper;
import chat.rocket.persistence.realm.models.ddp.RealmUser; import chat.rocket.persistence.realm.models.ddp.RealmUser;
...@@ -24,6 +25,7 @@ import io.realm.RealmResults; ...@@ -24,6 +25,7 @@ import io.realm.RealmResults;
* call raix:push-update if needed. * call raix:push-update if needed.
*/ */
public class GcmPushRegistrationObserver extends AbstractModelObserver<GcmPushRegistration> { public class GcmPushRegistrationObserver extends AbstractModelObserver<GcmPushRegistration> {
public GcmPushRegistrationObserver(Context context, String hostname, public GcmPushRegistrationObserver(Context context, String hostname,
RealmHelper realmHelper) { RealmHelper realmHelper) {
super(context, hostname, realmHelper); super(context, hostname, realmHelper);
...@@ -39,11 +41,19 @@ public class GcmPushRegistrationObserver extends AbstractModelObserver<GcmPushRe ...@@ -39,11 +41,19 @@ public class GcmPushRegistrationObserver extends AbstractModelObserver<GcmPushRe
@Override @Override
public void onUpdateResults(List<GcmPushRegistration> results) { public void onUpdateResults(List<GcmPushRegistration> results) {
if (results.isEmpty()) { String gcmToken = GcmPushHelper.INSTANCE.getGcmToken();
return; if (gcmToken != null && !gcmToken.isEmpty()) {
// We already have gcm token, so try to register it.
try {
tryToRegisterToken();
} catch (Exception e) {
e.printStackTrace();
}
}
} }
realmHelper.executeTransaction(realm -> { private Task<Void> tryToRegisterToken() {
return realmHelper.executeTransaction(realm -> {
GcmPushRegistration.queryDefault(realm).findFirst().setSyncState(SyncState.SYNCING); GcmPushRegistration.queryDefault(realm).findFirst().setSyncState(SyncState.SYNCING);
return null; return null;
}).onSuccessTask(_task -> registerGcmTokenForServer() }).onSuccessTask(_task -> registerGcmTokenForServer()
...@@ -55,7 +65,10 @@ public class GcmPushRegistrationObserver extends AbstractModelObserver<GcmPushRe ...@@ -55,7 +65,10 @@ public class GcmPushRegistrationObserver extends AbstractModelObserver<GcmPushRe
).continueWith(task -> { ).continueWith(task -> {
if (task.isFaulted()) { if (task.isFaulted()) {
realmHelper.executeTransaction(realm -> { realmHelper.executeTransaction(realm -> {
GcmPushRegistration.queryDefault(realm).findFirst().setSyncState(SyncState.FAILED); GcmPushRegistration gcmPushRegistration = GcmPushRegistration.queryDefault(realm).findFirst();
if (gcmPushRegistration != null) {
gcmPushRegistration.setSyncState(SyncState.FAILED);
}
return null; return null;
}).continueWith(new LogIfError()); }).continueWith(new LogIfError());
} }
...@@ -68,7 +81,7 @@ public class GcmPushRegistrationObserver extends AbstractModelObserver<GcmPushRe ...@@ -68,7 +81,7 @@ public class GcmPushRegistrationObserver extends AbstractModelObserver<GcmPushRe
final RealmUser currentUser = realmHelper.executeTransactionForRead(realm -> final RealmUser currentUser = realmHelper.executeTransactionForRead(realm ->
RealmUser.queryCurrentUser(realm).findFirst()); RealmUser.queryCurrentUser(realm).findFirst());
final String userId = currentUser != null ? currentUser.getId() : null; final String userId = currentUser != null ? currentUser.getId() : null;
final String pushId = new RocketChatCache(context).getOrCreatePushId(); final String pushId = RocketChatCache.INSTANCE.getOrCreatePushId();
return new RaixPushHelper(realmHelper) return new RaixPushHelper(realmHelper)
.pushUpdate(pushId, gcmToken, userId); .pushUpdate(pushId, gcmToken, userId);
......
...@@ -7,6 +7,7 @@ import java.util.List; ...@@ -7,6 +7,7 @@ import java.util.List;
import chat.rocket.android.RocketChatCache; import chat.rocket.android.RocketChatCache;
import chat.rocket.android.api.RaixPushHelper; import chat.rocket.android.api.RaixPushHelper;
import chat.rocket.android.helper.LogIfError; import chat.rocket.android.helper.LogIfError;
import chat.rocket.android.service.ConnectivityManager;
import chat.rocket.android.service.internal.StreamRoomMessageManager; import chat.rocket.android.service.internal.StreamRoomMessageManager;
import chat.rocket.persistence.realm.RealmHelper; import chat.rocket.persistence.realm.RealmHelper;
import chat.rocket.persistence.realm.models.internal.GetUsersOfRoomsProcedure; import chat.rocket.persistence.realm.models.internal.GetUsersOfRoomsProcedure;
...@@ -73,8 +74,10 @@ public class SessionObserver extends AbstractModelObserver<RealmSession> { ...@@ -73,8 +74,10 @@ public class SessionObserver extends AbstractModelObserver<RealmSession> {
// update push info // update push info
pushHelper pushHelper
.pushSetUser(new RocketChatCache(context).getOrCreatePushId()) .pushSetUser(RocketChatCache.INSTANCE.getOrCreatePushId())
.continueWith(new LogIfError()); .continueWith(new LogIfError());
ConnectivityManager.getInstance(context).notifySessionEstablished(hostname);
} }
@DebugLog @DebugLog
......
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="1000"
android:propertyName="rotation"
android:repeatCount="-1"
android:valueFrom="0"
android:valueTo="360" />
</set>
\ No newline at end of file
This diff is collapsed.
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportHeight="100.0"
android:viewportWidth="100.0">
<group
android:name="rotationGroup"
android:pivotX="50"
android:pivotY="50"
android:rotation="90">
<path
android:fillColor="#00000000"
android:pathData="M85,50A35,35 108.96,1 0,74.79 74.79"
android:strokeColor="#FFFFFF"
android:strokeWidth="12" />
<path
android:fillColor="#FFFFFF"
android:pathData="M105,49L70,49L85,65L100,49" />
</group>
</vector>
<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
tools:targetApi="lollipop" android:drawable="@drawable/ic_loading">
<target
android:name="rotationGroup"
android:animation="@anim/rotation" />
</animated-vector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#030000">
<TextView
android:id="@+id/text_view_status"
android:layout_width="wrap_content"
android:layout_height="32dp"
android:background="@color/connection_crouton_background"
android:gravity="center"
android:text="@string/server_config_activity_authenticating"
android:textAlignment="center"
android:textColor="@android:color/white"
android:textSize="16sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Authenticating…" />
<ImageView
android:id="@+id/try_again_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
app:layout_constraintBottom_toBottomOf="@+id/text_view_status"
app:layout_constraintStart_toEndOf="@+id/text_view_status"
app:layout_constraintTop_toTopOf="@+id/text_view_status"
tools:src="@drawable/ic_loading" />
</android.support.constraint.ConstraintLayout>
\ No newline at end of file
...@@ -11,84 +11,84 @@ ...@@ -11,84 +11,84 @@
<ScrollView <ScrollView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"> app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
<android.support.constraint.ConstraintLayout <android.support.constraint.ConstraintLayout
android:id="@+id/container" android:id="@+id/container"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:minWidth="280dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingStart="@dimen/margin_16" android:background="@drawable/container_bg"
android:paddingLeft="@dimen/margin_16" android:minWidth="280dp"
android:paddingBottom="@dimen/margin_8"
android:paddingEnd="@dimen/margin_16" android:paddingEnd="@dimen/margin_16"
android:paddingLeft="@dimen/margin_16"
android:paddingRight="@dimen/margin_16" android:paddingRight="@dimen/margin_16"
android:paddingStart="@dimen/margin_16"
android:paddingTop="@dimen/margin_8" android:paddingTop="@dimen/margin_8"
android:paddingBottom="@dimen/margin_8"
android:background="@drawable/container_bg"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"> app:layout_constraintTop_toTopOf="parent">
<ImageButton <ImageButton
android:id="@+id/btn_login_with_twitter" android:id="@+id/btn_login_with_twitter"
android:layout_width="48dp" android:layout_width="48dp"
android:layout_height="48dp" android:layout_height="48dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:scaleType="fitXY" android:scaleType="fitXY"
app:srcCompat="@drawable/ic_button_twitter_24dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/text_input_username" app:layout_constraintBottom_toTopOf="@+id/text_input_username"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/btn_login_with_facebook" app:layout_constraintRight_toLeftOf="@+id/btn_login_with_facebook"
android:background="?attr/selectableItemBackgroundBorderless" /> app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_button_twitter_24dp" />
<ImageButton <ImageButton
android:id="@+id/btn_login_with_facebook" android:id="@+id/btn_login_with_facebook"
android:layout_width="48dp" android:layout_width="48dp"
android:layout_height="48dp" android:layout_height="48dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:scaleType="fitXY" android:scaleType="fitXY"
app:srcCompat="@drawable/ic_button_facebook_24dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/text_input_username" app:layout_constraintBottom_toTopOf="@+id/text_input_username"
app:layout_constraintLeft_toRightOf="@+id/btn_login_with_twitter" app:layout_constraintLeft_toRightOf="@+id/btn_login_with_twitter"
app:layout_constraintRight_toLeftOf="@+id/btn_login_with_github" app:layout_constraintRight_toLeftOf="@+id/btn_login_with_github"
android:background="?attr/selectableItemBackgroundBorderless" /> app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_button_facebook_24dp" />
<ImageButton <ImageButton
android:id="@+id/btn_login_with_github" android:id="@+id/btn_login_with_github"
android:layout_width="48dp" android:layout_width="48dp"
android:layout_height="48dp" android:layout_height="48dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:scaleType="fitXY" android:scaleType="fitXY"
app:srcCompat="@drawable/ic_button_github_24dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/text_input_username" app:layout_constraintBottom_toTopOf="@+id/text_input_username"
app:layout_constraintLeft_toRightOf="@+id/btn_login_with_facebook" app:layout_constraintLeft_toRightOf="@+id/btn_login_with_facebook"
app:layout_constraintRight_toLeftOf="@+id/btn_login_with_google" app:layout_constraintRight_toLeftOf="@+id/btn_login_with_google"
android:background="?attr/selectableItemBackgroundBorderless" /> app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_button_github_24dp" />
<ImageButton <ImageButton
android:id="@+id/btn_login_with_google" android:id="@+id/btn_login_with_google"
android:layout_width="48dp" android:layout_width="48dp"
android:layout_height="48dp" android:layout_height="48dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:scaleType="fitXY" android:scaleType="fitXY"
app:srcCompat="@drawable/ic_button_google_24dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/text_input_username" app:layout_constraintBottom_toTopOf="@+id/text_input_username"
app:layout_constraintLeft_toRightOf="@+id/btn_login_with_github" app:layout_constraintLeft_toRightOf="@+id/btn_login_with_github"
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
android:background="?attr/selectableItemBackgroundBorderless" /> app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_button_google_24dp" />
<android.support.design.widget.TextInputLayout <android.support.design.widget.TextInputLayout
android:id="@+id/text_input_username" android:id="@+id/text_input_username"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/btn_login_with_twitter"
app:layout_constraintBottom_toTopOf="@+id/text_input_passwd" app:layout_constraintBottom_toTopOf="@+id/text_input_passwd"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"> app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_login_with_twitter">
<android.support.design.widget.TextInputEditText <android.support.design.widget.TextInputEditText
android:id="@+id/editor_username" android:id="@+id/editor_username"
...@@ -104,10 +104,11 @@ ...@@ -104,10 +104,11 @@
android:id="@+id/text_input_passwd" android:id="@+id/text_input_passwd"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/text_input_username" app:passwordToggleEnabled="true"
app:layout_constraintBottom_toTopOf="@+id/btn_user_registration" app:layout_constraintBottom_toTopOf="@+id/btn_user_registration"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"> app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_input_username">
<android.support.design.widget.TextInputEditText <android.support.design.widget.TextInputEditText
android:id="@+id/editor_passwd" android:id="@+id/editor_passwd"
...@@ -121,27 +122,27 @@ ...@@ -121,27 +122,27 @@
<Button <Button
android:id="@+id/btn_user_registration" android:id="@+id/btn_user_registration"
style="@style/Widget.AppCompat.Button.Colored"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_8" android:layout_marginTop="@dimen/margin_8"
android:text="@string/fragment_login_sign_up" android:text="@string/fragment_login_sign_up"
app:layout_constraintTop_toBottomOf="@+id/text_input_passwd"
app:layout_constraintRight_toLeftOf="@+id/btn_login_with_email"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
style="@style/Widget.AppCompat.Button.Colored" /> app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/btn_login_with_email"
app:layout_constraintTop_toBottomOf="@+id/text_input_passwd" />
<Button <Button
android:id="@+id/btn_login_with_email" android:id="@+id/btn_login_with_email"
style="@style/Widget.AppCompat.Button.Colored"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_8" android:layout_marginTop="@dimen/margin_8"
android:text="@string/fragment_login_sign_in" android:text="@string/fragment_login_sign_in"
app:layout_constraintTop_toBottomOf="@+id/text_input_passwd"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toRightOf="@+id/btn_user_registration"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
style="@style/Widget.AppCompat.Button.Colored" /> app:layout_constraintLeft_toRightOf="@+id/btn_user_registration"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_input_passwd" />
</android.support.constraint.ConstraintLayout> </android.support.constraint.ConstraintLayout>
</ScrollView> </ScrollView>
......
<resources>
<string name="app_name">Rocket.Chat+</string>
<string name="fragment_sidebar_main_favorite_title">Избранное</string>
<string name="fragment_sidebar_main_channels_title">Каналы</string>
<string name="fragment_sidebar_main_direct_messages_title">Личные сообщения</string>
<string name="fragment_sidebar_main_livechat_title">Чат</string>
<string name="user_status_online">Онлайн</string>
<string name="user_status_away">Отошел</string>
<string name="user_status_busy">Занят</string>
<string name="user_status_invisible">Невидимый</string>
<string name="fragment_sidebar_main_logout_title">Выход</string>
<string name="dialog_add_channel_name">Название</string>
<string name="dialog_add_channel_private">Закрытый</string>
<string name="dialog_add_channel_read_only">Только для чтения</string>
<string name="fragment_room_list_pinned_message_title">Закрепленные сообщения (%s)</string>
<string name="fragment_room_list_favorite_message_title">Избранные сообщения (%s)</string>
<string name="fragment_room_list_file_list_title">Список файлов (%s)</string>
<string name="fragment_room_list_member_list_title">Список (%s)</string>
<string name="fragment_room_list_could_not_load_your_request">Не удалось обработать запрос.\n%s.</string>
<string name="fragment_room_list_no_pinned_message_to_show">Нет закрепленных сообщений</string>
<string name="fragment_room_list_no_favorite_message_to_show">Нет избранных сообщений</string>
<string name="fragment_room_list_no_file_list_to_show">Нет файлов для показа</string>
<string name="fragment_room_list_no_member_list_to_show">Нет участников для отображения</string>
<string name="start_of_conversation">Начало переписки</string>
<string name="sending">Отправить</string>
<string name="not_synced">Не синхронизировано</string>
<string name="failed_to_sync">Ошибка синхронизации</string>
<string name="failed_to_delete">Ошибка удаления</string>
<string name="failed_to_delete_message">Сообщение не может быть удалено в это время. Повторите попытку позже</string>
<string name="resend">Повторить</string>
<string name="discard">Удалить</string>
<string name="ok">ОК</string>
<plurals name="fmt_dialog_view_latest_message_title">
<item quantity="one">%d новое сообщение</item>
<item quantity="few">%d новых сообщения</item>
<item quantity="many">%d новых сообщений</item>
</plurals>
<string name="dialog_view_latest_message_action">посмотреть</string>
<string name="file_uploading_title">Загрузка...</string>
<string name="dialog_user_registration_email">Почта</string>
<string name="dialog_user_registration_username">Имя пользователя</string>
<string name="sub_username">\@%s</string>
<string name="username">\@%s</string>
<string name="dialog_user_registration_password">Пароль</string>
<string name="fragment_home_welcome_message">Добро пожаловать в Чат.\nВыберите канал из меню.</string>
<string name="fragment_input_hostname_hostname">Адрес сервера</string>
<string name="fragment_input_hostname_server_hint">open.rocket.chat</string>
<string name="fragment_input_hostname_connect">Подключиться</string>
<string name="fragment_login_username_or_email">Имя пользователя или email</string>
<string name="fragment_login_password">Пароль</string>
<string name="fragment_login_sign_up">Зарегистрироваться</string>
<string name="fragment_login_sign_in">Войти</string>
<string name="fragment_retry_login_retry_title">Повторить</string>
<string name="fragment_retry_login_error_title">Ошибка соединения</string>
<string name="server_config_activity_authenticating">Вход...</string>
<string name="home_fragment_title">Rocket.Chat - Главная</string>
<string name="fragment_sidebar_main_unread_rooms_title">Непрочитанные каналы</string>
<string name="doc_upload_message_spec_title">Прикрепить файл</string>
<string name="image_upload_message_spec_title">Прикрепить изображения</string>
<string name="audio_upload_message_spec_title">Вложить аудио</string>
<string name="video_upload_message_spec_title">Прикрепить видео</string>
<string name="input_hostname_invalid_server_message">Сервер не найден</string>
<string name="make_sure_your_server_version_is_up_to_date">Убедитесь, что ваш сервер Rocket.Chat обновлен до последней версии</string>
<string name="connection_error_try_later">Ошибка соединения. Попробуйте позже.</string>
<string name="version_info_text">Версия: %s</string>
<string name="two_factor_authentication_title">Двухфакторная аутентификация</string>
<string name="open_your_authentication_app_and_enter_the_code">Откройте приложение для проверки подлинности и введите код</string>
<string name="two_factor_code">Код авторизации</string>
<string name="spotlight_search">Поиск</string>
<string name="spotlight_load_more_results">Еще...</string>
<string name="edit_message">Текст сообщения</string>
<string name="message_options_no_message_info">Ooops. Что-то не работает!</string>
<string name="message_options_no_permissions_info">У Вас не достаточно прав</string>
<string name="menu_pinned_messages">Закрепленные сообщения</string>
<string name="menu_favorite_messages">Избранные сообщения</string>
<string name="menu_file_list">Список файлов</string>
<string name="menu_member_list">Список коллег</string>
<string name="add_new_team">Добавить новую команду</string>
</resources>
...@@ -13,4 +13,5 @@ ...@@ -13,4 +13,5 @@
<color name="colorSecondaryTextDark">#8A000000</color> <color name="colorSecondaryTextDark">#8A000000</color>
<color name="colorDivider">#1F000000</color> <color name="colorDivider">#1F000000</color>
<color name="connection_crouton_background">#030000</color>
</resources> </resources>
\ No newline at end of file
...@@ -18,8 +18,8 @@ ...@@ -18,8 +18,8 @@
<string name="fragment_room_list_file_list_title">File list (%s)</string> <string name="fragment_room_list_file_list_title">File list (%s)</string>
<string name="fragment_room_list_member_list_title">Member list (%s)</string> <string name="fragment_room_list_member_list_title">Member list (%s)</string>
<string name="fragment_room_list_could_not_load_your_request">Could not load your request.\n%s.</string> <string name="fragment_room_list_could_not_load_your_request">Could not load your request.\n%s.</string>
<string name="fragment_room_list_no_pinned_message_to_show">No pinned message to show</string> <string name="fragment_room_list_no_pinned_message_to_show">No pinned messages to show</string>
<string name="fragment_room_list_no_favorite_message_to_show">No favorite message to show</string> <string name="fragment_room_list_no_favorite_message_to_show">No favorite messages to show</string>
<string name="fragment_room_list_no_file_list_to_show">No file list to show</string> <string name="fragment_room_list_no_file_list_to_show">No file list to show</string>
<string name="fragment_room_list_no_member_list_to_show">No member list to show</string> <string name="fragment_room_list_no_member_list_to_show">No member list to show</string>
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
<string name="username">\@%s</string> <string name="username">\@%s</string>
<string name="dialog_user_registration_password">Password</string> <string name="dialog_user_registration_password">Password</string>
<string name="fragment_home_welcome_message">Welcome to Rocket.Chat.Android\nSelect a channel from the drawer.</string> <string name="fragment_home_welcome_message">Welcome to Rocket.Chat.Android\nSelect a channel from the drawer.</string>
<string name="fragment_input_hostname_hostname">Hostname</string> <string name="fragment_input_hostname_hostname">Server</string>
<string name="fragment_input_hostname_server_hint">open.rocket.chat</string> <string name="fragment_input_hostname_server_hint">open.rocket.chat</string>
<string name="fragment_input_hostname_connect">CONNECT</string> <string name="fragment_input_hostname_connect">CONNECT</string>
<string name="fragment_login_username_or_email">Username or email</string> <string name="fragment_login_username_or_email">Username or email</string>
...@@ -55,7 +55,7 @@ ...@@ -55,7 +55,7 @@
<string name="fragment_login_sign_up">SIGN UP</string> <string name="fragment_login_sign_up">SIGN UP</string>
<string name="fragment_login_sign_in">SIGN IN</string> <string name="fragment_login_sign_in">SIGN IN</string>
<string name="fragment_retry_login_retry_title">RETRY</string> <string name="fragment_retry_login_retry_title">RETRY</string>
<string name="fragment_retry_login_error_title">Connection Error</string> <string name="fragment_retry_login_error_title">Your connection seems off…</string>
<string name="server_config_activity_authenticating">Authenticating…</string> <string name="server_config_activity_authenticating">Authenticating…</string>
<string name="home_fragment_title">Rocket.Chat - Home</string> <string name="home_fragment_title">Rocket.Chat - Home</string>
<string name="fragment_sidebar_main_unread_rooms_title">UNREAD ROOMS</string> <string name="fragment_sidebar_main_unread_rooms_title">UNREAD ROOMS</string>
......
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
<item name="actionModeBackground">?attr/colorPrimaryDark</item> <item name="actionModeBackground">?attr/colorPrimaryDark</item>
<item name="android:statusBarColor" tools:targetApi="21">?attr/colorPrimaryDark</item> <item name="android:statusBarColor" tools:targetApi="21">?attr/colorPrimaryDark</item>
<item name="android:navigationBarColor" tools:targetApi="21">?attr/colorPrimaryDark</item>
<item name="android:windowBackground">@android:color/white</item> <item name="android:windowBackground">@android:color/white</item>
</style> </style>
...@@ -27,7 +26,6 @@ ...@@ -27,7 +26,6 @@
<item name="actionModeBackground">?attr/colorPrimaryDark</item> <item name="actionModeBackground">?attr/colorPrimaryDark</item>
<item name="android:statusBarColor" tools:targetApi="21">?attr/colorPrimaryDark</item> <item name="android:statusBarColor" tools:targetApi="21">?attr/colorPrimaryDark</item>
<item name="android:navigationBarColor" tools:targetApi="21">?attr/colorPrimaryDark</item>
</style> </style>
<style name="AppTheme.Dialog" parent="Theme.AppCompat.Light.Dialog"> <style name="AppTheme.Dialog" parent="Theme.AppCompat.Light.Dialog">
......
...@@ -23,12 +23,12 @@ object OkHttpHelper { ...@@ -23,12 +23,12 @@ object OkHttpHelper {
return httpClientForUploadFile ?: throw AssertionError("httpClientForUploadFile set to null by another thread") return httpClientForUploadFile ?: throw AssertionError("httpClientForUploadFile set to null by another thread")
} }
fun getClientForDownloadFile(context: Context): OkHttpClient { fun getClientForDownloadFile(): OkHttpClient {
if(httpClientForDownloadFile == null) { if(httpClientForDownloadFile == null) {
httpClientForDownloadFile = OkHttpClient.Builder() httpClientForDownloadFile = OkHttpClient.Builder()
.followRedirects(true) .followRedirects(true)
.followSslRedirects(true) .followSslRedirects(true)
.addInterceptor(CookieInterceptor(DefaultCookieProvider(RocketChatCache(context)))) .addInterceptor(CookieInterceptor(DefaultCookieProvider()))
.build() .build()
} }
return httpClientForDownloadFile ?: throw AssertionError("httpClientForDownloadFile set to null by another thread") return httpClientForDownloadFile ?: throw AssertionError("httpClientForDownloadFile set to null by another thread")
......
...@@ -16,10 +16,10 @@ buildscript { ...@@ -16,10 +16,10 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.0.1' classpath 'com.android.tools.build:gradle:3.0.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.60" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.0"
classpath 'io.realm:realm-gradle-plugin:4.2.0' classpath 'io.realm:realm-gradle-plugin:4.2.0'
classpath 'com.jakewharton.hugo:hugo-plugin:1.2.1' classpath 'com.jakewharton.hugo:hugo-plugin:1.2.1'
classpath 'com.google.gms:google-services:3.0.0' classpath 'com.google.gms:google-services:3.1.0'
classpath 'com.github.triplet.gradle:play-publisher:1.1.5' classpath 'com.github.triplet.gradle:play-publisher:1.1.5'
classpath 'io.fabric.tools:gradle:1.+' classpath 'io.fabric.tools:gradle:1.+'
} }
......
ext { ext {
preDexLibs = "true" != System.getenv("CI") preDexLibs = "true" != System.getenv("CI")
supportLibraryVersion = "27.0.1" supportLibraryVersion = "27.0.1"
playLibVersion = '11.6.2'
constraintLayoutVersion = "1.0.2" constraintLayoutVersion = "1.0.2"
kotlinVersion = "1.1.51" kotlinVersion = "1.2.0"
okHttpVersion = "3.9.0" okHttpVersion = "3.9.0"
rxbindingVersion = '2.0.0' rxbindingVersion = '2.0.0'
rxJavaVersion = "2.1.0"
supportDependencies = [ supportDependencies = [
designSupportLibrary: "com.android.support:design:${supportLibraryVersion}", designSupportLibrary: "com.android.support:design:${supportLibraryVersion}",
...@@ -12,16 +14,23 @@ ext { ...@@ -12,16 +14,23 @@ ext {
constraintLayout : "com.android.support.constraint:constraint-layout:${constraintLayoutVersion}", constraintLayout : "com.android.support.constraint:constraint-layout:${constraintLayoutVersion}",
cardView : "com.android.support:cardview-v7:${supportLibraryVersion}", cardView : "com.android.support:cardview-v7:${supportLibraryVersion}",
supportV13 : "com.android.support:support-v13:${supportLibraryVersion}", supportV13 : "com.android.support:support-v13:${supportLibraryVersion}",
multidex : "com.android.support:multidex:1.0.2" multidex : "com.android.support:multidex:1.0.2",
customTabs : "com.android.support:customtabs:${supportLibraryVersion}"
] ]
extraDependencies = [ extraDependencies = [
okHTTP : "com.squareup.okhttp3:okhttp:${okHttpVersion}", okHTTP : "com.squareup.okhttp3:okhttp:${okHttpVersion}",
rxJava : "io.reactivex.rxjava2:rxjava:2.1.0", rxJava : "io.reactivex.rxjava2:rxjava:${rxJavaVersion}",
rxKotlin : "io.reactivex.rxjava2:rxkotlin:${rxJavaVersion}",
boltTask : "com.parse.bolts:bolts-tasks:1.4.0", boltTask : "com.parse.bolts:bolts-tasks:1.4.0",
rxAndroid : "io.reactivex.rxjava2:rxandroid:2.0.1", rxAndroid : "io.reactivex.rxjava2:rxandroid:2.0.1",
textDrawable : "com.github.rocketchat:textdrawable:1.0.2", textDrawable : "com.github.rocketchat:textdrawable:1.0.2",
optional : "com.hadisatrio:Optional:v1.0.1" optional : "com.hadisatrio:Optional:v1.0.1",
androidJob : "com.evernote:android-job:1.2.1",
jstate : "com.unquietcode.tools.jstate:jstate:2.1",
crouton : "de.keyboardsurfer.android.widget:crouton:1.8.5@aar"
] ]
rxbindingDependencies = [ rxbindingDependencies = [
rxBinding : "com.jakewharton.rxbinding2:rxbinding:${rxbindingVersion}", rxBinding : "com.jakewharton.rxbinding2:rxbinding:${rxbindingVersion}",
rxBindingSupport : "com.jakewharton.rxbinding2:rxbinding-support-v4:${rxbindingVersion}", rxBindingSupport : "com.jakewharton.rxbinding2:rxbinding-support-v4:${rxbindingVersion}",
...@@ -37,5 +46,14 @@ subprojects { ...@@ -37,5 +46,14 @@ subprojects {
project.android.dexOptions.preDexLibraries = rootProject.ext.preDexLibs project.android.dexOptions.preDexLibraries = rootProject.ext.preDexLibs
} }
} }
project.configurations.all {
resolutionStrategy.eachDependency { details ->
if (details.requested.group == 'com.android.support'
&& !details.requested.name.contains('multidex') ) {
details.useVersion "${supportLibraryVersion}"
}
}
}
} }
...@@ -30,17 +30,18 @@ android { ...@@ -30,17 +30,18 @@ android {
} }
} }
dependencies { dependencies {
compile project(':log-wrapper') api project(':log-wrapper')
compile project(':rocket-chat-core') api project(':rocket-chat-core')
compile extraDependencies.rxJava implementation extraDependencies.rxJava
compile extraDependencies.boltTask implementation extraDependencies.rxKotlin
compile supportDependencies.annotation implementation extraDependencies.boltTask
compile supportDependencies.designSupportLibrary implementation supportDependencies.annotation
compile extraDependencies.rxAndroid implementation supportDependencies.designSupportLibrary
provided extraDependencies.optional implementation extraDependencies.rxAndroid
testCompile "org.jetbrains.kotlin:kotlin-test:$rootProject.ext.kotlinVersion" implementation extraDependencies.optional
testCompile "org.jetbrains.kotlin:kotlin-test-junit:$rootProject.ext.kotlinVersion" testImplementation "org.jetbrains.kotlin:kotlin-test:$rootProject.ext.kotlinVersion"
testCompile 'org.json:json:20170516' testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$rootProject.ext.kotlinVersion"
testCompile 'org.skyscreamer:jsonassert:1.5.0' testImplementation 'org.json:json:20170516'
testCompile 'junit:junit:4.12' testImplementation 'org.skyscreamer:jsonassert:1.5.0'
testImplementation 'junit:junit:4.12'
} }
...@@ -31,6 +31,7 @@ public class RealmPublicSettingRepository extends RealmRepository ...@@ -31,6 +31,7 @@ public class RealmPublicSettingRepository extends RealmRepository
if (pair.first == null) { if (pair.first == null) {
return Flowable.empty(); return Flowable.empty();
} }
return pair.first.where(RealmPublicSetting.class) return pair.first.where(RealmPublicSetting.class)
.equalTo(RealmPublicSetting.ID, id) .equalTo(RealmPublicSetting.ID, id)
.findAll() .findAll()
...@@ -39,8 +40,21 @@ public class RealmPublicSettingRepository extends RealmRepository ...@@ -39,8 +40,21 @@ public class RealmPublicSettingRepository extends RealmRepository
pair -> close(pair.first, pair.second) pair -> close(pair.first, pair.second)
) )
.unsubscribeOn(AndroidSchedulers.from(Looper.myLooper())) .unsubscribeOn(AndroidSchedulers.from(Looper.myLooper()))
.filter(it -> it.isLoaded() && it.isValid() && it.size() > 0) .filter(it -> it.isLoaded() && it.isValid())
.map(it -> Optional.of(it.get(0).asPublicSetting())) .map(it -> getPublicSettingOrDefault(id, it))
.first(Optional.absent())); .first(Optional.absent()));
} }
private Optional<PublicSetting> getPublicSettingOrDefault(String id, RealmResults<RealmPublicSetting> results) {
if (results.size() > 0) {
return Optional.of(results.get(0).asPublicSetting());
}
PublicSetting defaultSetting = PublicSetting.builder()
.setId(id)
.setValue("")
.setUpdatedAt(0L)
.build();
return Optional.of(defaultSetting);
}
} }
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment