Commit caac8e2f authored by Leonardo Aramaki's avatar Leonardo Aramaki Committed by GitHub

Merge branch 'develop' into develop

parents 13af30b8 38b8792c
# Contributing to Rocket.Chat
:+1::tada: First off, thanks for taking the time to contribute! :tada::+1:
The following is a set of guidelines for contributing to Rocket.Chat and its packages, which are hosted in the [Rocket.Chat Organization](https://github.com/RocketChat) on GitHub.
__Note:__ If there's a feature you'd like, there's a bug you'd like to fix, or you'd just like to get involved please raise an issue and start a conversation. We'll help as much as we can so you can get contributing - although we may not always be able to respond right away :)
## Coding standards
We are following / moving to [Google Java Style](https://google.github.io/styleguide/javaguide.html). There's a nice IntelliJ style file for the project in `config/quality/style-guide` for code formatting. (Note: We'll be hosting the style guide file until it's updated in the official repo)
We are evaluating the Google's IntelliJ (and therefore Android Studio) [plugin](https://plugins.jetbrains.com/plugin/8527) for code formatting.
We acknowledge all the code does not meet these standards but we are working to change this over time.
### Syntax check
Before submitting a PR you should get no errors on `checkstyle`.
Just run:
```
./gradlew checkstyle
```
Your Rocket.Chat.Android version: (make sure you are running the latest) Before writing an issue, please make sure you're talking about the native application and not the Cordova one. If you are looking to open an issue to the Cordova application, go to this URL: https://github.com/RocketChat/Rocket.Chat.Cordova.
<!-- Version can be found by opening the side menu and then clicking on the chevron alongside username -->
<!-- Found a bug? List all devices that reproduced it and all that doesn't --> - Your Rocket.Chat.Android app version: ####
Mobile device model and OS version: (e.g. "Nexus 7 - Android 6.0.1") <!-- Make sure you are running the latest version (which can be found on the hostname screen or by opening the side menu and then clicking on the chevron alongside username -->
<!-- Don't forget to list the steps to reproduce. Stack traces may help too :) --> - Your Rocket.Chat server version: ####
- Device model (or emulator) you're running with: ####
<!-- e.g. Nexus 7 - Android 6.0.1 -->
- Steps to reproduce:
<!-- Stack traces may help too. -->
**The app isn't connecting to your server?**
Make sure your server supports WebSocket. These are the minimum requirements for Apache 2.4 and Nginx 1.3 or greater.
# Contributing Guidelines - Rocket.Chat.Android
Great to have you here! Here are a few ways you can help make this project better!
## Reporting an Issue
[Github Issues](https://github.com/RocketChat/Rocket.Chat.Android/issues) are used to track todos, bugs, feature requests, and more.
## Setting up a development environment
In case you're interested in playing around with the code or giving something back, here are some instructions on how to set up your project:
### Pre-requisites
1. [Android Studio and SDK Tools](https://developer.android.com/studio/index.html).
2. Clone this repo:
```
git clone https://github.com/RocketChat/Rocket.Chat.Android
```
3. Build the project.
### Code style guide
Before submitting a PR you should follow our [Coding Style](https://github.com/RocketChat/Rocket.Chat.Android/blob/develop/CODING_STYLE.md).
...@@ -10,16 +10,25 @@ ...@@ -10,16 +10,25 @@
Retrolambda needs java8 to be installed on your system Retrolambda needs java8 to be installed on your system
``` ```
export ANDROID_HOME=/path/to/android/sdk $ export ANDROID_HOME=/path/to/android/sdk
$ git clone https://github.com/RocketChat/Rocket.Chat.Android.git
$ cd Rocket.Chat.Android
$ echo "sdk.dir="$ANDROID_HOME > local.properties
$ ./gradlew assembleDebug
(> gradlew assembleDebug on Windows)
```
git clone https://github.com/RocketChat/Rocket.Chat.Android.git ### How to send APK to device
cd Rocket.Chat.Android
echo "sdk.dir="$ANDROID_HOME > local.properties The following steps are only needed if running via command line. They are not needed if you are building via Android Studio.
./gradlew assembleDebug Ensure that ADB recognizes your device with `$ adb devices`.
```
If a single device exists, install via `$ adb install /path/to/apk.apk`.
Assuming you used Gradle like earlier, the file will be called `module_name-debug.apk` in `project_name/module_name/build/outputs/apk/`.
Alternatively, you can simply run `$ ./gradlew installDebug` (`> gradlew installDebug` on Windows) to build, deploy, and debug all in a single command.
## Bug report & Feature request ## Bug report & Feature request
......
...@@ -11,11 +11,9 @@ buildscript { ...@@ -11,11 +11,9 @@ buildscript {
classpath 'me.tatarka.retrolambda.projectlombok:lombok.ast:0.2.3.a2' classpath 'me.tatarka.retrolambda.projectlombok:lombok.ast:0.2.3.a2'
} }
} }
android { android {
compileSdkVersion rootProject.ext.compileSdkVersion compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion buildToolsVersion rootProject.ext.buildToolsVersion
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8
...@@ -33,15 +31,10 @@ android { ...@@ -33,15 +31,10 @@ android {
} }
} }
} }
dependencies { dependencies {
compile project(':log-wrapper') compile project(':log-wrapper')
compile extraDependencies.okHTTP
compile "com.android.support:support-annotations:$rootProject.ext.supportLibraryVersion" compile extraDependencies.rxJava
compile extraDependencies.boltTask
compile "com.squareup.okhttp3:okhttp:$rootProject.ext.okHttpVersion" compile supportDependencies.annotation
compile 'io.reactivex.rxjava2:rxjava:2.1.0'
compile 'com.parse.bolts:bolts-tasks:1.4.0'
} }
\ No newline at end of file
package chat.rocket.android_ddp; package chat.rocket.android_ddp;
import android.support.annotation.Nullable;
import io.reactivex.Flowable;
import io.reactivex.Maybe;
import io.reactivex.annotations.Nullable;
import org.json.JSONArray; import org.json.JSONArray;
import bolts.Task; import bolts.Task;
import bolts.TaskCompletionSource; import bolts.TaskCompletionSource;
import chat.rocket.android_ddp.rx.RxWebSocketCallback; import chat.rocket.android_ddp.rx.RxWebSocketCallback;
import io.reactivex.Flowable;
import io.reactivex.Maybe;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
public class DDPClient { public class DDPClient {
......
...@@ -22,7 +22,6 @@ buildscript { ...@@ -22,7 +22,6 @@ buildscript {
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:2.3.3' classpath 'com.android.tools.build:gradle:2.3.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$rootProject.ext.kotlinVersion" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$rootProject.ext.kotlinVersion"
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files
classpath 'me.tatarka:gradle-retrolambda:3.5.0' classpath 'me.tatarka:gradle-retrolambda:3.5.0'
...@@ -46,8 +45,8 @@ android { ...@@ -46,8 +45,8 @@ android {
applicationId "chat.rocket.android" applicationId "chat.rocket.android"
minSdkVersion 16 minSdkVersion 16
targetSdkVersion rootProject.ext.targetSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 41 versionCode 43
versionName "1.0.21" versionName "1.0.22"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
multiDexEnabled true multiDexEnabled true
...@@ -115,7 +114,6 @@ play { ...@@ -115,7 +114,6 @@ play {
jsonFile = file('rocket-chat.json') jsonFile = file('rocket-chat.json')
track = "${track}" track = "${track}"
} }
ext { ext {
playLibVersion = '11.0.4' playLibVersion = '11.0.4'
stethoVersion = '1.5.0' stethoVersion = '1.5.0'
...@@ -128,67 +126,53 @@ ext { ...@@ -128,67 +126,53 @@ ext {
} }
dependencies { dependencies {
compile project(':log-wrapper')
compile project(':android-ddp') compile project(':android-ddp')
compile project(':rocket-chat-core')
compile project(':rocket-chat-android-widgets') compile project(':rocket-chat-android-widgets')
compile project(':persistence-realm') compile project(':persistence-realm')
compile extraDependencies.okHTTP
compile "com.android.support:appcompat-v7:$rootProject.ext.supportLibraryVersion" compile extraDependencies.rxJava
compile "com.android.support:design:$rootProject.ext.supportLibraryVersion" compile extraDependencies.boltTask
compile "com.android.support:support-annotations:$rootProject.ext.supportLibraryVersion" compile supportDependencies.designSupportLibrary
compile "com.android.support.constraint:constraint-layout:$rootProject.ext.constraintLayoutVersion" compile supportDependencies.annotation
compile supportDependencies.kotlin;
compile rxbindingDependencies.rxBinding
compile rxbindingDependencies.rxBindingSupport
compile rxbindingDependencies.rxBindingAppcompact
compile 'com.android.support:multidex:1.0.1' compile 'com.android.support:multidex:1.0.1'
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$rootProject.ext.kotlinVersion"
testCompile "org.jetbrains.kotlin:kotlin-test:$rootProject.ext.kotlinVersion"
testCompile "org.jetbrains.kotlin:kotlin-test-junit:$rootProject.ext.kotlinVersion"
compile "com.google.firebase:firebase-core:$playLibVersion" compile "com.google.firebase:firebase-core:$playLibVersion"
compile "com.google.firebase:firebase-crash:$playLibVersion" compile "com.google.firebase:firebase-crash:$playLibVersion"
compile "com.google.android.gms:play-services-gcm:$playLibVersion" compile "com.google.android.gms:play-services-gcm:$playLibVersion"
compile "com.squareup.okhttp3:okhttp:$rootProject.ext.okHttpVersion"
debugCompile "com.facebook.stetho:stetho:$stethoVersion" debugCompile "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"
compile "com.jakewharton.rxbinding2:rxbinding:$rxbindingVersion"
compile "com.jakewharton.rxbinding2:rxbinding-support-v4:$rxbindingVersion"
compile "com.jakewharton.rxbinding2:rxbinding-appcompat-v7:$rxbindingVersion"
compile "com.trello.rxlifecycle2:rxlifecycle:$rxlifecycleVersion" compile "com.trello.rxlifecycle2:rxlifecycle:$rxlifecycleVersion"
compile "com.trello.rxlifecycle2:rxlifecycle-android:$rxlifecycleVersion" compile "com.trello.rxlifecycle2:rxlifecycle-android:$rxlifecycleVersion"
compile "com.trello.rxlifecycle2:rxlifecycle-components:$rxlifecycleVersion" compile "com.trello.rxlifecycle2:rxlifecycle-components:$rxlifecycleVersion"
compile 'nl.littlerobots.rxlint:rxlint:1.2' compile 'nl.littlerobots.rxlint:rxlint:1.2'
compile 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
compile "frankiesardo:icepick:$icepickVersion" compile "frankiesardo:icepick:$icepickVersion"
provided "frankiesardo:icepick-processor:$icepickVersion" provided "frankiesardo:icepick-processor:$icepickVersion"
compile "com.github.hotchemi:permissionsdispatcher:$permissionsdispatcherVersion" compile "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') { compile('com.crashlytics.sdk.android:crashlytics:2.6.8@aar') {
transitive = true; transitive = true;
} }
debugCompile "com.tspoon.traceur:traceur:1.0.1" debugCompile "com.tspoon.traceur:traceur:1.0.1"
compile 'com.aurelhubert:ahbottomnavigation:2.0.6'
provided 'com.parse.bolts:bolts-tasks:1.4.0' compile('com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.10.6@aar') {
provided 'io.reactivex.rxjava2:rxjava:2.1.0' transitive = true
}
compile 'com.github.JakeWharton:ViewPagerIndicator:2.4.1@aar'
compile 'com.jakewharton:butterknife:8.5.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1'
compile 'com.jakewharton.timber:timber:4.5.1'
compile 'com.github.matrixxun:MaterialBadgeTextView:c5a27e8243'
compile 'com.github.chrisbanes:PhotoView:2.0.0'
provided 'io.reactivex:rxjava:1.3.0' provided 'io.reactivex:rxjava:1.3.0'
provided "com.github.akarnokd:rxjava2-interop:0.10.2" provided "com.github.akarnokd:rxjava2-interop:0.10.2"
provided 'com.hadisatrio:Optional:v1.0.1' provided 'com.hadisatrio:Optional:v1.0.1'
testCompile 'junit:junit:4.12' testCompile 'junit:junit:4.12'
testCompile "org.mockito:mockito-core:2.7.19" testCompile "org.mockito:mockito-core:2.7.19"
testCompile "org.jetbrains.kotlin:kotlin-test:$rootProject.ext.kotlinVersion" testCompile "org.jetbrains.kotlin:kotlin-test:$rootProject.ext.kotlinVersion"
testCompile "org.jetbrains.kotlin:kotlin-test-junit:$rootProject.ext.kotlinVersion" testCompile "org.jetbrains.kotlin:kotlin-test-junit:$rootProject.ext.kotlinVersion"
} }
apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.gms.google-services'
...@@ -36,7 +36,7 @@ public class RocketChatApplicationDebug extends RocketChatApplication { ...@@ -36,7 +36,7 @@ public class RocketChatApplicationDebug extends RocketChatApplication {
private void enableStetho() { private void enableStetho() {
Stetho.initialize(Stetho.newInitializerBuilder(this) Stetho.initialize(Stetho.newInitializerBuilder(this)
.enableDumpapp(Stetho.defaultDumperPluginsProvider(this)) .enableDumpapp(Stetho.defaultDumperPluginsProvider(this))
.enableWebKitInspector(RealmInspectorModulesProvider.builder(this).build()) .enableWebKitInspector(RealmInspectorModulesProvider.builder(this).withLimit(Long.MAX_VALUE).build())
.build()); .build());
} }
} }
\ No newline at end of file
...@@ -172,7 +172,10 @@ public class RocketChatCache { ...@@ -172,7 +172,10 @@ public class RocketChatCache {
} }
public Flowable<Optional<String>> getSelectedRoomIdPublisher() { public Flowable<Optional<String>> getSelectedRoomIdPublisher() {
return getValuePublisher(KEY_SELECTED_ROOM_ID); 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() { private SharedPreferences getSharedPreferences() {
......
...@@ -3,14 +3,11 @@ package chat.rocket.android.activity; ...@@ -3,14 +3,11 @@ package chat.rocket.android.activity;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import com.hadisatrio.optional.Optional; import com.hadisatrio.optional.Optional;
import io.reactivex.android.schedulers.AndroidSchedulers;
import org.json.JSONException; import io.reactivex.disposables.CompositeDisposable;
import org.json.JSONObject; import io.reactivex.schedulers.Schedulers;
import java.util.List; import java.util.List;
import chat.rocket.android.LaunchUtil; import chat.rocket.android.LaunchUtil;
import chat.rocket.android.RocketChatCache; import chat.rocket.android.RocketChatCache;
import chat.rocket.android.helper.Logger; import chat.rocket.android.helper.Logger;
...@@ -21,9 +18,6 @@ import chat.rocket.core.models.ServerInfo; ...@@ -21,9 +18,6 @@ import chat.rocket.core.models.ServerInfo;
import chat.rocket.persistence.realm.RealmStore; import chat.rocket.persistence.realm.RealmStore;
import chat.rocket.persistence.realm.models.ddp.RealmRoom; import chat.rocket.persistence.realm.models.ddp.RealmRoom;
import icepick.State; import icepick.State;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
abstract class AbstractAuthedActivity extends AbstractFragmentActivity { abstract class AbstractAuthedActivity extends AbstractFragmentActivity {
@State protected String hostname; @State protected String hostname;
...@@ -33,6 +27,7 @@ abstract class AbstractAuthedActivity extends AbstractFragmentActivity { ...@@ -33,6 +27,7 @@ abstract class AbstractAuthedActivity extends AbstractFragmentActivity {
private CompositeDisposable compositeDisposable = new CompositeDisposable(); private CompositeDisposable compositeDisposable = new CompositeDisposable();
private boolean isNotification; private boolean isNotification;
@Override @Override
protected void onCreate(@Nullable Bundle savedInstanceState) { protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
...@@ -198,9 +193,8 @@ abstract class AbstractAuthedActivity extends AbstractFragmentActivity { ...@@ -198,9 +193,8 @@ abstract class AbstractAuthedActivity extends AbstractFragmentActivity {
compositeDisposable.add( compositeDisposable.add(
rocketChatCache.getSelectedRoomIdPublisher() rocketChatCache.getSelectedRoomIdPublisher()
.filter(Optional::isPresent)
.map(Optional::get) .map(Optional::get)
.map(this::convertStringToJsonObject)
.map(jsonObject -> jsonObject.optString(rocketChatCache.getSelectedServerHostname(), null))
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe( .subscribe(
...@@ -209,11 +203,4 @@ abstract class AbstractAuthedActivity extends AbstractFragmentActivity { ...@@ -209,11 +203,4 @@ abstract class AbstractAuthedActivity extends AbstractFragmentActivity {
) )
); );
} }
private JSONObject convertStringToJsonObject(String json) throws JSONException {
if (json == null) {
return new JSONObject();
}
return new JSONObject(json);
}
} }
...@@ -48,7 +48,8 @@ public class MainActivity extends AbstractAuthedActivity implements MainContract ...@@ -48,7 +48,8 @@ public class MainActivity extends AbstractAuthedActivity implements MainContract
private SlidingPaneLayout pane; private SlidingPaneLayout pane;
private MainContract.Presenter presenter; private MainContract.Presenter presenter;
protected int getLayoutContainerForFragment() { @Override
public int getLayoutContainerForFragment() {
return R.id.activity_main_container; return R.id.activity_main_container;
} }
......
...@@ -9,7 +9,6 @@ import kotlinx.android.synthetic.main.activity_room.* ...@@ -9,7 +9,6 @@ import kotlinx.android.synthetic.main.activity_room.*
class RoomActivity : AppCompatActivity() { class RoomActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_room) setContentView(R.layout.activity_room)
...@@ -35,8 +34,7 @@ class RoomActivity : AppCompatActivity() { ...@@ -35,8 +34,7 @@ class RoomActivity : AppCompatActivity() {
} }
private fun addFragment(fragment: Fragment, tag: String) { private fun addFragment(fragment: Fragment, tag: String) {
supportFragmentManager supportFragmentManager.beginTransaction()
.beginTransaction()
.add(R.id.fragment_container, fragment, tag) .add(R.id.fragment_container, fragment, tag)
.commit() .commit()
} }
......
...@@ -30,7 +30,7 @@ public class DDPClientWrapper { ...@@ -30,7 +30,7 @@ public class DDPClientWrapper {
} }
/** /**
* create new API client instance. * build new API client instance.
*/ */
public static DDPClientWrapper create(String hostname) { public static DDPClientWrapper create(String hostname) {
return new DDPClientWrapper(hostname); return new DDPClientWrapper(hostname);
......
...@@ -96,6 +96,7 @@ object RestApiHelper { ...@@ -96,6 +96,7 @@ object RestApiHelper {
val parsedHttpUrl = HttpUrl.parse(getEndpointUrlForFileList(roomType, hostname)) val parsedHttpUrl = HttpUrl.parse(getEndpointUrlForFileList(roomType, hostname))
?.newBuilder() ?.newBuilder()
?.addQueryParameter("roomId", roomId) ?.addQueryParameter("roomId", roomId)
?.addQueryParameter("sort", "{\"uploadedAt\":-1}")
?.addQueryParameter("offset", offset) ?.addQueryParameter("offset", offset)
?.build() ?.build()
...@@ -178,7 +179,7 @@ object RestApiHelper { ...@@ -178,7 +179,7 @@ object RestApiHelper {
var restApiUrl: String? = null var restApiUrl: String? = null
when (roomType) { when (roomType) {
Room.TYPE_CHANNEL -> restApiUrl = "/api/v1/channels.messages" Room.TYPE_CHANNEL -> restApiUrl = "/api/v1/channels.messages"
Room.TYPE_PRIVATE -> restApiUrl = "/api/v1/groups.messages" Room.TYPE_GROUP -> restApiUrl = "/api/v1/groups.messages"
Room.TYPE_DIRECT_MESSAGE -> restApiUrl = "/api/v1/dm.messages" Room.TYPE_DIRECT_MESSAGE -> restApiUrl = "/api/v1/dm.messages"
} }
return restApiUrl return restApiUrl
...@@ -194,7 +195,7 @@ object RestApiHelper { ...@@ -194,7 +195,7 @@ object RestApiHelper {
var restApiUrl: String? = null var restApiUrl: String? = null
when (roomType) { when (roomType) {
Room.TYPE_CHANNEL -> restApiUrl = "/api/v1/channels.files" Room.TYPE_CHANNEL -> restApiUrl = "/api/v1/channels.files"
Room.TYPE_PRIVATE -> restApiUrl = "/api/v1/groups.files" Room.TYPE_GROUP -> restApiUrl = "/api/v1/groups.files"
Room.TYPE_DIRECT_MESSAGE -> restApiUrl = "/api/v1/dm.files" Room.TYPE_DIRECT_MESSAGE -> restApiUrl = "/api/v1/dm.files"
} }
return restApiUrl return restApiUrl
...@@ -210,7 +211,7 @@ object RestApiHelper { ...@@ -210,7 +211,7 @@ object RestApiHelper {
var restApiUrl: String? = null var restApiUrl: String? = null
when (roomType) { when (roomType) {
Room.TYPE_CHANNEL -> restApiUrl = "/api/v1/channels.members" Room.TYPE_CHANNEL -> restApiUrl = "/api/v1/channels.members"
Room.TYPE_PRIVATE -> restApiUrl = "/api/v1/groups.members" Room.TYPE_GROUP -> restApiUrl = "/api/v1/groups.members"
Room.TYPE_DIRECT_MESSAGE -> restApiUrl = "/api/v1/dm.members" Room.TYPE_DIRECT_MESSAGE -> restApiUrl = "/api/v1/dm.members"
} }
return restApiUrl return restApiUrl
......
...@@ -29,4 +29,8 @@ public class RocketChatAbsoluteUrl implements AbsoluteUrl { ...@@ -29,4 +29,8 @@ public class RocketChatAbsoluteUrl implements AbsoluteUrl {
public String getToken() { public String getToken() {
return token; return token;
} }
public String getBaseUrl() {
return baseUrl;
}
} }
\ No newline at end of file
package chat.rocket.android.fragment.chatroom; package chat.rocket.android.fragment.chatroom;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import chat.rocket.core.models.User;
import java.util.List; import java.util.List;
import chat.rocket.android.shared.BaseContract; import chat.rocket.android.shared.BaseContract;
import chat.rocket.android.widget.AbsoluteUrl;
import chat.rocket.core.models.Message; import chat.rocket.core.models.Message;
import chat.rocket.core.models.Room; import chat.rocket.core.models.Room;
import chat.rocket.core.models.User;
public interface RoomContract { public interface RoomContract {
...@@ -35,6 +38,12 @@ public interface RoomContract { ...@@ -35,6 +38,12 @@ public interface RoomContract {
void autoloadImages(); void autoloadImages();
void manualLoadImages(); void manualLoadImages();
void onReply(AbsoluteUrl absoluteUrl, String markdown, Message message);
void onCopy(String message);
void showMessageActions(Message message);
} }
interface Presenter extends BaseContract.Presenter<View> { interface Presenter extends BaseContract.Presenter<View> {
...@@ -45,18 +54,22 @@ public interface RoomContract { ...@@ -45,18 +54,22 @@ public interface RoomContract {
void onMessageSelected(@Nullable Message message); void onMessageSelected(@Nullable Message message);
void onMessageTap(@Nullable Message message);
void sendMessage(String messageText); void sendMessage(String messageText);
void resendMessage(Message message); void resendMessage(@NonNull Message message);
void updateMessage(Message message, String content); void updateMessage(@NonNull Message message, String content);
void deleteMessage(Message message); void deleteMessage(@NonNull Message message);
void onUnreadCount(); void onUnreadCount();
void onMarkAsRead(); void onMarkAsRead();
void refreshRoom(); void refreshRoom();
void replyMessage(@NonNull Message message, boolean justQuote);
} }
} }
...@@ -2,6 +2,9 @@ package chat.rocket.android.fragment.chatroom; ...@@ -2,6 +2,9 @@ package chat.rocket.android.fragment.chatroom;
import android.Manifest; import android.Manifest;
import android.app.Activity; import android.app.Activity;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
...@@ -26,10 +29,11 @@ import java.util.List; ...@@ -26,10 +29,11 @@ import java.util.List;
import chat.rocket.android.BackgroundLooper; import chat.rocket.android.BackgroundLooper;
import chat.rocket.android.R; import chat.rocket.android.R;
import chat.rocket.android.RocketChatApplication;
import chat.rocket.android.activity.MainActivity;
import chat.rocket.android.activity.room.RoomActivity; import chat.rocket.android.activity.room.RoomActivity;
import chat.rocket.android.api.MethodCallHelper; import chat.rocket.android.api.MethodCallHelper;
import chat.rocket.android.fragment.chatroom.dialog.FileUploadProgressDialogFragment; import chat.rocket.android.fragment.chatroom.dialog.FileUploadProgressDialogFragment;
import chat.rocket.android.fragment.chatroom.dialog.MessageOptionsDialogFragment;
import chat.rocket.android.fragment.sidebar.SidebarMainFragment; import chat.rocket.android.fragment.sidebar.SidebarMainFragment;
import chat.rocket.android.helper.AbsoluteUrlHelper; import chat.rocket.android.helper.AbsoluteUrlHelper;
import chat.rocket.android.helper.FileUploadHelper; import chat.rocket.android.helper.FileUploadHelper;
...@@ -42,12 +46,14 @@ import chat.rocket.android.helper.TextUtils; ...@@ -42,12 +46,14 @@ import chat.rocket.android.helper.TextUtils;
import chat.rocket.android.layouthelper.chatroom.AbstractNewMessageIndicatorManager; import chat.rocket.android.layouthelper.chatroom.AbstractNewMessageIndicatorManager;
import chat.rocket.android.layouthelper.chatroom.MessageFormManager; import chat.rocket.android.layouthelper.chatroom.MessageFormManager;
import chat.rocket.android.layouthelper.chatroom.MessageListAdapter; import chat.rocket.android.layouthelper.chatroom.MessageListAdapter;
import chat.rocket.android.layouthelper.chatroom.MessagePopup;
import chat.rocket.android.layouthelper.chatroom.ModelListAdapter; import chat.rocket.android.layouthelper.chatroom.ModelListAdapter;
import chat.rocket.android.layouthelper.chatroom.PairedMessage; import chat.rocket.android.layouthelper.chatroom.PairedMessage;
import chat.rocket.android.layouthelper.extra_action.AbstractExtraActionItem; import chat.rocket.android.layouthelper.extra_action.AbstractExtraActionItem;
import chat.rocket.android.layouthelper.extra_action.MessageExtraActionBehavior; import chat.rocket.android.layouthelper.extra_action.MessageExtraActionBehavior;
import chat.rocket.android.layouthelper.extra_action.upload.AbstractUploadActionItem; import chat.rocket.android.layouthelper.extra_action.upload.AbstractUploadActionItem;
import chat.rocket.android.layouthelper.extra_action.upload.AudioUploadActionItem; import chat.rocket.android.layouthelper.extra_action.upload.AudioUploadActionItem;
import chat.rocket.android.layouthelper.extra_action.upload.FileUploadActionItem;
import chat.rocket.android.layouthelper.extra_action.upload.ImageUploadActionItem; import chat.rocket.android.layouthelper.extra_action.upload.ImageUploadActionItem;
import chat.rocket.android.layouthelper.extra_action.upload.VideoUploadActionItem; import chat.rocket.android.layouthelper.extra_action.upload.VideoUploadActionItem;
import chat.rocket.android.log.RCLog; import chat.rocket.android.log.RCLog;
...@@ -55,6 +61,7 @@ import chat.rocket.android.renderer.RocketChatUserStatusProvider; ...@@ -55,6 +61,7 @@ import chat.rocket.android.renderer.RocketChatUserStatusProvider;
import chat.rocket.android.service.ConnectivityManager; import chat.rocket.android.service.ConnectivityManager;
import chat.rocket.android.service.temp.DeafultTempSpotlightRoomCaller; import chat.rocket.android.service.temp.DeafultTempSpotlightRoomCaller;
import chat.rocket.android.service.temp.DefaultTempSpotlightUserCaller; import chat.rocket.android.service.temp.DefaultTempSpotlightUserCaller;
import chat.rocket.android.widget.AbsoluteUrl;
import chat.rocket.android.widget.RoomToolbar; import chat.rocket.android.widget.RoomToolbar;
import chat.rocket.android.widget.internal.ExtraActionPickerDialogFragment; import chat.rocket.android.widget.internal.ExtraActionPickerDialogFragment;
import chat.rocket.android.widget.message.MessageFormLayout; import chat.rocket.android.widget.message.MessageFormLayout;
...@@ -90,8 +97,8 @@ import permissions.dispatcher.RuntimePermissions; ...@@ -90,8 +97,8 @@ import permissions.dispatcher.RuntimePermissions;
public class RoomFragment extends AbstractChatRoomFragment implements public class RoomFragment extends AbstractChatRoomFragment implements
OnBackPressListener, OnBackPressListener,
ExtraActionPickerDialogFragment.Callback, ExtraActionPickerDialogFragment.Callback,
ModelListAdapter.OnItemClickListener<PairedMessage>,
ModelListAdapter.OnItemLongClickListener<PairedMessage>, ModelListAdapter.OnItemLongClickListener<PairedMessage>,
ModelListAdapter.OnItemClickListener<PairedMessage>,
RoomContract.View { RoomContract.View {
private static final int DIALOG_ID = 1; private static final int DIALOG_ID = 1;
...@@ -128,14 +135,14 @@ public class RoomFragment extends AbstractChatRoomFragment implements ...@@ -128,14 +135,14 @@ public class RoomFragment extends AbstractChatRoomFragment implements
private RoomToolbar toolbar; private RoomToolbar toolbar;
private SlidingPaneLayout pane; private Optional<SlidingPaneLayout> optionalPane;
private SidebarMainFragment sidebarFragment; private SidebarMainFragment sidebarFragment;
public RoomFragment() { public RoomFragment() {
} }
/** /**
* create fragment with roomId. * build fragment with roomId.
*/ */
public static RoomFragment create(String hostname, String roomId) { public static RoomFragment create(String hostname, String roomId) {
Bundle args = new Bundle(); Bundle args = new Bundle();
...@@ -197,13 +204,13 @@ public class RoomFragment extends AbstractChatRoomFragment implements ...@@ -197,13 +204,13 @@ public class RoomFragment extends AbstractChatRoomFragment implements
@Override @Override
protected void onSetupView() { protected void onSetupView() {
pane = getActivity().findViewById(R.id.sliding_pane); optionalPane = Optional.ofNullable(getActivity().findViewById(R.id.sliding_pane));
messageRecyclerView = rootView.findViewById(R.id.messageRecyclerView); messageRecyclerView = rootView.findViewById(R.id.messageRecyclerView);
messageListAdapter = new MessageListAdapter(getContext(), hostname); messageListAdapter = new MessageListAdapter(getContext(), hostname);
messageRecyclerView.setAdapter(messageListAdapter); messageRecyclerView.setAdapter(messageListAdapter);
messageListAdapter.setOnItemClickListener(this);
messageListAdapter.setOnItemLongClickListener(this); messageListAdapter.setOnItemLongClickListener(this);
messageListAdapter.setOnItemClickListener(this);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, true); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, true);
messageRecyclerView.setLayoutManager(linearLayoutManager); messageRecyclerView.setLayoutManager(linearLayoutManager);
...@@ -251,10 +258,11 @@ public class RoomFragment extends AbstractChatRoomFragment implements ...@@ -251,10 +258,11 @@ public class RoomFragment extends AbstractChatRoomFragment implements
} }
private void setupMessageActions() { private void setupMessageActions() {
extraActionItems = new ArrayList<>(3); // fixed number as of now extraActionItems = new ArrayList<>(4); // fixed number as of now
extraActionItems.add(new ImageUploadActionItem()); extraActionItems.add(new ImageUploadActionItem());
extraActionItems.add(new AudioUploadActionItem()); extraActionItems.add(new AudioUploadActionItem());
extraActionItems.add(new VideoUploadActionItem()); extraActionItems.add(new VideoUploadActionItem());
extraActionItems.add(new FileUploadActionItem());
} }
private void scrollToLatestMessage() { private void scrollToLatestMessage() {
...@@ -288,22 +296,14 @@ public class RoomFragment extends AbstractChatRoomFragment implements ...@@ -288,22 +296,14 @@ public class RoomFragment extends AbstractChatRoomFragment implements
} }
@Override @Override
public void onItemClick(PairedMessage pairedMessage) { public boolean onItemLongClick(PairedMessage pairedMessage) {
presenter.onMessageSelected(pairedMessage.target); presenter.onMessageSelected(pairedMessage.target);
return true;
} }
@Override @Override
public boolean onItemLongClick(PairedMessage pairedMessage) { public void onItemClick(PairedMessage pairedMessage) {
MessageOptionsDialogFragment messageOptionsDialogFragment = MessageOptionsDialogFragment presenter.onMessageTap(pairedMessage.target);
.create(pairedMessage.target);
messageOptionsDialogFragment.setOnMessageOptionSelectedListener(message -> {
messageOptionsDialogFragment.dismiss();
onEditMessage(message);
});
messageOptionsDialogFragment.show(getChildFragmentManager(), "MessageOptionsDialogFragment");
return true;
} }
private void setupToolbar() { private void setupToolbar() {
...@@ -311,11 +311,11 @@ public class RoomFragment extends AbstractChatRoomFragment implements ...@@ -311,11 +311,11 @@ public class RoomFragment extends AbstractChatRoomFragment implements
toolbar.getMenu().clear(); toolbar.getMenu().clear();
toolbar.inflateMenu(R.menu.menu_room); toolbar.inflateMenu(R.menu.menu_room);
toolbar.setNavigationOnClickListener(view -> { optionalPane.ifPresent(pane -> toolbar.setNavigationOnClickListener(view -> {
if (pane.isSlideable() && !pane.isOpen()) { if (pane.isSlideable() && !pane.isOpen()) {
pane.openPane(); pane.openPane();
} }
}); }));
toolbar.setOnMenuItemClickListener(menuItem -> { toolbar.setOnMenuItemClickListener(menuItem -> {
switch (menuItem.getItemId()) { switch (menuItem.getItemId()) {
...@@ -325,9 +325,9 @@ public class RoomFragment extends AbstractChatRoomFragment implements ...@@ -325,9 +325,9 @@ public class RoomFragment extends AbstractChatRoomFragment implements
case R.id.action_favorite_messages: case R.id.action_favorite_messages:
showRoomListFragment(R.id.action_favorite_messages); showRoomListFragment(R.id.action_favorite_messages);
break; break;
// case R.id.action_file_list: case R.id.action_file_list:
// showRoomListFragment(R.id.action_file_list); showRoomListFragment(R.id.action_file_list);
// break; break;
case R.id.action_member_list: case R.id.action_member_list:
showRoomListFragment(R.id.action_member_list); showRoomListFragment(R.id.action_member_list);
break; break;
...@@ -342,8 +342,7 @@ public class RoomFragment extends AbstractChatRoomFragment implements ...@@ -342,8 +342,7 @@ public class RoomFragment extends AbstractChatRoomFragment implements
SlidingPaneLayout subPane = getActivity().findViewById(R.id.sub_sliding_pane); SlidingPaneLayout subPane = getActivity().findViewById(R.id.sub_sliding_pane);
sidebarFragment = (SidebarMainFragment) getActivity().getSupportFragmentManager().findFragmentById(R.id.sidebar_fragment_container); sidebarFragment = (SidebarMainFragment) getActivity().getSupportFragmentManager().findFragmentById(R.id.sidebar_fragment_container);
if (pane != null) { optionalPane.ifPresent(pane -> pane.setPanelSlideListener(new SlidingPaneLayout.PanelSlideListener() {
pane.setPanelSlideListener(new SlidingPaneLayout.PanelSlideListener() {
@Override @Override
public void onPanelSlide(View view, float v) { public void onPanelSlide(View view, float v) {
messageFormManager.enableComposingText(false); messageFormManager.enableComposingText(false);
...@@ -364,8 +363,7 @@ public class RoomFragment extends AbstractChatRoomFragment implements ...@@ -364,8 +363,7 @@ public class RoomFragment extends AbstractChatRoomFragment implements
subPane.closePane(); subPane.closePane();
closeUserActionContainer(); closeUserActionContainer();
} }
}); }));
}
} }
public void closeUserActionContainer() { public void closeUserActionContainer() {
...@@ -659,6 +657,32 @@ public class RoomFragment extends AbstractChatRoomFragment implements ...@@ -659,6 +657,32 @@ public class RoomFragment extends AbstractChatRoomFragment implements
messageListAdapter.setAutoloadImages(false); messageListAdapter.setAutoloadImages(false);
} }
@Override
public void onReply(AbsoluteUrl absoluteUrl, String markdown, Message message) {
messageFormManager.setReply(absoluteUrl, markdown, message);
}
@Override
public void onCopy(String message) {
RocketChatApplication context = RocketChatApplication.getInstance();
ClipboardManager clipboardManager =
(ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
clipboardManager.setPrimaryClip(ClipData.newPlainText("message", message));
}
@Override
public void showMessageActions(Message message) {
Activity context = getActivity();
if (context != null && context instanceof MainActivity) {
MessagePopup.take(message)
.setReplyAction(msg -> presenter.replyMessage(message, false))
.setEditAction(this::onEditMessage)
.setCopyAction(msg -> onCopy(message.getMessage()))
.setQuoteAction(msg -> presenter.replyMessage(message, true))
.showWith(context);
}
}
private void onEditMessage(Message message) { private void onEditMessage(Message message) {
edittingMessage = message; edittingMessage = message;
messageFormManager.setEditMessage(message.getMessage()); messageFormManager.setEditMessage(message.getMessage());
......
...@@ -6,15 +6,12 @@ import android.support.v4.util.Pair; ...@@ -6,15 +6,12 @@ import android.support.v4.util.Pair;
import com.hadisatrio.optional.Optional; import com.hadisatrio.optional.Optional;
import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import chat.rocket.android.BackgroundLooper; import chat.rocket.android.BackgroundLooper;
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.service.ConnectivityManagerApi;
import chat.rocket.android.shared.BasePresenter; import chat.rocket.android.shared.BasePresenter;
import chat.rocket.core.SyncState; import chat.rocket.core.SyncState;
import chat.rocket.core.interactors.MessageInteractor; import chat.rocket.core.interactors.MessageInteractor;
...@@ -24,7 +21,9 @@ import chat.rocket.core.models.Settings; ...@@ -24,7 +21,9 @@ 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 chat.rocket.android.service.ConnectivityManagerApi; import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
public class RoomPresenter extends BasePresenter<RoomContract.View> public class RoomPresenter extends BasePresenter<RoomContract.View>
implements RoomContract.Presenter { implements RoomContract.Presenter {
...@@ -36,8 +35,9 @@ public class RoomPresenter extends BasePresenter<RoomContract.View> ...@@ -36,8 +35,9 @@ public class RoomPresenter extends BasePresenter<RoomContract.View>
private final AbsoluteUrlHelper absoluteUrlHelper; private final AbsoluteUrlHelper absoluteUrlHelper;
private final MethodCallHelper methodCallHelper; private final MethodCallHelper methodCallHelper;
private final ConnectivityManagerApi connectivityManagerApi; private final ConnectivityManagerApi connectivityManagerApi;
private Room currentRoom;
public RoomPresenter(String roomId, public RoomPresenter(String roomId,
UserRepository userRepository, UserRepository userRepository,
MessageInteractor messageInteractor, MessageInteractor messageInteractor,
RoomRepository roomRepository, RoomRepository roomRepository,
...@@ -112,11 +112,58 @@ public class RoomPresenter extends BasePresenter<RoomContract.View> ...@@ -112,11 +112,58 @@ public class RoomPresenter extends BasePresenter<RoomContract.View>
return; return;
} }
if (message.getType() == null && message.getSyncState() == SyncState.SYNCED) {
// If message is not a system message show applicable actions.
view.showMessageActions(message);
}
}
@Override
public void onMessageTap(@Nullable Message message) {
if (message == null) {
return;
}
if (message.getSyncState() == SyncState.FAILED) { if (message.getSyncState() == SyncState.FAILED) {
view.showMessageSendFailure(message); view.showMessageSendFailure(message);
} }
} }
@Override
public void replyMessage(@NonNull Message message, boolean justQuote) {
this.absoluteUrlHelper.getRocketChatAbsoluteUrl()
.cache()
.subscribeOn(AndroidSchedulers.from(BackgroundLooper.get()))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
serverUrl -> {
if (serverUrl.isPresent()) {
RocketChatAbsoluteUrl absoluteUrl = serverUrl.get();
String baseUrl = absoluteUrl.getBaseUrl();
view.onReply(absoluteUrl, buildReplyOrQuoteMarkdown(baseUrl, message, justQuote), message);
}
},
Logger::report
);
}
private String buildReplyOrQuoteMarkdown(String baseUrl, Message message, boolean justQuote) {
if (currentRoom == null || message.getUser() == null) {
return "";
}
if (currentRoom.isDirectMessage()) {
return String.format("[ ](%s/direct/%s?msg=%s) ", baseUrl,
message.getUser().getUsername(),
message.getId());
} else {
return String.format("[ ](%s/channel/%s?msg=%s) %s", baseUrl,
currentRoom.getName(),
message.getId(),
justQuote ? "" : "@" + message.getUser().getUsername() + " ");
}
}
@Override @Override
public void sendMessage(String messageText) { public void sendMessage(String messageText) {
view.disableMessageInput(); view.disableMessageInput();
...@@ -141,7 +188,7 @@ public class RoomPresenter extends BasePresenter<RoomContract.View> ...@@ -141,7 +188,7 @@ public class RoomPresenter extends BasePresenter<RoomContract.View>
} }
@Override @Override
public void resendMessage(Message message) { public void resendMessage(@NonNull Message message) {
final Disposable subscription = getCurrentUser() final Disposable subscription = getCurrentUser()
.flatMap(user -> messageInteractor.resend(message, user)) .flatMap(user -> messageInteractor.resend(message, user))
.subscribeOn(AndroidSchedulers.from(BackgroundLooper.get())) .subscribeOn(AndroidSchedulers.from(BackgroundLooper.get()))
...@@ -152,7 +199,7 @@ public class RoomPresenter extends BasePresenter<RoomContract.View> ...@@ -152,7 +199,7 @@ public class RoomPresenter extends BasePresenter<RoomContract.View>
} }
@Override @Override
public void updateMessage(Message message, String content) { public void updateMessage(@NonNull Message message, String content) {
view.disableMessageInput(); view.disableMessageInput();
final Disposable subscription = getCurrentUser() final Disposable subscription = getCurrentUser()
.flatMap(user -> messageInteractor.update(message, user, content)) .flatMap(user -> messageInteractor.update(message, user, content))
...@@ -175,7 +222,7 @@ public class RoomPresenter extends BasePresenter<RoomContract.View> ...@@ -175,7 +222,7 @@ public class RoomPresenter extends BasePresenter<RoomContract.View>
} }
@Override @Override
public void deleteMessage(Message message) { public void deleteMessage(@NonNull Message message) {
final Disposable subscription = messageInteractor.delete(message) final Disposable subscription = messageInteractor.delete(message)
.subscribeOn(AndroidSchedulers.from(BackgroundLooper.get())) .subscribeOn(AndroidSchedulers.from(BackgroundLooper.get()))
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
...@@ -233,6 +280,7 @@ public class RoomPresenter extends BasePresenter<RoomContract.View> ...@@ -233,6 +280,7 @@ public class RoomPresenter extends BasePresenter<RoomContract.View>
} }
private void processRoom(Room room) { private void processRoom(Room room) {
this.currentRoom = room;
view.render(room); view.render(room);
if (room.isDirectMessage()) { if (room.isDirectMessage()) {
......
package chat.rocket.android.fragment.chatroom.list package chat.rocket.android.fragment.chatroom.list
import chat.rocket.core.models.Attachment
import chat.rocket.core.models.Message import chat.rocket.core.models.Message
import chat.rocket.core.models.User import chat.rocket.core.models.User
...@@ -32,7 +33,7 @@ interface RoomListContract { ...@@ -32,7 +33,7 @@ interface RoomListContract {
* @param dataSet The file data set to show. * @param dataSet The file data set to show.
* @param total The total number of files. * @param total The total number of files.
*/ */
fun showFileList(dataSet: ArrayList<String>, total: String) fun showFileList(dataSet: ArrayList<Attachment>, total: String)
/** /**
* Shows a list of members of a room. * Shows a list of members of a room.
......
...@@ -9,8 +9,10 @@ import android.view.View ...@@ -9,8 +9,10 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.helper.EndlessRecyclerViewScrollListener import chat.rocket.android.helper.EndlessRecyclerViewScrollListener
import chat.rocket.android.layouthelper.chatroom.list.RoomFileListAdapter
import chat.rocket.android.layouthelper.chatroom.list.RoomMemberListAdapter import chat.rocket.android.layouthelper.chatroom.list.RoomMemberListAdapter
import chat.rocket.android.layouthelper.chatroom.list.RoomMessagesAdapter import chat.rocket.android.layouthelper.chatroom.list.RoomMessagesAdapter
import chat.rocket.core.models.Attachment
import chat.rocket.core.models.Message import chat.rocket.core.models.Message
import chat.rocket.core.models.User import chat.rocket.core.models.User
import kotlinx.android.synthetic.main.fragment_room_list.* import kotlinx.android.synthetic.main.fragment_room_list.*
...@@ -84,6 +86,14 @@ class RoomListFragment : Fragment(), RoomListContract.View { ...@@ -84,6 +86,14 @@ class RoomListFragment : Fragment(), RoomListContract.View {
userId, userId,
offset) offset)
} }
R.id.action_file_list -> {
presenter.requestFileList(roomId,
roomType,
hostname,
token,
userId,
offset)
}
R.id.action_favorite_messages -> { R.id.action_favorite_messages -> {
presenter.requestFavoriteMessages(roomId, presenter.requestFavoriteMessages(roomId,
roomType, roomType,
...@@ -139,8 +149,23 @@ class RoomListFragment : Fragment(), RoomListContract.View { ...@@ -139,8 +149,23 @@ class RoomListFragment : Fragment(), RoomListContract.View {
} }
} }
// TODO (after REST api fixes) override fun showFileList(dataSet: ArrayList<Attachment>, total: String) {
override fun showFileList(dataSet: ArrayList<String>, total: String) {} activity.title = getString(R.string.fragment_room_list_file_list_title, total)
if (recyclerView.adapter == null) {
recyclerView.adapter = RoomFileListAdapter(dataSet)
val linearLayoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
recyclerView.layoutManager = linearLayoutManager
if (dataSet.size >= 50) {
recyclerView.addOnScrollListener(object : EndlessRecyclerViewScrollListener(linearLayoutManager) {
override fun onLoadMore(page: Int, totalItemsCount: Int, recyclerView: RecyclerView?) {
loadNextDataFromApi(page)
}
})
}
} else {
(recyclerView.adapter as RoomFileListAdapter).addDataSet(dataSet)
}
}
override fun showMemberList(dataSet: ArrayList<User>, total: String) { override fun showMemberList(dataSet: ArrayList<User>, total: String) {
activity.title = getString(R.string.fragment_room_list_member_list_title, total) activity.title = getString(R.string.fragment_room_list_member_list_title, total)
......
...@@ -2,11 +2,13 @@ package chat.rocket.android.fragment.chatroom.list ...@@ -2,11 +2,13 @@ package chat.rocket.android.fragment.chatroom.list
import android.content.Context import android.content.Context
import android.os.Handler import android.os.Handler
import android.util.Log
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.api.rest.RestApiHelper import chat.rocket.android.api.rest.RestApiHelper
import chat.rocket.android.helper.OkHttpHelper import chat.rocket.android.helper.OkHttpHelper
import chat.rocket.android.helper.UrlHelper
import chat.rocket.core.SyncState import chat.rocket.core.SyncState
import chat.rocket.core.models.Attachment
import chat.rocket.core.models.AttachmentTitle
import chat.rocket.core.models.Message import chat.rocket.core.models.Message
import chat.rocket.core.models.User import chat.rocket.core.models.User
import okhttp3.Call import okhttp3.Call
...@@ -98,13 +100,43 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) : ...@@ -98,13 +100,43 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) :
}) })
} }
// TODO (after the REST api fixes)
override fun requestFileList(roomId: String, override fun requestFileList(roomId: String,
roomType: String, roomType: String,
hostname: String, hostname: String,
token: String, token: String,
userId: String, userId: String,
offset: Int) {} offset: Int) {
view.showWaitingView(true)
OkHttpHelper.getClient()
.newCall(RestApiHelper.getRequestForFileList(roomId,
roomType,
hostname,
token,
userId,
offset.toString()))
.enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
if (!call.isCanceled) {
val message = e.message
if (message != null) {
showErrorMessage(message)
}
}
}
@Throws(IOException::class)
override fun onResponse(call: Call, response: Response) {
if (response.isSuccessful) {
val result = response.body()?.string()
if (result != null) {
handleFilesJson(result, hostname)
}
} else {
showErrorMessage(response.message())
}
}
})
}
override fun requestMemberList(roomId: String, override fun requestMemberList(roomId: String,
roomType: String, roomType: String,
...@@ -159,27 +191,13 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) : ...@@ -159,27 +191,13 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) :
val messageJsonObject = messagesJSONArray.getJSONObject(it) val messageJsonObject = messagesJSONArray.getJSONObject(it)
val userJsonObject = messageJsonObject.getJSONObject("u") val userJsonObject = messageJsonObject.getJSONObject("u")
val timestampString = messageJsonObject.optString("ts")
val timestamp = if (timestampString.isBlank()) {
0
} else {
Timestamp.valueOf(timestampString.replace("T", " ").replace("Z", "")).time
}
val editedAtString = messageJsonObject.optString("_updatedAt")
val editedAt = if (editedAtString.isBlank()) {
0
} else {
Timestamp.valueOf(editedAtString.replace("T", " ").replace("Z", "")).time
}
Message.builder() Message.builder()
.setId(messageJsonObject.optString("_id")) .setId(messageJsonObject.optString("_id"))
.setRoomId(messageJsonObject.optString("rid")) .setRoomId(messageJsonObject.optString("rid"))
.setMessage(messageJsonObject.optString("msg")) .setMessage(messageJsonObject.optString("msg"))
.setUser(getUserFromJsonObject(userJsonObject)) .setUser(getUserFromJsonObject(userJsonObject))
.setTimestamp(timestamp) .setTimestamp(getLongTimestamp(messageJsonObject.optString("ts")))
.setEditedAt(editedAt) .setEditedAt(getLongTimestamp(messageJsonObject.optString("_updatedAt")))
.setGroupable(messageJsonObject.optBoolean("groupable")) .setGroupable(messageJsonObject.optBoolean("groupable"))
.setSyncState(SyncState.SYNCED) .setSyncState(SyncState.SYNCED)
.build() .build()
...@@ -202,6 +220,52 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) : ...@@ -202,6 +220,52 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) :
} }
} }
private fun handleFilesJson(json: String, hostname: String) {
try {
val jsonObject = JSONObject(json)
val filesJsonArray = jsonObject.getJSONArray("files")
val total = filesJsonArray.length()
val dataSet = ArrayList<Attachment>(total)
(0 until total).mapTo(dataSet) {
val fileJsonObject = filesJsonArray.getJSONObject(it)
val fileLink = UrlHelper.getAttachmentLink(hostname, fileJsonObject.optString("_id"), fileJsonObject.optString("name"))
val attachmentTitle = AttachmentTitle.builder()
.setTitle(fileJsonObject.optString("name"))
.setLink(fileLink)
.setDownloadLink(fileLink)
.build()
val attachment = Attachment.builder()
val type = fileJsonObject.optString("type")
when {
type.startsWith("image") -> attachment.setImageUrl(fileLink)
type.startsWith("audio") -> attachment.setAudioUrl(fileLink)
type.startsWith("video") -> attachment.setVideoUrl(fileLink)
}
attachment.setCollapsed(false)
.setAttachmentTitle(attachmentTitle)
.setTimestamp(getSafeTimestamp(fileJsonObject.optString("uploadedAt")))
.build()
}
if (dataSet.isEmpty() && !hasItem) {
showEmptyViewMessage(context.getString(R.string.fragment_room_list_no_file_list_to_show))
} else {
if (dataSet.isNotEmpty()) {
hasItem = true
showFileList(dataSet, jsonObject.optString("total"))
}
}
} catch (exception: JSONException) {
showInvalidRequest()
}
}
private fun handleMembersJson(json: String) { private fun handleMembersJson(json: String) {
try { try {
val jsonObject = JSONObject(json) val jsonObject = JSONObject(json)
...@@ -221,7 +285,7 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) : ...@@ -221,7 +285,7 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) :
showMemberList(dataSet, jsonObject.optString("total")) showMemberList(dataSet, jsonObject.optString("total"))
} }
} }
}catch (exception: JSONException) { } catch (exception: JSONException) {
showInvalidRequest() showInvalidRequest()
} }
} }
...@@ -236,6 +300,17 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) : ...@@ -236,6 +300,17 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) :
.build() .build()
} }
private fun getLongTimestamp(timestamp: String): Long {
return if (timestamp.isNotBlank()) {
Timestamp.valueOf(getSafeTimestamp(timestamp)).time
} else {
0
}
}
private fun getSafeTimestamp(timestamp: String): String =
timestamp.replace("T", " ").replace("Z", "")
private fun showPinnedMessageList(dataSet: ArrayList<Message>, total: String) { private fun showPinnedMessageList(dataSet: ArrayList<Message>, total: String) {
mainHandler.post { mainHandler.post {
view.showWaitingView(false) view.showWaitingView(false)
...@@ -250,6 +325,13 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) : ...@@ -250,6 +325,13 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) :
} }
} }
private fun showFileList(dataSet: ArrayList<Attachment>, total: String) {
mainHandler.post {
view.showWaitingView(false)
view.showFileList(dataSet, total)
}
}
private fun showMemberList(dataSet: ArrayList<User>, total: String) { private fun showMemberList(dataSet: ArrayList<User>, total: String) {
mainHandler.post { mainHandler.post {
view.showWaitingView(false) view.showWaitingView(false)
......
...@@ -100,7 +100,7 @@ public class LoginFragment extends AbstractServerConfigFragment implements Login ...@@ -100,7 +100,7 @@ public class LoginFragment extends AbstractServerConfigFragment implements Login
try { try {
fragment = info.fragmentClass.newInstance(); fragment = info.fragmentClass.newInstance();
} catch (Exception exception) { } catch (Exception exception) {
RCLog.w(exception, "failed to create new Fragment"); RCLog.w(exception, "failed to build new Fragment");
} }
if (fragment != null) { if (fragment != null) {
Bundle args = new Bundle(); Bundle args = new Bundle();
......
...@@ -30,7 +30,7 @@ public class UserRegistrationDialogFragment extends DialogFragment { ...@@ -30,7 +30,7 @@ public class UserRegistrationDialogFragment extends DialogFragment {
} }
/** /**
* create UserRegistrationDialogFragment with auto-detect email/username. * build UserRegistrationDialogFragment with auto-detect email/username.
*/ */
public static UserRegistrationDialogFragment create(String hostname, public static UserRegistrationDialogFragment create(String hostname,
String usernameOrEmail, String password) { String usernameOrEmail, String password) {
...@@ -42,7 +42,7 @@ public class UserRegistrationDialogFragment extends DialogFragment { ...@@ -42,7 +42,7 @@ public class UserRegistrationDialogFragment extends DialogFragment {
} }
/** /**
* create UserRegistrationDialogFragment. * build UserRegistrationDialogFragment.
*/ */
public static UserRegistrationDialogFragment create(String hostname, public static UserRegistrationDialogFragment create(String hostname,
String username, String email, String username, String email,
......
...@@ -67,7 +67,7 @@ public class SidebarMainFragment extends AbstractFragment implements SidebarMain ...@@ -67,7 +67,7 @@ public class SidebarMainFragment extends AbstractFragment implements SidebarMain
public SidebarMainFragment() {} public SidebarMainFragment() {}
/** /**
* create SidebarMainFragment with hostname. * build SidebarMainFragment with hostname.
*/ */
public static SidebarMainFragment create(String hostname) { public static SidebarMainFragment create(String hostname) {
Bundle args = new Bundle(); Bundle args = new Bundle();
......
...@@ -8,7 +8,8 @@ object UrlHelper { ...@@ -8,7 +8,8 @@ object UrlHelper {
* @param uri The URI. * @param uri The URI.
* @return The URI whit no scheme (HTTP or HTTPS) * @return The URI whit no scheme (HTTP or HTTPS)
*/ */
fun removeUriScheme(uri: String) = uri.replace("http://", "").replace("https://", "") fun removeUriScheme(uri: String) =
uri.replace("http://", "").replace("https://", "")
/** /**
* Returns the hostname with the security protocol (scheme) HTTPS. * Returns the hostname with the security protocol (scheme) HTTPS.
...@@ -17,7 +18,7 @@ object UrlHelper { ...@@ -17,7 +18,7 @@ object UrlHelper {
* @return The hostname with the security protocol (scheme) HTTPS. * @return The hostname with the security protocol (scheme) HTTPS.
*/ */
fun getSafeHostname(hostname: String): String = fun getSafeHostname(hostname: String): String =
"https://" + hostname.replace("http://", "").replace("https://", "") "https://" + removeUriScheme(hostname)
/** /**
* Returns an URL with no spaces and inverted slashes. * Returns an URL with no spaces and inverted slashes.
...@@ -25,17 +26,17 @@ object UrlHelper { ...@@ -25,17 +26,17 @@ object UrlHelper {
* @param url The URL. * @param url The URL.
* @return The URL with no spaces and inverted slashes. * @return The URL with no spaces and inverted slashes.
*/ */
fun getUrl(url: String) = fun getSafeUrl(url: String) =
url.replace(" ", "%20").replace("\\", "") url.replace(" ", "%20").replace("\\", "")
/** /**
* Returns an URL for a file. * Returns an attachment link.
* *
* @param path The path to the file. * @param hostname The hostname.
* @param userId The user ID. * @param fileId The file ID.
* @param token The token. * @param fileName The file name.
* @return The URL for a file * @return The attachment link.
*/ */
fun getUrlForFile(path: String, userId: String, token: String): String = fun getAttachmentLink(hostname: String, fileId: String, fileName: String): String =
"https://" + removeUriScheme(getUrl(path)) + "?rc_uid=$userId" + "&rc_token=$token" getSafeUrl(getSafeHostname(hostname) + "/file-upload/" + fileId + "/" + fileName)
} }
\ No newline at end of file
package chat.rocket.android.layouthelper.chatroom package chat.rocket.android.layouthelper.chatroom
import chat.rocket.android.widget.AbsoluteUrl
import chat.rocket.android.widget.message.MessageFormLayout import chat.rocket.android.widget.message.MessageFormLayout
import chat.rocket.core.models.Message
class MessageFormManager(private val messageFormLayout: MessageFormLayout, val callback: MessageFormLayout.ExtraActionSelectionClickListener) { class MessageFormManager(private val messageFormLayout: MessageFormLayout, val callback: MessageFormLayout.ExtraActionSelectionClickListener) {
private var sendMessageCallback: SendMessageCallback? = null private var sendMessageCallback: SendMessageCallback? = null
private var replyMarkDown: String = ""
init { init {
messageFormLayout.setExtraActionSelectionClickListener(callback) messageFormLayout.setExtraActionSelectionClickListener(callback)
...@@ -31,8 +34,20 @@ class MessageFormManager(private val messageFormLayout: MessageFormLayout, val c ...@@ -31,8 +34,20 @@ class MessageFormManager(private val messageFormLayout: MessageFormLayout, val c
messageFormLayout.isEnabled = enable messageFormLayout.isEnabled = enable
} }
fun setReply(absoluteUrl: AbsoluteUrl, replyMarkDown: String, message: Message) {
this.replyMarkDown = replyMarkDown
messageFormLayout.setReplyContent(absoluteUrl, message)
messageFormLayout.setReplyCancelListener({
this.replyMarkDown = ""
messageFormLayout.clearReplyContent()
messageFormLayout.hideKeyboard()
})
}
private fun sendMessage(message: String) { private fun sendMessage(message: String) {
sendMessageCallback?.onSubmitText(message) val finalMessage = if (replyMarkDown.isNotEmpty()) "$replyMarkDown $message" else message
replyMarkDown = ""
sendMessageCallback?.onSubmitText(finalMessage)
} }
interface SendMessageCallback { interface SendMessageCallback {
......
...@@ -4,14 +4,19 @@ import android.support.v7.widget.RecyclerView ...@@ -4,14 +4,19 @@ import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.TextView
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.widget.message.RocketChatMessageLayout import chat.rocket.android.helper.DateTime
import chat.rocket.android.widget.message.RocketChatMessageAttachmentsLayout
import chat.rocket.core.models.Attachment
import kotlinx.android.synthetic.main.day.view.*
import kotlinx.android.synthetic.main.item_room_file.view.* import kotlinx.android.synthetic.main.item_room_file.view.*
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 RoomFileListAdapter(private var dataSet: List<String>) : RecyclerView.Adapter<RoomFileListAdapter.ViewHolder>() { class RoomFileListAdapter(private var dataSet: List<Attachment>) : RecyclerView.Adapter<RoomFileListAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_room_file, parent, false) val view = LayoutInflater.from(parent.context).inflate(R.layout.item_room_file, parent, false)
...@@ -19,17 +24,22 @@ class RoomFileListAdapter(private var dataSet: List<String>) : RecyclerView.Adap ...@@ -19,17 +24,22 @@ class RoomFileListAdapter(private var dataSet: List<String>) : RecyclerView.Adap
} }
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.fileNameLink.setText(dataSet[position]) val attachment = dataSet[position]
holder.newDay.text = DateTime.fromEpocMs(Timestamp.valueOf(attachment.timestamp).time, DateTime.Format.DATE)
holder.attachment.appendAttachmentView(attachment, true, false)
} }
override fun getItemCount(): Int = dataSet.size override fun getItemCount(): Int = dataSet.size
fun setDataSet(dataSet: List<String>) { fun addDataSet(dataSet: List<Attachment>) {
this.dataSet = dataSet val previousDataSetSize = this.dataSet.size
notifyDataSetChanged() this.dataSet += dataSet
notifyItemRangeInserted(previousDataSetSize, dataSet.size)
} }
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val fileNameLink : RocketChatMessageLayout = itemView.fileLink val newDay: TextView = itemView.day
val attachment: RocketChatMessageAttachmentsLayout = itemView.attachment
} }
} }
\ No newline at end of file
...@@ -23,14 +23,14 @@ public class ChannelRoomListHeader implements RoomListHeader { ...@@ -23,14 +23,14 @@ public class ChannelRoomListHeader implements RoomListHeader {
@Override @Override
public boolean owns(RoomSidebar roomSidebar) { public boolean owns(RoomSidebar roomSidebar) {
return roomSidebar.getType().equals(Room.TYPE_CHANNEL) || roomSidebar.getType().equals(Room.TYPE_PRIVATE); return roomSidebar.getType().equals(Room.TYPE_CHANNEL) || roomSidebar.getType().equals(Room.TYPE_GROUP);
} }
@Override @Override
public boolean shouldShow(@NonNull List<RoomSidebar> roomSidebarList) { public boolean shouldShow(@NonNull List<RoomSidebar> roomSidebarList) {
for (RoomSidebar roomSidebar: roomSidebarList) { for (RoomSidebar roomSidebar: roomSidebarList) {
if ((roomSidebar.getType().equals(Room.TYPE_CHANNEL) if ((roomSidebar.getType().equals(Room.TYPE_CHANNEL)
|| roomSidebar.getType().equals(Room.TYPE_PRIVATE)) || roomSidebar.getType().equals(Room.TYPE_GROUP))
&& !roomSidebar.isAlert() && !roomSidebar.isAlert()
&& !roomSidebar.isFavorite()) { && !roomSidebar.isFavorite()) {
return true; return true;
......
...@@ -2,6 +2,7 @@ package chat.rocket.android.layouthelper.chatroom.roomlist; ...@@ -2,6 +2,7 @@ package chat.rocket.android.layouthelper.chatroom.roomlist;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import chat.rocket.android.helper.Logger;
import chat.rocket.android.widget.internal.RoomListItemView; import chat.rocket.android.widget.internal.RoomListItemView;
import chat.rocket.core.models.Room; import chat.rocket.core.models.Room;
import chat.rocket.core.models.RoomSidebar; import chat.rocket.core.models.RoomSidebar;
...@@ -92,14 +93,16 @@ public class RoomListItemViewHolder extends RecyclerView.ViewHolder { ...@@ -92,14 +93,16 @@ public class RoomListItemViewHolder extends RecyclerView.ViewHolder {
case Room.TYPE_CHANNEL: case Room.TYPE_CHANNEL:
itemView.showPublicChannelIcon(); itemView.showPublicChannelIcon();
break; break;
case Room.TYPE_PRIVATE: case Room.TYPE_GROUP:
itemView.showPrivateChannelIcon(); itemView.showPrivateChannelIcon();
break; break;
case Room.TYPE_LIVECHAT: case Room.TYPE_LIVECHAT:
itemView.showLivechatChannelIcon(); itemView.showLivechatChannelIcon();
break; break;
default: default: {
throw new AssertionError("Room type doesn't satisfies the method documentation. Room type is:" + roomType); itemView.showPrivateChannelIcon();
Logger.report(new AssertionError("Room type doesn't satisfies the method documentation. Room type is:" + roomType));
}
} }
} }
} }
\ No newline at end of file
...@@ -88,7 +88,7 @@ public class PushNotificationHandler implements PushConstants { ...@@ -88,7 +88,7 @@ public class PushNotificationHandler implements PushConstants {
if ((message != null && message.length() != 0) || if ((message != null && message.length() != 0) ||
(title != null && title.length() != 0)) { (title != null && title.length() != 0)) {
Log.d(LOG_TAG, "create notification"); Log.d(LOG_TAG, "build notification");
if (title == null || title.isEmpty()) { if (title == null || title.isEmpty()) {
extras.putString(TITLE, getAppName(context)); extras.putString(TITLE, getAppName(context));
...@@ -191,7 +191,7 @@ public class PushNotificationHandler implements PushConstants { ...@@ -191,7 +191,7 @@ public class PushNotificationHandler implements PushConstants {
private void createActions(Context context, Bundle extras, NotificationCompat.Builder builder, private void createActions(Context context, Bundle extras, NotificationCompat.Builder builder,
Resources resources, String packageName, int notId) { Resources resources, String packageName, int notId) {
Log.d(LOG_TAG, "create actions: with in-line"); Log.d(LOG_TAG, "build actions: with in-line");
String actions = extras.getString(ACTIONS); String actions = extras.getString(ACTIONS);
if (actions == null) { if (actions == null) {
return; return;
...@@ -256,7 +256,7 @@ public class PushNotificationHandler implements PushConstants { ...@@ -256,7 +256,7 @@ public class PushNotificationHandler implements PushConstants {
RemoteInput remoteInput; RemoteInput remoteInput;
if (inline) { if (inline) {
Log.d(LOG_TAG, "create remote input"); Log.d(LOG_TAG, "build remote input");
String replyLabel = "Enter your reply here"; String replyLabel = "Enter your reply here";
remoteInput = new RemoteInput.Builder(INLINE_REPLY) remoteInput = new RemoteInput.Builder(INLINE_REPLY)
.setLabel(replyLabel) .setLabel(replyLabel)
...@@ -287,7 +287,7 @@ public class PushNotificationHandler implements PushConstants { ...@@ -287,7 +287,7 @@ public class PushNotificationHandler implements PushConstants {
@RequiresApi(api = Build.VERSION_CODES.KITKAT_WATCH) @RequiresApi(api = Build.VERSION_CODES.KITKAT_WATCH)
private void createActions(Context context, Bundle extras, Notification.Builder builder, private void createActions(Context context, Bundle extras, Notification.Builder builder,
Resources resources, String packageName, int notId) { Resources resources, String packageName, int notId) {
Log.d(LOG_TAG, "create actions: with in-line"); Log.d(LOG_TAG, "build actions: with in-line");
String actions = extras.getString(ACTIONS); String actions = extras.getString(ACTIONS);
if (actions == null) { if (actions == null) {
return; return;
...@@ -352,7 +352,7 @@ public class PushNotificationHandler implements PushConstants { ...@@ -352,7 +352,7 @@ public class PushNotificationHandler implements PushConstants {
android.app.RemoteInput remoteInput; android.app.RemoteInput remoteInput;
if (inline) { if (inline) {
Log.d(LOG_TAG, "create remote input"); Log.d(LOG_TAG, "build remote input");
String replyLabel = "Enter your reply here"; String replyLabel = "Enter your reply here";
remoteInput = new android.app.RemoteInput.Builder(INLINE_REPLY) remoteInput = new android.app.RemoteInput.Builder(INLINE_REPLY)
.setLabel(replyLabel) .setLabel(replyLabel)
......
...@@ -109,7 +109,7 @@ public class RocketChatWebSocketThread extends HandlerThread { ...@@ -109,7 +109,7 @@ public class RocketChatWebSocketThread extends HandlerThread {
} }
/** /**
* create new Thread. * build new Thread.
*/ */
@DebugLog @DebugLog
public static Single<RocketChatWebSocketThread> getStarted(Context appContext, String hostname) { public static Single<RocketChatWebSocketThread> getStarted(Context appContext, String hostname) {
...@@ -241,11 +241,11 @@ public class RocketChatWebSocketThread extends HandlerThread { ...@@ -241,11 +241,11 @@ public class RocketChatWebSocketThread extends HandlerThread {
private Single<Boolean> prepareDDPClient() { private Single<Boolean> prepareDDPClient() {
// TODO: temporarily replaced checkIfConnectionAlive() call for this single checking if ddpClient is // TODO: temporarily replaced checkIfConnectionAlive() call for this single checking if ddpClient is
// null or not. In case it is, create a new client, otherwise just keep connecting with existing one. // null or not. In case it is, build a new client, otherwise just keep connecting with existing one.
return Single.just(ddpClient != null) return Single.just(ddpClient != null)
.doOnSuccess(alive -> { .doOnSuccess(alive -> {
if (!alive) { if (!alive) {
RCLog.d("DDPClient#create"); RCLog.d("DDPClient#build");
ddpClient = DDPClientWrapper.create(hostname); ddpClient = DDPClientWrapper.create(hostname);
} }
}); });
...@@ -392,7 +392,7 @@ public class RocketChatWebSocketThread extends HandlerThread { ...@@ -392,7 +392,7 @@ public class RocketChatWebSocketThread extends HandlerThread {
) )
); );
} else { } else {
// if we don't have any session then just create the observers and register normally // if we don't have any session then just build the observers and register normally
createObserversAndRegister(); createObserversAndRegister();
} }
} }
......
...@@ -4,14 +4,13 @@ import android.content.Context; ...@@ -4,14 +4,13 @@ import android.content.Context;
import com.hadisatrio.optional.Optional; import com.hadisatrio.optional.Optional;
import chat.rocket.android.log.RCLog;
import io.reactivex.disposables.CompositeDisposable;
import chat.rocket.android.RocketChatCache; import chat.rocket.android.RocketChatCache;
import chat.rocket.android.helper.TextUtils; import chat.rocket.android.helper.TextUtils;
import chat.rocket.persistence.realm.models.ddp.RealmRoom; import chat.rocket.android.log.RCLog;
import chat.rocket.persistence.realm.RealmHelper;
import chat.rocket.android.service.Registrable; import chat.rocket.android.service.Registrable;
import chat.rocket.persistence.realm.RealmHelper;
import chat.rocket.persistence.realm.models.ddp.RealmRoom;
import io.reactivex.disposables.CompositeDisposable;
public abstract class AbstractRocketChatCacheObserver implements Registrable { public abstract class AbstractRocketChatCacheObserver implements Registrable {
private final Context context; private final Context context;
...@@ -50,6 +49,7 @@ public abstract class AbstractRocketChatCacheObserver implements Registrable { ...@@ -50,6 +49,7 @@ public abstract class AbstractRocketChatCacheObserver implements Registrable {
compositeDisposable.add( compositeDisposable.add(
new RocketChatCache(context) new RocketChatCache(context)
.getSelectedRoomIdPublisher() .getSelectedRoomIdPublisher()
.filter(Optional::isPresent)
.map(Optional::get) .map(Optional::get)
.subscribe(this::updateRoomIdWith, RCLog::e) .subscribe(this::updateRoomIdWith, RCLog::e)
); );
......
...@@ -3,20 +3,20 @@ ...@@ -3,20 +3,20 @@
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:padding="@dimen/margin_16"> android:paddingRight="@dimen/margin_16"
android:paddingStart="@dimen/margin_16"
android:paddingLeft="@dimen/margin_16"
android:paddingEnd="@dimen/margin_16"
android:paddingBottom="@dimen/margin_16">
<chat.rocket.android.widget.message.RocketChatMessageLayout <include
android:id="@+id/fileLink" android:id="@+id/dayLayout"
android:layout_width="wrap_content" layout="@layout/day" />
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_16"
android:layout_marginStart="@dimen/margin_16" />
<View <chat.rocket.android.widget.message.RocketChatMessageAttachmentsLayout
android:layout_width="0dp" android:id="@+id/attachment"
android:layout_height="1dp" android:layout_width="match_parent"
android:layout_weight="1" android:layout_height="wrap_content"
android:background="@color/colorDivider" android:layout_marginTop="@dimen/margin_16"
android:layout_marginTop="@dimen/margin_8" app:layout_constraintTop_toBottomOf="@+id/dayLayout" />
app:layout_constraintTop_toBottomOf="@+id/fileLink" />
</android.support.constraint.ConstraintLayout> </android.support.constraint.ConstraintLayout>
\ No newline at end of file
...@@ -10,9 +10,9 @@ ...@@ -10,9 +10,9 @@
android:title="@string/menu_favorite_messages" android:title="@string/menu_favorite_messages"
app:showAsAction="never" /> app:showAsAction="never" />
<!--<item android:id="@+id/action_file_list"--> <item android:id="@+id/action_file_list"
<!--android:title="@string/menu_file_list"--> android:title="@string/menu_file_list"
<!--app:showAsAction="never" />--> app:showAsAction="never" />
<item android:id="@+id/action_member_list" <item android:id="@+id/action_member_list"
android:title="@string/menu_member_list" android:title="@string/menu_member_list"
......
...@@ -21,20 +21,17 @@ class UrlHelperTest { ...@@ -21,20 +21,17 @@ class UrlHelperTest {
@Test @Test
fun getUrlTest() { fun getUrlTest() {
assertEquals("https://demo.rocket.chat/GENERAL/file.txt", UrlHelper.getUrl("https://demo.rocket.chat/GENERAL/file.txt")) assertEquals("https://demo.rocket.chat/GENERAL/file.txt", UrlHelper.getSafeUrl("https://demo.rocket.chat/GENERAL/file.txt"))
assertEquals("http://demo.rocket.chat/GENERAL/file.txt", UrlHelper.getUrl("http://demo.rocket.chat/GENERAL/file.txt")) assertEquals("http://demo.rocket.chat/GENERAL/file.txt", UrlHelper.getSafeUrl("http://demo.rocket.chat/GENERAL/file.txt"))
assertEquals("demo.rocket.chat/GENERAL/file.txt", UrlHelper.getUrl("demo.rocket.chat/GENERAL/file.txt")) assertEquals("demo.rocket.chat/GENERAL/file.txt", UrlHelper.getSafeUrl("demo.rocket.chat/GENERAL/file.txt"))
assertEquals("demo.rocket.chat/GENERAL/a%20sample%20file.txt", UrlHelper.getUrl("demo.rocket.chat/GENERAL/a sample file.txt")) assertEquals("demo.rocket.chat/GENERAL/a%20sample%20file.txt", UrlHelper.getSafeUrl("demo.rocket.chat/GENERAL/a sample file.txt"))
assertEquals("demo.rocket.chat/GENERAL/file.txt", UrlHelper.getUrl("demo.rocket.chat\\/GENERAL\\/file.txt")) assertEquals("demo.rocket.chat/GENERAL/file.txt", UrlHelper.getSafeUrl("demo.rocket.chat\\/GENERAL\\/file.txt"))
} }
@Test @Test
fun getUrlForFileTest() { fun getAttachmentLinkTest() {
assertEquals("https://demo.rocket.chat/GENERAL/file.txt?rc_uid=userId&rc_token=token", UrlHelper.getUrlForFile("https://demo.rocket.chat/GENERAL/file.txt","userId", "token")) assertEquals("https://demo.rocket.chat/file-upload/aFileId/aFileName.txt", UrlHelper.getAttachmentLink("https://demo.rocket.chat", "aFileId", "aFileName.txt"))
assertEquals("https://demo.rocket.chat/GENERAL/file.txt?rc_uid=userId&rc_token=token", UrlHelper.getUrlForFile("http://demo.rocket.chat/GENERAL/file.txt","userId", "token")) assertEquals("https://demo.rocket.chat/file-upload/aFileId/aFileName.txt", UrlHelper.getAttachmentLink("http://demo.rocket.chat", "aFileId", "aFileName.txt"))
assertEquals("https://demo.rocket.chat/GENERAL/file.txt?rc_uid=userId&rc_token=token", UrlHelper.getUrlForFile("demo.rocket.chat/GENERAL/file.txt","userId", "token")) assertEquals("https://demo.rocket.chat/file-upload/aFileId/aFileName.txt", UrlHelper.getAttachmentLink("demo.rocket.chat", "aFileId", "aFileName.txt"))
assertEquals("https://demo.rocket.chat/GENERAL/a%20sample%20file.txt?rc_uid=userId&rc_token=token", UrlHelper.getUrlForFile("demo.rocket.chat/GENERAL/a sample file.txt","userId", "token"))
assertEquals("https://demo.rocket.chat/GENERAL/file.txt?rc_uid=userId&rc_token=token", UrlHelper.getUrlForFile("demo.rocket.chat\\/GENERAL\\/file.txt","userId", "token"))
} }
} }
\ No newline at end of file
...@@ -20,10 +20,7 @@ ext { ...@@ -20,10 +20,7 @@ ext {
compileSdkVersion = 26 compileSdkVersion = 26
targetSdkVersion = 26 targetSdkVersion = 26
buildToolsVersion = "26.0.0" buildToolsVersion = "26.0.0"
supportLibraryVersion = "25.4.0"
constraintLayoutVersion = "1.0.2"
kotlinVersion = "1.1.4-3"
okHttpVersion = "3.9.0"
} }
task clean(type: Delete) { task clean(type: Delete) {
......
ext { ext {
preDexLibs = "true" != System.getenv("CI") preDexLibs = "true" != System.getenv("CI")
supportLibraryVersion = "25.4.0"
constraintLayoutVersion = "1.0.2"
kotlinVersion = "1.1.4-2"
okHttpVersion = "3.9.0"
rxbindingVersion = '2.0.0'
supportDependencies = [
designSupportLibrary: "com.android.support:design:${supportLibraryVersion}",
annotation : "com.android.support:support-annotations:${supportLibraryVersion}",
constrainLayout : "com.android.support.constraint:constraint-layout:${constraintLayoutVersion}",
kotlin : "org.jetbrains.kotlin:kotlin-stdlib-jre7:${kotlinVersion}",
cardView : "com.android.support:cardview-v7:${supportLibraryVersion}",
]
extraDependencies = [
okHTTP : "com.squareup.okhttp3:okhttp:3.8.0",
rxJava : "io.reactivex.rxjava2:rxjava:2.1.0",
boltTask : "com.parse.bolts:bolts-tasks:1.4.0",
textDrawable : "com.amulyakhare:com.amulyakhare.textdrawable:1.0.1",
rxAndroid : "io.reactivex.rxjava2:rxandroid:2.0.1"
]
rxbindingDependencies = [
rxBinding : "com.jakewharton.rxbinding2:rxbinding:${rxbindingVersion}",
rxBindingSupport : "com.jakewharton.rxbinding2:rxbinding-support-v4:${rxbindingVersion}",
rxBindingAppcompact: "com.jakewharton.rxbinding2:rxbinding-appcompat-v7:${rxbindingVersion}",
]
} }
subprojects { subprojects {
project.plugins.whenPluginAdded { plugin -> project.plugins.whenPluginAdded { plugin ->
if ("com.android.build.gradle.AppPlugin" == plugin.class.name) { if ("com.android.build.gradle.AppPlugin" == plugin.class.name) {
...@@ -10,4 +33,5 @@ subprojects { ...@@ -10,4 +33,5 @@ subprojects {
project.android.dexOptions.preDexLibraries = rootProject.ext.preDexLibs project.android.dexOptions.preDexLibraries = rootProject.ext.preDexLibs
} }
} }
} }
\ No newline at end of file
...@@ -8,11 +8,9 @@ buildscript { ...@@ -8,11 +8,9 @@ buildscript {
classpath 'com.android.tools.build:gradle:2.3.3' classpath 'com.android.tools.build:gradle:2.3.3'
} }
} }
android { android {
compileSdkVersion rootProject.ext.compileSdkVersion compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion buildToolsVersion rootProject.ext.buildToolsVersion
defaultConfig { defaultConfig {
minSdkVersion 16 minSdkVersion 16
targetSdkVersion rootProject.ext.targetSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion
......
...@@ -44,30 +44,20 @@ android { ...@@ -44,30 +44,20 @@ android {
androidTest.java.srcDirs += 'src/androidTest/kotlin' androidTest.java.srcDirs += 'src/androidTest/kotlin'
} }
} }
dependencies { dependencies {
compile project(':log-wrapper') compile project(':log-wrapper')
compile project(':rocket-chat-core') compile project(':rocket-chat-core')
compile extraDependencies.rxJava
compile "com.android.support:support-annotations:$rootProject.ext.supportLibraryVersion" compile extraDependencies.boltTask
compile "com.android.support:appcompat-v7:$rootProject.ext.supportLibraryVersion" compile supportDependencies.annotation
compile "com.android.support:design:$rootProject.ext.supportLibraryVersion" compile supportDependencies.designSupportLibrary
compile supportDependencies.kotlin
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$rootProject.ext.kotlinVersion" compile extraDependencies.rxAndroid
testCompile "org.jetbrains.kotlin:kotlin-test:$rootProject.ext.kotlinVersion" testCompile "org.jetbrains.kotlin:kotlin-test:$rootProject.ext.kotlinVersion"
testCompile "org.jetbrains.kotlin:kotlin-test-junit:$rootProject.ext.kotlinVersion" testCompile "org.jetbrains.kotlin:kotlin-test-junit:$rootProject.ext.kotlinVersion"
testCompile 'org.json:json:20170516' testCompile 'org.json:json:20170516'
testCompile 'org.skyscreamer:jsonassert:1.5.0' testCompile 'org.skyscreamer:jsonassert:1.5.0'
compile 'io.reactivex.rxjava2:rxjava:2.1.0'
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
compile 'com.github.akarnokd:rxjava2-interop:0.10.0' compile 'com.github.akarnokd:rxjava2-interop:0.10.0'
compile 'com.parse.bolts:bolts-tasks:1.4.0'
provided 'com.hadisatrio:Optional:v1.0.1' provided 'com.hadisatrio:Optional:v1.0.1'
testCompile 'junit:junit:4.12' testCompile 'junit:junit:4.12'
} }
...@@ -12,7 +12,6 @@ buildscript { ...@@ -12,7 +12,6 @@ buildscript {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$rootProject.ext.kotlinVersion" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$rootProject.ext.kotlinVersion"
} }
} }
android { android {
compileSdkVersion rootProject.ext.compileSdkVersion compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion buildToolsVersion rootProject.ext.buildToolsVersion
...@@ -43,41 +42,25 @@ ext { ...@@ -43,41 +42,25 @@ ext {
frescoVersion = '1.4.0' frescoVersion = '1.4.0'
rxbindingVersion = '2.0.0' rxbindingVersion = '2.0.0'
} }
dependencies { dependencies {
compile project(':rocket-chat-core') compile project(':rocket-chat-core')
compile extraDependencies.okHTTP;
compile "com.android.support:support-annotations:$rootProject.ext.supportLibraryVersion" compile supportDependencies.annotation
compile "com.android.support:appcompat-v7:$rootProject.ext.supportLibraryVersion" compile supportDependencies.cardView
compile "com.android.support:recyclerview-v7:$rootProject.ext.supportLibraryVersion" compile supportDependencies.designSupportLibrary
compile "com.android.support:cardview-v7:$rootProject.ext.supportLibraryVersion" compile supportDependencies.constrainLayout
compile supportDependencies.kotlin
compile extraDependencies.textDrawable
compile rxbindingDependencies.rxBinding
compile rxbindingDependencies.rxBindingSupport
compile "com.android.support:support-v13:$rootProject.ext.supportLibraryVersion" compile "com.android.support:support-v13:$rootProject.ext.supportLibraryVersion"
compile "com.android.support:design:$rootProject.ext.supportLibraryVersion"
compile "com.android.support.constraint:constraint-layout:$rootProject.ext.constraintLayoutVersion"
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$rootProject.ext.kotlinVersion"
testCompile "org.jetbrains.kotlin:kotlin-test:$rootProject.ext.kotlinVersion" testCompile "org.jetbrains.kotlin:kotlin-test:$rootProject.ext.kotlinVersion"
testCompile "org.jetbrains.kotlin:kotlin-test-junit:$rootProject.ext.kotlinVersion" testCompile "org.jetbrains.kotlin:kotlin-test-junit:$rootProject.ext.kotlinVersion"
compile 'org.nibor.autolink:autolink:0.6.0' compile 'org.nibor.autolink:autolink:0.6.0'
compile 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
compile "com.squareup.okhttp3:okhttp:$rootProject.ext.okHttpVersion"
compile 'com.github.yusukeiwaki.android-widget:widget-fontawesome:0.0.1' compile 'com.github.yusukeiwaki.android-widget:widget-fontawesome:0.0.1'
compile "com.facebook.fresco:fresco:$frescoVersion" compile "com.facebook.fresco:fresco:$frescoVersion"
compile "com.facebook.fresco:animated-gif:$frescoVersion"
compile "com.facebook.fresco:animated-webp:$frescoVersion"
compile "com.facebook.fresco:webpsupport:$frescoVersion"
compile "com.facebook.fresco:imagepipeline-okhttp3:$frescoVersion" compile "com.facebook.fresco:imagepipeline-okhttp3:$frescoVersion"
compile 'com.caverock:androidsvg:1.2.1' compile 'com.caverock:androidsvg:1.2.1'
compile "com.jakewharton.rxbinding2:rxbinding:$rxbindingVersion"
compile "com.jakewharton.rxbinding2:rxbinding-support-v4:$rxbindingVersion"
testCompile 'junit:junit:4.12' testCompile 'junit:junit:4.12'
testCompile "org.mockito:mockito-core:2.7.19" testCompile "org.mockito:mockito-core:2.7.19"
} }
...@@ -6,6 +6,7 @@ import android.graphics.Typeface ...@@ -6,6 +6,7 @@ import android.graphics.Typeface
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import chat.rocket.android.widget.AbsoluteUrl import chat.rocket.android.widget.AbsoluteUrl
import com.amulyakhare.textdrawable.TextDrawable import com.amulyakhare.textdrawable.TextDrawable
import java.net.URLEncoder import java.net.URLEncoder
/** /**
......
...@@ -6,7 +6,9 @@ import android.support.graphics.drawable.VectorDrawableCompat ...@@ -6,7 +6,9 @@ import android.support.graphics.drawable.VectorDrawableCompat
import chat.rocket.android.widget.R import chat.rocket.android.widget.R
import com.facebook.drawee.backends.pipeline.Fresco import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.drawee.drawable.ProgressBarDrawable import com.facebook.drawee.drawable.ProgressBarDrawable
import com.facebook.drawee.drawable.ScalingUtils
import com.facebook.drawee.generic.GenericDraweeHierarchy import com.facebook.drawee.generic.GenericDraweeHierarchy
import com.facebook.drawee.generic.RoundingParams
import com.facebook.drawee.view.SimpleDraweeView import com.facebook.drawee.view.SimpleDraweeView
object FrescoHelper { object FrescoHelper {
...@@ -31,6 +33,8 @@ object FrescoHelper { ...@@ -31,6 +33,8 @@ object FrescoHelper {
val hierarchy: GenericDraweeHierarchy = draweeView.hierarchy val hierarchy: GenericDraweeHierarchy = draweeView.hierarchy
hierarchy.setPlaceholderImage(VectorDrawableCompat.create(draweeView.resources, R.drawable.image_dummy, null)) hierarchy.setPlaceholderImage(VectorDrawableCompat.create(draweeView.resources, R.drawable.image_dummy, null))
hierarchy.setFailureImage(VectorDrawableCompat.create(draweeView.resources, R.drawable.image_error, null)) hierarchy.setFailureImage(VectorDrawableCompat.create(draweeView.resources, R.drawable.image_error, null))
hierarchy.roundingParams = RoundingParams().setCornersRadii(5F, 5F, 5F, 5F)
hierarchy.actualImageScaleType = ScalingUtils.ScaleType.FIT_CENTER
hierarchy.setProgressBarImage(ProgressBarDrawable()) hierarchy.setProgressBarImage(ProgressBarDrawable())
val controller = Fresco.newDraweeControllerBuilder() val controller = Fresco.newDraweeControllerBuilder()
......
...@@ -51,7 +51,7 @@ public class MarkDown { ...@@ -51,7 +51,7 @@ public class MarkDown {
private static final Pattern LINK_PATTERN = Pattern.compile( private static final Pattern LINK_PATTERN = Pattern.compile(
"\\[([^\\]]+)\\]\\(((?:http|https):\\/\\/[^\\)]+)\\)", Pattern.MULTILINE); "\\[(.*?)\\]\\(((https?):\\/\\/[-a-zA-Z0-9+&@#\\/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#\\/%=~_|]?)\\)", Pattern.MULTILINE);
private static void highlightLink1(SpannableString inputText) { private static void highlightLink1(SpannableString inputText) {
final Matcher matcher = LINK_PATTERN.matcher(inputText); final Matcher matcher = LINK_PATTERN.matcher(inputText);
while (matcher.find()) { while (matcher.find()) {
......
...@@ -4,6 +4,7 @@ import android.annotation.TargetApi; ...@@ -4,6 +4,7 @@ import android.annotation.TargetApi;
import android.content.Context; import android.content.Context;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v13.view.inputmethod.InputContentInfoCompat; import android.support.v13.view.inputmethod.InputContentInfoCompat;
import android.text.Editable; import android.text.Editable;
import android.text.TextUtils; import android.text.TextUtils;
...@@ -15,10 +16,20 @@ import android.view.ViewGroup; ...@@ -15,10 +16,20 @@ import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import android.widget.EditText; import android.widget.EditText;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.facebook.drawee.view.SimpleDraweeView;
import chat.rocket.android.widget.AbsoluteUrl;
import chat.rocket.android.widget.R; import chat.rocket.android.widget.R;
import chat.rocket.android.widget.helper.DebouncingOnClickListener; import chat.rocket.android.widget.helper.DebouncingOnClickListener;
import chat.rocket.android.widget.helper.FrescoHelper;
import chat.rocket.core.models.Attachment;
import chat.rocket.core.models.AttachmentTitle;
import chat.rocket.core.models.Message;
public class MessageFormLayout extends LinearLayout { public class MessageFormLayout extends LinearLayout {
...@@ -27,6 +38,12 @@ public class MessageFormLayout extends LinearLayout { ...@@ -27,6 +38,12 @@ public class MessageFormLayout extends LinearLayout {
private ImageButton attachButton; private ImageButton attachButton;
private ImageButton sendButton; private ImageButton sendButton;
private RelativeLayout replyBar;
private ImageView replyCancelButton;
private SimpleDraweeView replyThumb;
private TextView replyMessageText;
private TextView replyUsernameText;
private ExtraActionSelectionClickListener extraActionSelectionClickListener; private ExtraActionSelectionClickListener extraActionSelectionClickListener;
private SubmitTextListener submitTextListener; private SubmitTextListener submitTextListener;
private ImageKeyboardEditText.OnCommitContentListener listener; private ImageKeyboardEditText.OnCommitContentListener listener;
...@@ -65,6 +82,12 @@ public class MessageFormLayout extends LinearLayout { ...@@ -65,6 +82,12 @@ public class MessageFormLayout extends LinearLayout {
} }
}); });
replyCancelButton = composer.findViewById(R.id.reply_cancel);
replyMessageText = composer.findViewById(R.id.reply_message);
replyUsernameText = composer.findViewById(R.id.reply_username);
replyThumb = composer.findViewById(R.id.reply_thumb);
replyBar = composer.findViewById(R.id.reply_bar);
sendButton = composer.findViewById(R.id.button_send); sendButton = composer.findViewById(R.id.button_send);
sendButton.setOnClickListener(new DebouncingOnClickListener() { sendButton.setOnClickListener(new DebouncingOnClickListener() {
...@@ -73,6 +96,7 @@ public class MessageFormLayout extends LinearLayout { ...@@ -73,6 +96,7 @@ public class MessageFormLayout extends LinearLayout {
String messageText = getText(); String messageText = getText();
if (messageText.length() > 0 && submitTextListener != null) { if (messageText.length() > 0 && submitTextListener != null) {
submitTextListener.onSubmitText(messageText); submitTextListener.onSubmitText(messageText);
clearReplyContent();
} }
} }
}); });
...@@ -118,6 +142,20 @@ public class MessageFormLayout extends LinearLayout { ...@@ -118,6 +142,20 @@ public class MessageFormLayout extends LinearLayout {
addView(composer); addView(composer);
} }
public void clearReplyContent() {
replyBar.setVisibility(View.GONE);
replyThumb.setVisibility(View.GONE);
replyMessageText.setText("");
replyUsernameText.setText("");
}
public void showReplyThumb() {
replyThumb.setVisibility(View.VISIBLE);
}
public void setReplyCancelListener(OnClickListener onClickListener) {
replyCancelButton.setOnClickListener(onClickListener);
}
public EditText getEditText() { public EditText getEditText() {
return (EditText) composer.findViewById(R.id.editor); return (EditText) composer.findViewById(R.id.editor);
} }
...@@ -154,10 +192,7 @@ public class MessageFormLayout extends LinearLayout { ...@@ -154,10 +192,7 @@ public class MessageFormLayout extends LinearLayout {
if (text.length() > 0) { if (text.length() > 0) {
editor.setSelection(text.length()); editor.setSelection(text.length());
InputMethodManager inputMethodManager = (InputMethodManager) editor.getContext() requestFocusAndShowKeyboard();
.getSystemService(Context.INPUT_METHOD_SERVICE);
editor.requestFocus();
inputMethodManager.showSoftInput(editor, 0);
} }
} }
}); });
...@@ -173,6 +208,61 @@ public class MessageFormLayout extends LinearLayout { ...@@ -173,6 +208,61 @@ public class MessageFormLayout extends LinearLayout {
this.listener = listener; this.listener = listener;
} }
public void setReplyContent(@NonNull AbsoluteUrl absoluteUrl, @NonNull Message message) {
String text = message.getMessage();
replyUsernameText.setText(message.getUser().getUsername());
if (!TextUtils.isEmpty(text)) {
replyMessageText.setText(text);
} else {
if (message.getAttachments() != null && message.getAttachments().size() > 0) {
Attachment attachment = message.getAttachments().get(0);
AttachmentTitle attachmentTitle = attachment.getAttachmentTitle();
String imageUrl = null;
if (attachment.getImageUrl() != null) {
imageUrl = absoluteUrl.from(attachment.getImageUrl());
}
if (attachmentTitle != null) {
text = attachmentTitle.getTitle();
}
if (TextUtils.isEmpty(text)) {
text = "Unknown";
}
if (imageUrl != null) {
FrescoHelper.INSTANCE.loadImageWithCustomization(replyThumb, imageUrl);
showReplyThumb();
}
replyMessageText.setText(text);
}
}
replyBar.setVisibility(View.VISIBLE);
requestFocusAndShowKeyboard();
}
public void hideKeyboard() {
final EditText editor = getEditor();
editor.post(new Runnable() {
@Override
public void run() {
InputMethodManager inputMethodManager = (InputMethodManager) editor.getContext()
.getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(editor.getWindowToken(), 0);
}
});
}
private void requestFocusAndShowKeyboard() {
final EditText editor = getEditor();
editor.post(new Runnable() {
@Override
public void run() {
InputMethodManager inputMethodManager = (InputMethodManager) editor.getContext()
.getSystemService(Context.INPUT_METHOD_SERVICE);
editor.requestFocus();
inputMethodManager.showSoftInput(editor, 0);
}
});
}
private void animateHide(final View view) { private void animateHide(final View view) {
view.animate().scaleX(0).scaleY(0).setDuration(150).withEndAction(new Runnable() { view.animate().scaleX(0).scaleY(0).setDuration(150).withEndAction(new Runnable() {
@Override @Override
......
...@@ -71,21 +71,21 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout { ...@@ -71,21 +71,21 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout {
return; return;
} }
this.attachments = attachments; this.attachments = attachments;
removeAllViews();
for (int i = 0, size = attachments.size(); i < size; i++) { for (int i = 0, size = attachments.size(); i < size; i++) {
appendAttachmentView(attachments.get(i), autoloadImages); appendAttachmentView(attachments.get(i), autoloadImages, true);
} }
} }
private void appendAttachmentView(Attachment attachment, boolean autoloadImages) { public void appendAttachmentView(Attachment attachment, boolean autoloadImages, boolean showAttachmentStrip) {
if (attachment == null) { if (attachment == null) {
return; return;
} }
removeAllViews();
View attachmentView = inflater.inflate(R.layout.message_inline_attachment, this, false); View attachmentView = inflater.inflate(R.layout.message_inline_attachment, this, false);
colorizeAttachmentBar(attachment, attachmentView); colorizeAttachmentBar(attachment, attachmentView, showAttachmentStrip);
showAuthorAttachment(attachment, attachmentView); showAuthorAttachment(attachment, attachmentView);
showTitleAttachment(attachment, attachmentView); showTitleAttachment(attachment, attachmentView);
showReferenceAttachment(attachment, attachmentView); showReferenceAttachment(attachment, attachmentView);
...@@ -97,19 +97,23 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout { ...@@ -97,19 +97,23 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout {
addView(attachmentView); addView(attachmentView);
} }
private void colorizeAttachmentBar(Attachment attachment, View attachmentView) { private void colorizeAttachmentBar(Attachment attachment, View attachmentView, boolean showAttachmentStrip) {
final View attachmentStrip = attachmentView.findViewById(R.id.attachment_strip); final View attachmentStrip = attachmentView.findViewById(R.id.attachment_strip);
final String colorString = attachment.getColor(); if (showAttachmentStrip) {
if (TextUtils.isEmpty(colorString)) { final String colorString = attachment.getColor();
attachmentStrip.setBackgroundResource(R.color.inline_attachment_quote_line); if (TextUtils.isEmpty(colorString)) {
return; attachmentStrip.setBackgroundResource(R.color.inline_attachment_quote_line);
} return;
}
try { try {
attachmentStrip.setBackgroundColor(Color.parseColor(colorString)); attachmentStrip.setBackgroundColor(Color.parseColor(colorString));
} catch (Exception e) { } catch (Exception e) {
attachmentStrip.setBackgroundResource(R.color.inline_attachment_quote_line); attachmentStrip.setBackgroundResource(R.color.inline_attachment_quote_line);
}
} else {
attachmentStrip.setVisibility(GONE);
} }
} }
...@@ -204,8 +208,7 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout { ...@@ -204,8 +208,7 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout {
} }
} }
private void showImageAttachment(Attachment attachment, View attachmentView, private void showImageAttachment(Attachment attachment, View attachmentView, boolean autoloadImages) {
boolean autoloadImages) {
final View imageContainer = attachmentView.findViewById(R.id.image_container); final View imageContainer = attachmentView.findViewById(R.id.image_container);
if (attachment.getImageUrl() == null) { if (attachment.getImageUrl() == null) {
imageContainer.setVisibility(GONE); imageContainer.setVisibility(GONE);
......
<!-- drawable/close.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path android:fillColor="#000" android:pathData="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z" />
</vector>
\ No newline at end of file
<!-- drawable/reply.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path android:fillColor="#000" android:pathData="M10,9V5L3,12L10,19V14.9C15,14.9 18.5,16.5 21,20C20,15 17,10 10,9Z" />
</vector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"> <shape xmlns:android="http://schemas.android.com/apk/res/android">
<stroke <stroke
android:color="@color/inline_attachment_box_outline" android:width="1dp"
android:width="1dp"/> android:color="@color/inline_attachment_box_outline" />
<solid android:color="@color/inline_attachment_box_background"/>
<corners android:radius="2dp"/> <solid
android:color="@color/inline_attachment_box_background" />
<corners
android:radius="2dp" />
</shape> </shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:fresco="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" xmlns:tools="http://schemas.android.com/tools"
android:layout_height="wrap_content" android:layout_width="match_parent"
android:minHeight="48dp" android:layout_height="wrap_content"
android:background="@drawable/top_shadow" android:background="@drawable/top_shadow"
tools:context="chat.rocket.android.widget.message.MessageFormLayout"> android:minHeight="48dp"
tools:context="chat.rocket.android.widget.message.MessageFormLayout">
<chat.rocket.android.widget.message.ImageKeyboardEditText
android:id="@+id/editor" <RelativeLayout
android:layout_width="0dp" android:id="@+id/reply_bar"
android:layout_height="wrap_content" android:layout_width="0dp"
android:layout_marginLeft="16dp" android:layout_height="wrap_content"
android:layout_marginStart="16dp" android:layout_marginBottom="8dp"
android:inputType="textCapSentences|textMultiLine" android:layout_marginEnd="8dp"
android:hint="@string/message_composer_message_hint" android:layout_marginLeft="8dp"
android:textSize="14sp" android:layout_marginRight="8dp"
android:minLines="1" android:layout_marginStart="8dp"
android:maxLines="4" android:layout_marginTop="8dp"
android:background="@null" android:visibility="gone"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toTopOf="@+id/keyboard_container"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/container" app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/> app:layout_constraintTop_toTopOf="parent"
tools:layout_editor_absoluteX="8dp"
<FrameLayout tools:layout_editor_absoluteY="8dp"
android:id="@+id/container" tools:visibility="visible">
android:layout_width="wrap_content"
android:layout_height="wrap_content" <android.support.v7.widget.AppCompatImageView
android:layout_marginLeft="16dp" android:id="@+id/reply_icon"
android:layout_marginStart="16dp" android:layout_width="24dp"
android:layout_marginRight="16dp" android:layout_height="24dp"
android:layout_marginEnd="16dp" android:layout_marginRight="8dp"
app:layout_constraintTop_toTopOf="@+id/editor" android:layout_marginEnd="8dp"
app:layout_constraintRight_toRightOf="parent" android:layout_centerVertical="true"
app:layout_constraintLeft_toRightOf="@+id/editor" android:layout_alignParentStart="true"
app:layout_constraintBottom_toBottomOf="@+id/editor"> android:layout_alignParentLeft="true"
android:adjustViewBounds="true"
<ImageButton app:srcCompat="@drawable/ic_reply"
android:id="@+id/button_attach" app:tint="@color/color_accent" />
android:layout_width="wrap_content"
android:layout_height="wrap_content" <android.support.v7.widget.AppCompatImageView
android:tint="@color/color_icon_composer" android:id="@+id/reply_cancel"
app:srcCompat="@drawable/ic_attach_file_black_24dp" android:layout_width="24dp"
android:background="?attr/selectableItemBackgroundBorderless"/> android:layout_height="24dp"
android:layout_marginLeft="8dp"
<ImageButton android:layout_marginStart="8dp"
android:id="@+id/button_send" android:layout_centerVertical="true"
android:layout_width="wrap_content" android:layout_alignParentEnd="true"
android:layout_height="wrap_content" android:layout_alignParentRight="true"
android:tint="@color/color_accent" android:adjustViewBounds="true"
app:srcCompat="@drawable/ic_send_black_24dp" app:srcCompat="@drawable/ic_close"
android:background="?attr/selectableItemBackgroundBorderless"/> app:tint="@color/color_icon_composer" />
</FrameLayout>
<TextView
android:id="@+id/reply_username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignBaseline="@id/reply_username"
android:layout_toLeftOf="@+id/reply_cancel"
android:layout_toStartOf="@id/reply_cancel"
android:layout_toRightOf="@+id/reply_thumb"
android:layout_toEndOf="@+id/reply_thumb"
android:ellipsize="end"
android:maxLines="1"
android:textColor="@color/color_accent"
android:textStyle="bold"
tools:text="jane.doe" />
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/reply_thumb"
android:layout_width="32dp"
android:layout_height="wrap_content"
android:layout_marginRight="4dp"
android:layout_marginEnd="4dp"
android:layout_toRightOf="@+id/reply_icon"
android:layout_toEndOf="@+id/reply_icon"
android:layout_alignBottom="@+id/reply_message"
android:layout_alignTop="@+id/reply_username"
android:layout_centerVertical="true"
android:visibility="gone"
fresco:actualImageScaleType="fitCenter" />
<TextView
android:id="@+id/reply_message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/reply_username"
android:layout_toLeftOf="@+id/reply_cancel"
android:layout_toStartOf="@id/reply_cancel"
android:layout_toRightOf="@+id/reply_thumb"
android:layout_toEndOf="@+id/reply_thumb"
android:ellipsize="end"
android:maxLines="1"
tools:text="Message" />
</RelativeLayout>
<android.support.constraint.ConstraintLayout
android:id="@+id/keyboard_container"
android:layout_width="0dp"
android:layout_height="48dp"
android:background="@drawable/top_shadow"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/reply_bar">
<chat.rocket.android.widget.message.ImageKeyboardEditText
android:id="@+id/editor"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginStart="16dp"
android:background="@null"
android:hint="@string/message_composer_message_hint"
android:inputType="textCapSentences|textMultiLine"
android:maxLines="4"
android:minLines="1"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/container"
app:layout_constraintTop_toTopOf="parent" />
<FrameLayout
android:id="@+id/container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginStart="16dp"
app:layout_constraintBottom_toBottomOf="@+id/editor"
app:layout_constraintLeft_toRightOf="@+id/editor"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@+id/editor">
<ImageButton
android:id="@+id/button_attach"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackgroundBorderless"
android:tint="@color/color_icon_composer"
app:srcCompat="@drawable/ic_attach_file_black_24dp" />
<ImageButton
android:id="@+id/button_send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackgroundBorderless"
android:tint="@color/color_accent"
app:srcCompat="@drawable/ic_send_black_24dp" />
</FrameLayout>
</android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout> </android.support.constraint.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:fresco="http://schemas.android.com/apk/res-auto"
xmlns:fresco="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" android:orientation="horizontal"
android:paddingTop="4dp" android:paddingBottom="4dp"
android:paddingBottom="4dp"> android:paddingTop="4dp">
<View <View
android:id="@+id/attachment_strip" android:id="@+id/attachment_strip"
android:layout_width="3dp" android:layout_width="3dp"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginRight="5dp" android:layout_marginEnd="5dp"
android:background="@color/inline_attachment_quote_line" /> android:layout_marginRight="5dp"
android:background="@color/inline_attachment_quote_line" />
<LinearLayout <LinearLayout
android:id="@+id/attachment_content" android:id="@+id/attachment_content"
android:layout_width="0px" android:layout_width="0px"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:orientation="vertical"> android:orientation="vertical">
<LinearLayout <LinearLayout
android:id="@+id/author_box" android:id="@+id/author_box"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center_vertical" android:layout_marginBottom="8dp"
android:orientation="horizontal" android:gravity="center_vertical"
android:layout_marginBottom="8dp"> android:orientation="horizontal">
<com.facebook.drawee.view.SimpleDraweeView <com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/author_icon" android:id="@+id/author_icon"
android:layout_width="16dp" android:layout_width="16dp"
android:layout_height="16dp" android:layout_height="16dp"
tools:src="@drawable/circle_black" fresco:actualImageScaleType="fitCenter"
fresco:actualImageScaleType="fitCenter" /> tools:src="@drawable/circle_black" />
<android.support.v4.widget.Space <android.support.v4.widget.Space
android:layout_width="8dp" android:layout_width="8dp"
android:layout_height="8dp" /> android:layout_height="8dp" />
<TextView <TextView
android:id="@+id/author_name" android:id="@+id/author_name"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.RocketChat.MessageAttachment.Title.Link" android:textAppearance="@style/TextAppearance.RocketChat.MessageAttachment.Title.Link"
tools:text="Bradley Hilton" /> tools:text="Bradley Hilton" />
<android.support.v4.widget.Space <android.support.v4.widget.Space
android:layout_width="8dp" android:layout_width="8dp"
android:layout_height="8dp" /> android:layout_height="8dp" />
<TextView <TextView
android:id="@+id/timestamp" android:id="@+id/timestamp"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
tools:text="14:53" /> tools:text="14:53" />
</LinearLayout> </LinearLayout>
<TextView <TextView
android:id="@+id/title" android:id="@+id/title"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="8dp" android:layout_gravity="center"
android:textAppearance="@style/TextAppearance.RocketChat.MessageAttachment.Title" android:background="?attr/selectableItemBackground"
android:background="?attr/selectableItemBackground" android:textAppearance="@style/TextAppearance.RocketChat.MessageAttachment.Title"
tools:text="Attachment Example" /> tools:text="Attachment Example" />
<LinearLayout <LinearLayout
android:id="@+id/ref_box" android:id="@+id/ref_box"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center_vertical" android:layout_marginBottom="8dp"
android:orientation="horizontal" android:gravity="center_vertical"
android:layout_marginBottom="8dp"> android:orientation="horizontal">
<com.facebook.drawee.view.SimpleDraweeView <com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/thumb" android:id="@+id/thumb"
android:layout_width="32dp" android:layout_width="32dp"
android:layout_height="32dp" android:layout_height="32dp"
tools:src="@drawable/circle_black" fresco:actualImageScaleType="fitCenter"
fresco:actualImageScaleType="fitCenter" /> tools:src="@drawable/circle_black" />
<android.support.v4.widget.Space <android.support.v4.widget.Space
android:layout_width="8dp" android:layout_width="8dp"
android:layout_height="8dp" /> android:layout_height="8dp" />
<TextView <TextView
android:id="@+id/text" android:id="@+id/text"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
tools:text="Bradley Hilton" /> tools:text="Bradley Hilton" />
</LinearLayout> </LinearLayout>
<FrameLayout <FrameLayout
android:id="@+id/image_container" android:id="@+id/image_container"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="wrap_content"> android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="8dp"
android:padding="5dp"
android:background="@drawable/inline_attachment_background">
<com.facebook.drawee.view.SimpleDraweeView <com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/image" android:id="@+id/image"
android:layout_width="match_parent" android:layout_width="200dp"
android:layout_height="150dp" android:layout_height="200dp"/>
android:layout_marginBottom="8dp"
fresco:actualImageScaleType="fitStart" />
<TextView <TextView
android:id="@+id/image_load" android:id="@+id/image_load"
android:layout_width="match_parent" android:layout_width="200dp"
android:layout_height="150dp" android:layout_height="200dp"
android:gravity="center_horizontal|bottom" android:gravity="center_horizontal|bottom"
android:paddingBottom="16dp" android:paddingBottom="16dp"
android:text="@string/click_to_load" /> android:text="@string/click_to_load" />
</FrameLayout> </FrameLayout>
<!-- audio --> <!-- audio -->
<!-- video --> <!-- video -->
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
...@@ -4,15 +4,14 @@ plugins { ...@@ -4,15 +4,14 @@ plugins {
apply plugin: 'idea' apply plugin: 'idea'
apply plugin: 'java' apply plugin: 'java'
dependencies { dependencies {
compile fileTree(dir: 'libs', include: ['*.jar']) compile fileTree(dir: 'libs', include: ['*.jar'])
compile extraDependencies.rxJava
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$rootProject.ext.kotlinVersion" compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$rootProject.ext.kotlinVersion"
compile 'com.google.code.findbugs:jsr305:3.0.1' compile 'com.google.code.findbugs:jsr305:3.0.1'
compile 'io.reactivex.rxjava2:rxjava:2.1.0'
compile 'com.hadisatrio:Optional:v1.0.1' compile 'com.hadisatrio:Optional:v1.0.1'
...@@ -23,6 +22,5 @@ dependencies { ...@@ -23,6 +22,5 @@ dependencies {
testCompile 'junit:junit:4.12' testCompile 'junit:junit:4.12'
testCompile "org.mockito:mockito-inline:2.8.9" testCompile "org.mockito:mockito-inline:2.8.9"
} }
sourceCompatibility = "1.7" sourceCompatibility = "1.7"
targetCompatibility = "1.7" targetCompatibility = "1.7"
\ No newline at end of file
...@@ -6,7 +6,7 @@ import com.google.auto.value.AutoValue; ...@@ -6,7 +6,7 @@ import com.google.auto.value.AutoValue;
public abstract class Room { public abstract class Room {
public static final String TYPE_CHANNEL = "c"; public static final String TYPE_CHANNEL = "c";
public static final String TYPE_PRIVATE = "p"; public static final String TYPE_GROUP = "p";
public static final String TYPE_DIRECT_MESSAGE = "d"; public static final String TYPE_DIRECT_MESSAGE = "d";
public static final String TYPE_LIVECHAT = "l"; public static final String TYPE_LIVECHAT = "l";
...@@ -35,7 +35,7 @@ public abstract class Room { ...@@ -35,7 +35,7 @@ public abstract class Room {
} }
public boolean isPrivate() { public boolean isPrivate() {
return TYPE_PRIVATE.equals(getType()); return TYPE_GROUP.equals(getType());
} }
public boolean isDirectMessage() { public boolean isDirectMessage() {
......
...@@ -2,9 +2,10 @@ package chat.rocket.core.models ...@@ -2,9 +2,10 @@ package chat.rocket.core.models
class RoomSidebar { class RoomSidebar {
lateinit var id: String lateinit var id: String
lateinit var roomId: String
lateinit var roomName: String lateinit var roomName: String
lateinit var type: String lateinit var roomId: String
var type: String? = null
get() = RoomType.get(field) ?: Room.TYPE_GROUP
var userStatus: String? = null var userStatus: String? = null
var isAlert: Boolean = false var isAlert: Boolean = false
var isFavorite: Boolean = false var isFavorite: Boolean = false
......
package chat.rocket.core.models;
import org.jetbrains.annotations.Nullable;
public enum RoomType {
CHANNEL("c"),
GROUP("p"),
DIRECT_MESSAGE("d"),
LIVECHAT("l")
;
private final String type;
RoomType(String type) {
this.type = type;
}
@Nullable
public static String get(@Nullable String type) {
for (RoomType roomType : RoomType.values()) {
if (roomType.type.equals(type)) {
return roomType.type;
}
}
return null;
}
}
...@@ -16,7 +16,7 @@ public abstract class SpotlightRoom { ...@@ -16,7 +16,7 @@ public abstract class SpotlightRoom {
} }
public boolean isPrivate() { public boolean isPrivate() {
return Room.TYPE_PRIVATE.equals(getType()); return Room.TYPE_GROUP.equals(getType());
} }
public boolean isDirectMessage() { public boolean isDirectMessage() {
......
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