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 {
}
}
dependencies {
compile project(':log-wrapper')
compile extraDependencies.okHTTP
compile extraDependencies.rxJava
compile extraDependencies.boltTask
compile supportDependencies.annotation
api project(':log-wrapper')
implementation extraDependencies.okHTTP
implementation extraDependencies.rxJava
implementation extraDependencies.rxKotlin
implementation extraDependencies.boltTask
implementation supportDependencies.annotation
}
\ No newline at end of file
......@@ -84,7 +84,11 @@ public class DDPClient {
}
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()");
}
/**
......
......@@ -3,7 +3,8 @@ apply plugin: 'io.fabric'
repositories {
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'
......@@ -20,8 +21,8 @@ android {
applicationId "chat.rocket.android"
minSdkVersion 16
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 54
versionName "1.0.31"
versionCode 58
versionName "1.1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
multiDexEnabled true
......@@ -97,10 +98,9 @@ play {
track = "${track}"
}
ext {
playLibVersion = '11.6.0'
stethoVersion = '1.5.0'
stethoOkhttp3Version = '1.5.0'
stethoRealmVersion = '2.1.0'
stethoRealmVersion = '2.2.2'
rxbindingVersion = '2.0.0'
rxlifecycleVersion = '2.1.0'
icepickVersion = '3.2.0'
......@@ -108,43 +108,49 @@ ext {
}
dependencies {
compile project(':android-ddp')
compile project(':rocket-chat-android-widgets')
compile project(':persistence-realm')
compile extraDependencies.okHTTP
compile extraDependencies.rxJava
compile extraDependencies.boltTask
compile supportDependencies.multidex
compile supportDependencies.designSupportLibrary
compile supportDependencies.annotation
compile rxbindingDependencies.rxBinding
compile rxbindingDependencies.rxBindingSupport
compile rxbindingDependencies.rxBindingAppcompact
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$rootProject.ext.kotlinVersion"
compile "com.google.firebase:firebase-core:$playLibVersion"
compile "com.google.firebase:firebase-crash:$playLibVersion"
compile "com.google.android.gms:play-services-gcm:$playLibVersion"
compile "com.trello.rxlifecycle2:rxlifecycle:$rxlifecycleVersion"
compile "com.trello.rxlifecycle2:rxlifecycle-android:$rxlifecycleVersion"
compile "com.trello.rxlifecycle2:rxlifecycle-components:$rxlifecycleVersion"
compile 'nl.littlerobots.rxlint:rxlint:1.2'
compile "frankiesardo:icepick:$icepickVersion"
api project(':android-ddp')
api project(':rocket-chat-android-widgets')
api project(':persistence-realm')
implementation extraDependencies.okHTTP
implementation extraDependencies.rxJava
implementation extraDependencies.rxKotlin
implementation extraDependencies.boltTask
implementation supportDependencies.multidex
implementation supportDependencies.designSupportLibrary
implementation supportDependencies.annotation
implementation rxbindingDependencies.rxBinding
implementation rxbindingDependencies.rxBindingSupport
implementation rxbindingDependencies.rxBindingAppcompact
api "org.jetbrains.kotlin:kotlin-stdlib-jre8:$rootProject.ext.kotlinVersion"
implementation "com.google.firebase:firebase-core:$rootProject.ext.playLibVersion"
implementation "com.google.firebase:firebase-crash:$rootProject.ext.playLibVersion"
implementation "com.google.android.gms:play-services-gcm:$rootProject.ext.playLibVersion"
implementation "com.trello.rxlifecycle2:rxlifecycle:$rxlifecycleVersion"
implementation "com.trello.rxlifecycle2:rxlifecycle-android:$rxlifecycleVersion"
implementation "com.trello.rxlifecycle2:rxlifecycle-components:$rxlifecycleVersion"
implementation 'nl.littlerobots.rxlint:rxlint:1.2'
implementation "frankiesardo:icepick:$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"
compile('com.crashlytics.sdk.android:crashlytics:2.6.8@aar') {
implementation('com.crashlytics.sdk.android:crashlytics:2.6.8@aar') {
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.uphyca:stetho_realm:$stethoRealmVersion"
debugCompile "com.tspoon.traceur:traceur:1.0.1"
testCompile 'junit:junit:4.12'
testCompile 'org.robolectric:robolectric:3.3'
testCompile "org.jetbrains.kotlin:kotlin-test:$rootProject.ext.kotlinVersion"
testCompile "org.jetbrains.kotlin:kotlin-test-junit:$rootProject.ext.kotlinVersion"
testCompile "org.jetbrains.kotlin:kotlin-reflect:$rootProject.ext.kotlinVersion"
testCompile "com.nhaarman:mockito-kotlin:1.5.0"
testCompile 'org.amshove.kluent:kluent:1.14'
testImplementation 'junit:junit:4.12'
testImplementation 'org.robolectric:robolectric:3.3'
testImplementation "org.jetbrains.kotlin:kotlin-test:$rootProject.ext.kotlinVersion"
testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$rootProject.ext.kotlinVersion"
testImplementation "org.jetbrains.kotlin:kotlin-reflect:$rootProject.ext.kotlinVersion"
testImplementation "com.nhaarman:mockito-kotlin:1.5.0"
testImplementation 'org.amshove.kluent:kluent:1.14'
}
apply plugin: 'com.google.gms.google-services'
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.DefaultCookieProvider
import com.facebook.stetho.okhttp3.StethoInterceptor
......@@ -24,17 +22,18 @@ object OkHttpHelper {
return httpClientForUploadFile ?: throw AssertionError("httpClientForUploadFile set to null by another thread")
}
fun getClientForDownloadFile(context: Context): OkHttpClient {
if(httpClientForDownloadFile == null) {
fun getClientForDownloadFile(): OkHttpClient {
if (httpClientForDownloadFile == null) {
httpClientForDownloadFile = OkHttpClient.Builder()
.addNetworkInterceptor(StethoInterceptor())
.followRedirects(true)
.followSslRedirects(true)
.addInterceptor(CookieInterceptor(DefaultCookieProvider(RocketChatCache(context))))
.addInterceptor(CookieInterceptor(DefaultCookieProvider()))
.build()
}
return httpClientForDownloadFile ?: throw AssertionError("httpClientForDownloadFile set to null by another thread")
}
/**
* Returns the OkHttpClient instance for WebSocket connection.
* @return The OkHttpClient WebSocket connection instance.
......
<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.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.VIBRATE" />
<permission
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
android:name=".RocketChatApplication"
......@@ -26,39 +27,40 @@
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="adjustResize">
<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.LAUNCHER"/>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".activity.room.RoomActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="adjustResize"/>
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".activity.AddServerActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="adjustResize"
android:launchMode="singleTop"/>
android:launchMode="singleTop"
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".activity.LoginActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="adjustResize"/>
android:windowSoftInputMode="adjustResize" />
<service android:name=".service.RocketChatService"/>
<service android:name=".service.RocketChatService" />
<receiver
android:name="com.google.android.gms.gcm.GcmReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE"/>
<action android:name="com.google.android.c2dm.intent.REGISTRATION"/>
<category android:name="chat.rocket.android"/>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="chat.rocket.android" />
</intent-filter>
</receiver>
......@@ -67,8 +69,8 @@
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE"/>
<category android:name="chat.rocket.android"/>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="chat.rocket.android" />
</intent-filter>
</receiver>
......@@ -76,7 +78,8 @@
android:name="com.google.firebase.iid.FirebaseInstanceIdInternalReceiver"
android:exported="false" />
<service android:name="com.google.firebase.iid.FirebaseInstanceIdService"
<service
android:name="com.google.firebase.iid.FirebaseInstanceIdService"
android:exported="true">
<intent-filter android:priority="-500">
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
......@@ -87,7 +90,7 @@
android:name=".push.gcm.GCMIntentService"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE"/>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
......@@ -95,14 +98,16 @@
android:name=".push.gcm.GcmInstanceIDListenerService"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.gms.iid.InstanceID"/>
<action android:name="com.google.android.gms.iid.InstanceID" />
</intent-filter>
</service>
<receiver android:name=".push.PushManager$DeleteReceiver"
<receiver
android:name=".push.PushManager$DeleteReceiver"
android:exported="false" />
<receiver android:name=".push.PushManager$ReplyReceiver"
<receiver
android:name=".push.PushManager$ReplyReceiver"
android:exported="false" />
<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
......@@ -12,31 +12,31 @@ import chat.rocket.android.activity.MainActivity;
*/
public class LaunchUtil {
/**
* launch MainActivity with proper flags.
*/
public static void showMainActivity(Context context) {
Intent intent = new Intent(context, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
context.startActivity(intent);
}
/**
* launch MainActivity with proper flags.
*/
public static void showMainActivity(Context context) {
Intent intent = new Intent(context, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
context.startActivity(intent);
}
/**
* launch AddServerActivity with proper flags.
*/
public static void showAddServerActivity(Context context) {
Intent intent = new Intent(context, AddServerActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
context.startActivity(intent);
}
/**
* launch AddServerActivity with proper flags.
*/
public static void showAddServerActivity(Context context) {
Intent intent = new Intent(context, AddServerActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
context.startActivity(intent);
}
/**
* launch ServerConfigActivity with proper flags.
*/
public static void showLoginActivity(Context context, String hostname) {
Intent intent = new Intent(context, LoginActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra(LoginActivity.KEY_HOSTNAME, hostname);
context.startActivity(intent);
}
/**
* launch ServerConfigActivity with proper flags.
*/
public static void showLoginActivity(Context context, String hostname) {
Intent intent = new Intent(context, LoginActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra(LoginActivity.KEY_HOSTNAME, hostname);
context.startActivity(intent);
}
}
......@@ -5,6 +5,7 @@ import android.support.multidex.MultiDexApplication;
import android.support.v7.app.AppCompatDelegate;
import com.crashlytics.android.Crashlytics;
import com.evernote.android.job.JobManager;
import java.util.List;
......@@ -34,6 +35,8 @@ public class RocketChatApplication extends MultiDexApplication {
@Override
public void onCreate() {
super.onCreate();
RocketChatCache.INSTANCE.initialize(this);
JobManager.create(this).addJobCreator(new RocketChatJobCreator());
DDPClient.initialize(OkHttpHelper.INSTANCE.getClientForWebSocket());
Fabric.with(this, new Crashlytics());
......@@ -44,7 +47,7 @@ public class RocketChatApplication extends MultiDexApplication {
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) {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
......@@ -57,7 +60,7 @@ public class RocketChatApplication extends MultiDexApplication {
if (BuildConfig.DEBUG) {
e.printStackTrace();
}
Logger.report(e);
Logger.INSTANCE.report(e);
});
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
......@@ -8,6 +8,7 @@ import android.support.v4.app.Fragment;
import chat.rocket.android.R;
import chat.rocket.android.fragment.server_config.LoginFragment;
import chat.rocket.android.fragment.server_config.RetryLoginFragment;
import chat.rocket.android.helper.BackStackHelper;
import chat.rocket.android.service.ConnectivityManager;
import chat.rocket.core.interactors.SessionInteractor;
import chat.rocket.persistence.realm.repositories.RealmSessionRepository;
......@@ -16,77 +17,90 @@ import chat.rocket.persistence.realm.repositories.RealmSessionRepository;
* Activity for Login, Sign-up, and Retry connecting...
*/
public class LoginActivity extends AbstractFragmentActivity implements LoginContract.View {
public static final String KEY_HOSTNAME = "hostname";
public static final String KEY_HOSTNAME = "hostname";
private LoginContract.Presenter presenter;
private LoginContract.Presenter presenter;
@Override
protected int getLayoutContainerForFragment() {
return R.id.content;
}
@Override
protected int getLayoutContainerForFragment() {
return R.id.content;
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String hostname = null;
Intent intent = getIntent();
if (intent != null && intent.getExtras() != null) {
hostname = intent.getStringExtra(KEY_HOSTNAME);
}
presenter = new LoginPresenter(
hostname,
new SessionInteractor(new RealmSessionRepository(hostname)),
ConnectivityManager.getInstance(getApplicationContext())
);
}
@Override
protected void onResume() {
super.onResume();
presenter.bindView(this);
}
@Override
protected void onDestroy() {
presenter.release();
super.onDestroy();
}
private void showFragment(Fragment fragment, String hostname) {
setContentView(R.layout.simple_screen);
injectHostnameArgTo(fragment, hostname);
super.showFragment(fragment);
}
private void injectHostnameArgTo(Fragment fragment, String hostname) {
Bundle args = fragment.getArguments();
if (args == null) {
args = new Bundle();
}
args.putString(LoginActivity.KEY_HOSTNAME, hostname);
fragment.setArguments(args);
}
@Override
protected void onBackPressedNotHandled() {
moveTaskToBack(true);
}
@Override
public void showLogin(String hostname) {
showFragment(new LoginFragment(), hostname);
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@Override
public void showRetryLogin(String hostname) {
showFragment(new RetryLoginFragment(), hostname);
}
String hostname = null;
Intent intent = getIntent();
if (intent != null && intent.getExtras() != null) {
hostname = intent.getStringExtra(KEY_HOSTNAME);
@Override
public void closeView() {
finish();
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
}
presenter = new LoginPresenter(
hostname,
new SessionInteractor(new RealmSessionRepository(hostname)),
ConnectivityManager.getInstance(getApplicationContext())
);
}
@Override
protected void onResume() {
super.onResume();
presenter.bindView(this);
}
@Override
protected void onDestroy() {
presenter.release();
super.onDestroy();
}
private void showFragment(Fragment fragment, String hostname) {
setContentView(R.layout.simple_screen);
injectHostnameArgTo(fragment, hostname);
super.showFragment(fragment);
}
private void injectHostnameArgTo(Fragment fragment, String hostname) {
Bundle args = fragment.getArguments();
if (args == null) {
args = new Bundle();
@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;
}
args.putString(LoginActivity.KEY_HOSTNAME, hostname);
fragment.setArguments(args);
}
@Override
protected void onBackPressedNotHandled() {
moveTaskToBack(true);
}
@Override
public void showLogin(String hostname) {
showFragment(new LoginFragment(), hostname);
}
@Override
public void showRetryLogin(String hostname) {
showFragment(new RetryLoginFragment(), hostname);
}
@Override
public void closeView() {
finish();
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
}
}
......@@ -66,7 +66,7 @@ public class LoginPresenter extends BasePresenter<LoginContract.View>
view.closeView();
}
},
Logger::report
Logger.INSTANCE::report
);
addSubscription(subscription);
......
......@@ -40,6 +40,6 @@ public interface MainContract {
void loadSignedInServers(String hostname);
void beforeLogoutCleanUp();
void prepareToLogout();
}
}
......@@ -28,6 +28,7 @@ import chat.rocket.core.models.Session;
import chat.rocket.core.models.User;
import chat.rocket.core.repositories.PublicSettingRepository;
import chat.rocket.core.utils.Pair;
import hugo.weaving.DebugLog;
import io.reactivex.Flowable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
......@@ -40,7 +41,6 @@ public class MainPresenter extends BasePresenter<MainContract.View>
private final SessionInteractor sessionInteractor;
private final MethodCallHelper methodCallHelper;
private final ConnectivityManagerApi connectivityManagerApi;
private final RocketChatCache rocketChatCache;
private final PublicSettingRepository publicSettingRepository;
public MainPresenter(RoomInteractor roomInteractor,
......@@ -48,13 +48,12 @@ public class MainPresenter extends BasePresenter<MainContract.View>
SessionInteractor sessionInteractor,
MethodCallHelper methodCallHelper,
ConnectivityManagerApi connectivityManagerApi,
RocketChatCache rocketChatCache, PublicSettingRepository publicSettingRepository) {
PublicSettingRepository publicSettingRepository) {
this.roomInteractor = roomInteractor;
this.canCreateRoomInteractor = canCreateRoomInteractor;
this.sessionInteractor = sessionInteractor;
this.methodCallHelper = methodCallHelper;
this.connectivityManagerApi = connectivityManagerApi;
this.rocketChatCache = rocketChatCache;
this.publicSettingRepository = publicSettingRepository;
}
......@@ -96,12 +95,13 @@ public class MainPresenter extends BasePresenter<MainContract.View>
subscribeToNetworkChanges();
subscribeToUnreadCount();
subscribeToSession();
setUserOnline();
}
@Override
public void release() {
setUserAway();
if (RocketChatCache.INSTANCE.getSessionToken() != null) {
setUserAway();
}
super.release();
}
......@@ -119,7 +119,7 @@ public class MainPresenter extends BasePresenter<MainContract.View>
view.showHome();
}
},
Logger::report
Logger.INSTANCE::report
);
addSubscription(subscription);
......@@ -133,8 +133,9 @@ public class MainPresenter extends BasePresenter<MainContract.View>
addSubscription(subscription);
}
@DebugLog
@Override
public void beforeLogoutCleanUp() {
public void prepareToLogout() {
clearSubscriptions();
}
......@@ -155,13 +156,13 @@ public class MainPresenter extends BasePresenter<MainContract.View>
String logoUrl = (jsonObject.has("url")) ?
jsonObject.optString("url") : jsonObject.optString("defaultUrl");
String siteName = serverInfoPair.second;
rocketChatCache.addHostname(hostname.toLowerCase(), logoUrl, siteName);
return rocketChatCache.getServerList();
RocketChatCache.INSTANCE.addHostname(hostname.toLowerCase(), logoUrl, siteName);
return RocketChatCache.INSTANCE.getServerList();
}
private void openRoom() {
String hostname = rocketChatCache.getSelectedServerHostname();
String roomId = rocketChatCache.getSelectedRoomId();
String hostname = RocketChatCache.INSTANCE.getSelectedServerHostname();
String roomId = RocketChatCache.INSTANCE.getSelectedRoomId();
if (roomId == null || roomId.length() == 0) {
view.showHome();
......@@ -181,7 +182,7 @@ public class MainPresenter extends BasePresenter<MainContract.View>
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
pair -> view.showUnreadCount(pair.first, pair.second),
Logger::report
Logger.INSTANCE::report
);
addSubscription(subscription);
......@@ -209,10 +210,11 @@ public class MainPresenter extends BasePresenter<MainContract.View>
view.showConnecting();
return;
}
view.showConnectionOk();
// TODO: Should we remove below and above calls to view?
// view.showConnectionOk();
RocketChatCache.INSTANCE.setSessionToken(session.getToken());
},
Logger::report
Logger.INSTANCE::report
);
addSubscription(subscription);
......@@ -225,17 +227,21 @@ public class MainPresenter extends BasePresenter<MainContract.View>
.subscribe(
connectivity -> {
if (connectivity.state == ServerConnectivity.STATE_CONNECTED) {
view.showConnectionOk();
view.refreshRoom();
//TODO: notify almost connected or something like that.
// view.showConnectionOk();
} else if (connectivity.state == ServerConnectivity.STATE_DISCONNECTED) {
if (connectivity.code == DDPClient.REASON_NETWORK_ERROR) {
view.showConnectionError();
}
} else if (connectivity.state == ServerConnectivity.STATE_SESSION_ESTABLISHED) {
setUserOnline();
view.refreshRoom();
view.showConnectionOk();
} else {
view.showConnecting();
}
},
Logger::report
RCLog::e
);
addSubscription(disposable);
......
......@@ -8,42 +8,37 @@ import chat.rocket.persistence.realm.models.internal.RealmSession;
public class DefaultCookieProvider implements CookieProvider {
private RocketChatCache rocketChatCache;
public DefaultCookieProvider(RocketChatCache rocketChatCache) {
this.rocketChatCache = rocketChatCache;
}
@Override
public String getHostname() {
return getHostnameFromCache();
}
@Override
public String getCookie() {
final String hostname = getHostnameFromCache();
if (hostname == null) {
return "";
}
final RealmHelper realmHelper = RealmStore.get(getHostnameFromCache());
if (realmHelper == null) {
return "";
@Override
public String getHostname() {
return getHostnameFromCache();
}
final RealmUser user = realmHelper.executeTransactionForRead(realm ->
RealmUser.queryCurrentUser(realm).findFirst());
final RealmSession session = realmHelper.executeTransactionForRead(realm ->
RealmSession.queryDefaultSession(realm).findFirst());
@Override
public String getCookie() {
final String hostname = getHostnameFromCache();
if (hostname == null) {
return "";
}
if (user == null || session == null) {
return "";
}
final RealmHelper realmHelper = RealmStore.get(getHostnameFromCache());
if (realmHelper == null) {
return "";
}
final RealmUser user = realmHelper.executeTransactionForRead(realm ->
RealmUser.queryCurrentUser(realm).findFirst());
final RealmSession session = realmHelper.executeTransactionForRead(realm ->
RealmSession.queryDefaultSession(realm).findFirst());
return "rc_uid=" + user.getId() + ";rc_token=" + session.getToken();
}
if (user == null || session == null) {
return "";
}
private String getHostnameFromCache() {
return rocketChatCache.getSelectedServerHostname();
}
return "rc_uid=" + user.getId() + ";rc_token=" + session.getToken();
}
private String getHostnameFromCache() {
return RocketChatCache.INSTANCE.getSelectedServerHostname();
}
}
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.push.gcm.GcmPushHelper
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.MediaType
import okhttp3.Request
import okhttp3.RequestBody
import org.json.JSONObject
import java.io.IOException
/**
* Helper class for dealing with Rest API calls.
......@@ -139,6 +148,30 @@ object RestApiHelper {
.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.
*
......@@ -169,6 +202,9 @@ object RestApiHelper {
fun getEndpointUrlForMemberList(roomType: String, hostname: String): String =
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.
*
......@@ -216,4 +252,21 @@ object RestApiHelper {
}
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 {
interface View extends BaseContract.View {
void showLoader();
void hideLoader();
void hideLoader(Boolean isValidServerUrl);
void showInvalidServerError();
......
......@@ -6,12 +6,12 @@ import android.support.annotation.Nullable;
import android.support.constraint.ConstraintLayout;
import android.support.design.widget.Snackbar;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.TextView;
import chat.rocket.android.BuildConfig;
import chat.rocket.android.LaunchUtil;
import chat.rocket.android.R;
import chat.rocket.android.RocketChatCache;
import chat.rocket.android.fragment.AbstractFragment;
import chat.rocket.android.helper.TextUtils;
import chat.rocket.android.service.ConnectivityManager;
......@@ -21,90 +21,101 @@ import chat.rocket.android.service.ConnectivityManager;
*/
public class InputHostnameFragment extends AbstractFragment implements InputHostnameContract.View {
private InputHostnameContract.Presenter presenter;
private ConstraintLayout container;
private View waitingView;
public InputHostnameFragment() {}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Context appContext = getContext().getApplicationContext();
presenter = new InputHostnamePresenter(new RocketChatCache(appContext), ConnectivityManager.getInstance(appContext));
}
@Override
protected int getLayout() {
return R.layout.fragment_input_hostname;
}
@Override
protected void onSetupView() {
setupVersionInfo();
container = rootView.findViewById(R.id.container);
waitingView = rootView.findViewById(R.id.waiting);
rootView.findViewById(R.id.btn_connect).setOnClickListener(view -> handleConnect());
}
private void setupVersionInfo() {
TextView versionInfoView = (TextView) rootView.findViewById(R.id.version_info);
versionInfoView.setText(getString(R.string.version_info_text, BuildConfig.VERSION_NAME));
}
private void handleConnect() {
presenter.connectTo(getHostname());
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
presenter.bindView(this);
}
@Override
public void onDestroyView() {
presenter.release();
super.onDestroyView();
}
private String getHostname() {
final TextView editor = (TextView) rootView.findViewById(R.id.editor_hostname);
return TextUtils.or(TextUtils.or(editor.getText(), editor.getHint()), "").toString().toLowerCase();
}
private void showError(String errString) {
Snackbar.make(rootView, errString, Snackbar.LENGTH_LONG).show();
}
@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 showInvalidServerError() {
showError(getString(R.string.input_hostname_invalid_server_message));
}
@Override
public void showConnectionError() {
showError(getString(R.string.connection_error_try_later));
}
@Override
public void showHome() {
LaunchUtil.showMainActivity(getContext());
getActivity().overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
}
private InputHostnameContract.Presenter presenter;
private ConstraintLayout container;
private View waitingView;
public InputHostnameFragment() {
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Context appContext = getContext().getApplicationContext();
presenter = new InputHostnamePresenter(ConnectivityManager.getInstance(appContext));
}
@Override
protected int getLayout() {
return R.layout.fragment_input_hostname;
}
@Override
protected void onSetupView() {
setupVersionInfo();
container = rootView.findViewById(R.id.container);
waitingView = rootView.findViewById(R.id.waiting);
rootView.findViewById(R.id.btn_connect).setOnClickListener(view -> handleConnect());
}
private void setupVersionInfo() {
TextView versionInfoView = rootView.findViewById(R.id.version_info);
versionInfoView.setText(getString(R.string.version_info_text, BuildConfig.VERSION_NAME));
}
private void handleConnect() {
hideSoftKeyboard();
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
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
presenter.bindView(this);
}
@Override
public void onDestroyView() {
presenter.release();
super.onDestroyView();
}
private String getHostname() {
final TextView editor = (TextView) rootView.findViewById(R.id.editor_hostname);
return TextUtils.or(TextUtils.or(editor.getText(), editor.getHint()), "").toString().toLowerCase();
}
private void showError(String errString) {
Snackbar.make(rootView, errString, Snackbar.LENGTH_LONG).show();
}
@Override
public void showLoader() {
container.setVisibility(View.GONE);
waitingView.setVisibility(View.VISIBLE);
}
@Override
public void hideLoader(Boolean isValidServerUrl) {
if(!isValidServerUrl) {
waitingView.setVisibility(View.GONE);
container.setVisibility(View.VISIBLE);
}
}
@Override
public void showInvalidServerError() {
showError(getString(R.string.input_hostname_invalid_server_message));
}
@Override
public void showConnectionError() {
showError(getString(R.string.connection_error_try_later));
}
@Override
public void showHome() {
LaunchUtil.showMainActivity(getContext());
getActivity().overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
}
}
......@@ -14,11 +14,10 @@ import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
public class InputHostnamePresenter extends BasePresenter<InputHostnameContract.View> implements InputHostnameContract.Presenter {
private final RocketChatCache rocketChatCache;
private final ConnectivityManagerApi connectivityManager;
private boolean isValidServerUrl;
public InputHostnamePresenter(RocketChatCache rocketChatCache, ConnectivityManagerApi connectivityManager) {
this.rocketChatCache = rocketChatCache;
public InputHostnamePresenter(ConnectivityManagerApi connectivityManager) {
this.connectivityManager = connectivityManager;
}
......@@ -37,24 +36,25 @@ public class InputHostnamePresenter extends BasePresenter<InputHostnameContract.
final Disposable subscription = ServerPolicyHelper.isApiVersionValid(validationHelper)
.subscribeOn(AndroidSchedulers.from(BackgroundLooper.get()))
.observeOn(AndroidSchedulers.mainThread())
.doOnTerminate(() -> view.hideLoader())
.doOnTerminate(() -> view.hideLoader(isValidServerUrl))
.subscribe(
serverValidation -> {
if (serverValidation.isValid()) {
isValidServerUrl=true;
onServerValid(hostname, serverValidation.usesSecureConnection());
} else {
view.showInvalidServerError();
}
},
throwable -> {
Logger.report(throwable);
Logger.INSTANCE.report(throwable);
view.showConnectionError();
});
addSubscription(subscription);
}
private void onServerValid(String hostname, boolean usesSecureConnection) {
rocketChatCache.setSelectedServerHostname(hostname);
RocketChatCache.INSTANCE.setSelectedServerHostname(hostname);
String server = hostname.replace("/", ".");
connectivityManager.addOrUpdateServer(server, server, !usesSecureConnection);
......
......@@ -11,7 +11,7 @@ import chat.rocket.android.fragment.AbstractFragment;
import chat.rocket.android.widget.RoomToolbar;
import chat.rocket.core.models.User;
abstract class AbstractChatRoomFragment extends AbstractFragment {
public abstract class AbstractChatRoomFragment extends AbstractFragment {
private RoomToolbar roomToolbar;
@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
private MethodCallHelper methodCallHelper;
private AbsoluteUrlHelper absoluteUrlHelper;
private Message edittingMessage = null;
private Message editingMessage = null;
private RoomToolbar toolbar;
......@@ -344,7 +344,7 @@ public class RoomFragment extends AbstractChatRoomFragment implements
optionalPane.ifPresent(pane -> pane.setPanelSlideListener(new SlidingPaneLayout.PanelSlideListener() {
@Override
public void onPanelSlide(View view, float v) {
public void onPanelSlide(@NonNull View view, float v) {
messageFormManager.enableComposingText(false);
sidebarFragment.clearSearchViewFocus();
//Ref: ActionBarDrawerToggle#setProgress
......@@ -352,12 +352,12 @@ public class RoomFragment extends AbstractChatRoomFragment implements
}
@Override
public void onPanelOpened(View view) {
public void onPanelOpened(@NonNull View view) {
toolbar.setNavigationIconVerticalMirror(true);
}
@Override
public void onPanelClosed(View view) {
public void onPanelClosed(@NonNull View view) {
messageFormManager.enableComposingText(true);
toolbar.setNavigationIconVerticalMirror(false);
subPane.closePane();
......@@ -487,8 +487,8 @@ public class RoomFragment extends AbstractChatRoomFragment implements
@Override
public boolean onBackPressed() {
if (edittingMessage != null) {
edittingMessage = null;
if (editingMessage != null) {
editingMessage = null;
messageFormManager.clearComposingText();
}
return false;
......@@ -540,22 +540,22 @@ public class RoomFragment extends AbstractChatRoomFragment implements
inputContentInfo.releasePermission();
} catch (Exception e) {
RCLog.e(e);
Logger.report(e);
Logger.INSTANCE.report(e);
}
return true;
}
private void sendMessage(String messageText) {
if (edittingMessage == null) {
if (editingMessage == null) {
presenter.sendMessage(messageText);
} else {
presenter.updateMessage(edittingMessage, messageText);
presenter.updateMessage(editingMessage, messageText);
}
}
@Override
public void setupWith(RocketChatAbsoluteUrl rocketChatAbsoluteUrl) {
public void setupWith(@NonNull RocketChatAbsoluteUrl rocketChatAbsoluteUrl) {
if (rocketChatAbsoluteUrl != null) {
token = rocketChatAbsoluteUrl.getToken();
userId = rocketChatAbsoluteUrl.getUserId();
......@@ -564,7 +564,7 @@ public class RoomFragment extends AbstractChatRoomFragment implements
}
@Override
public void render(Room room) {
public void render(@NonNull Room room) {
roomType = room.getType();
setToolbarTitle(room.getName());
......@@ -589,7 +589,7 @@ public class RoomFragment extends AbstractChatRoomFragment implements
}
@Override
public void showUserStatus(User user) {
public void showUserStatus(@NonNull User user) {
showToolbarUserStatuslIcon(user.getStatus());
}
......@@ -610,7 +610,7 @@ public class RoomFragment extends AbstractChatRoomFragment implements
public void onMessageSendSuccessfully() {
scrollToLatestMessage();
messageFormManager.onMessageSend();
edittingMessage = null;
editingMessage = null;
}
@Override
......@@ -629,15 +629,16 @@ public class RoomFragment extends AbstractChatRoomFragment implements
}
@Override
public void showMessages(List<Message> messages) {
public void showMessages(@NonNull List<? extends Message> messages) {
if (messageListAdapter == null) {
return;
}
messageListAdapter.updateData(messages);
messageListAdapter.updateData((List<Message>) messages);
}
@Override
public void showMessageSendFailure(Message message) {
public void showMessageSendFailure(@NonNull Message message) {
new AlertDialog.Builder(getContext())
.setPositiveButton(R.string.resend,
(dialog, which) -> presenter.resendMessage(message))
......@@ -648,7 +649,7 @@ public class RoomFragment extends AbstractChatRoomFragment implements
}
@Override
public void showMessageDeleteFailure(Message message) {
public void showMessageDeleteFailure(@NonNull Message message) {
new AlertDialog.Builder(getContext())
.setTitle(getContext().getString(R.string.failed_to_delete))
.setMessage(getContext().getString(R.string.failed_to_delete_message))
......@@ -667,12 +668,12 @@ public class RoomFragment extends AbstractChatRoomFragment implements
}
@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);
}
@Override
public void onCopy(String message) {
public void onCopy(@NonNull String message) {
RocketChatApplication context = RocketChatApplication.getInstance();
ClipboardManager clipboardManager =
(ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
......@@ -680,7 +681,7 @@ public class RoomFragment extends AbstractChatRoomFragment implements
}
@Override
public void showMessageActions(Message message) {
public void showMessageActions(@NonNull Message message) {
Activity context = getActivity();
if (context != null && context instanceof MainActivity) {
MessagePopup.take(message)
......@@ -694,7 +695,7 @@ public class RoomFragment extends AbstractChatRoomFragment implements
}
private void onEditMessage(Message message) {
edittingMessage = message;
editingMessage = message;
messageFormManager.setEditMessage(message.getMessage());
}
......@@ -716,7 +717,7 @@ public class RoomFragment extends AbstractChatRoomFragment implements
}
}
public void loadMessages() {
presenter.loadMessages();
public void loadMissedMessages() {
presenter.loadMissedMessages();
}
}
\ No newline at end of file
......@@ -23,13 +23,14 @@ import java.sql.Timestamp
* Created by Filipe de Lima Brito (filipedelimabrito@gmail.com) on 9/22/17.
*/
class RoomListPresenter(val context: Context, val view: RoomListContract.View) : RoomListContract.Presenter {
private lateinit var TAG: String
override fun requestPinnedMessages(roomId: String,
roomType: String,
hostname: String,
token: String,
userId: String,
offset: Int) {
TAG = "pinned"
view.showWaitingView(true)
OkHttpHelper.getClient()
.newCall(RestApiHelper.getRequestForPinnedMessages(roomId,
......@@ -53,7 +54,7 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) :
if (response.isSuccessful) {
val result = response.body()?.string()
if (result != null) {
handleMessagesJson(result, true)
handleMessagesJson(result, true, TAG)
}
} else {
showErrorMessage(response.message())
......@@ -68,6 +69,7 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) :
token: String,
userId: String,
offset: Int) {
TAG = "favorite"
view.showWaitingView(true)
OkHttpHelper.getClient()
.newCall(RestApiHelper.getRequestForFavoriteMessages(roomId,
......@@ -91,7 +93,7 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) :
if (response.isSuccessful) {
val result = response.body()?.string()
if (result != null) {
handleMessagesJson(result, false)
handleMessagesJson(result, false, TAG)
}
} else {
showErrorMessage(response.message())
......@@ -180,7 +182,7 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) :
OkHttpHelper.getClient().dispatcher().cancelAll()
}
private fun handleMessagesJson(json: String, isPinnedMessage: Boolean) {
private fun handleMessagesJson(json: String, isPinnedMessage: Boolean, TAG: String) {
try {
val jSONObject = JSONObject(json)
val messagesJSONArray = jSONObject.getJSONArray("messages")
......@@ -204,7 +206,10 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) :
}
if (dataSet.isEmpty() && !hasItem) {
showEmptyViewMessage(context.getString(R.string.fragment_room_list_no_favorite_message_to_show))
if (TAG.equals("favorite"))
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 {
if (dataSet.isNotEmpty()) {
hasItem = true
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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