Commit 5d95c19f authored by Lucio Maciel's avatar Lucio Maciel Committed by GitHub

Merge pull request #408 from filipedelimabrito/userstatus-on-toolbar

[NEW] Show user status on toolbar
parents a906c68f 6f9e4848
# Auth files
*.jks
app/rocket-chat.json
app/src/release/google-services.json
app/src/release/res/values/api_key_strings.xml
################################# Created by https://www.gitignore.io/api/androidstudio (modified) #################################
# Signing files
.signing/
# Android Studio
/*/build/
/*/local.properties
/*/out
/*/*/build
/*/*/production
*.ipr
*~
*.swp
# NDK
obj/
# IntelliJ IDEA
*.iws
/out/
# User-specific configurations
.idea/
# OS-specific files
.DS_Store?
.Trashes
ehthumbs.db
Thumbs.db
# Package Files #
*.war
*.ear
# virtual machine crash logs (Reference: http://www.java.com/en/download/help/error_hotspot.xml)
hs_err_pid*
### AndroidStudio Patch ###
!/gradle/wrapper/gradle-wrapper.jar
# End of https://www.gitignore.io/api/androidstudio
################################# Created by https://www.gitignore.io/api/android (modified) #################################
### Android ###
# Built application files
*.apk
*.ap_
# Files for the Dalvik VM
# Files for the ART/Dalvik VM
*.dex
# Java class files
......@@ -11,15 +63,14 @@
# Generated files
bin/
gen/
out/
# Gradle files
.gradle/
build/
/*/build/
# Local configuration file (sdk path, etc)
local.properties
fabric.properties
# Proguard folder generated by Eclipse
proguard/
......@@ -27,15 +78,66 @@ proguard/
# Log Files
*.log
# Android Studio Files
# Android Studio Navigation editor temp files
.navigation/
# Android Studio captures folder
captures/
# Intellij
*.iml
.idea
# MacOS
.DS_Store
# External native build folder generated in Android Studio 2.2 and later
.externalNativeBuild
# Auth files
*.jks
app/rocket-chat.json
app/src/release/google-services.json
app/src/release/res/values/api_key_strings.xml
# Freeline
freeline.py
freeline/
freeline_project_description.json
### Android Patch ###
gen-external-apklibs
# End of https://www.gitignore.io/api/android
################################# Created by https://www.gitignore.io/api/crashlytics #################################
### Crashlytics ###
#Crashlytics
crashlytics-build.properties
com_crashlytics_export_strings.xml
crashlytics.properties
fabric.properties
# End of https://www.gitignore.io/api/crashlytics
################################# Created by https://www.gitignore.io/api/osx #################################
### OSX ###
*.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
# End of https://www.gitignore.io/api/osx
......@@ -173,6 +173,7 @@ dependencies {
provided 'io.reactivex.rxjava2:rxjava:2.1.0'
provided 'io.reactivex:rxjava:1.3.0'
provided "com.github.akarnokd:rxjava2-interop:0.10.2"
provided 'com.hadisatrio:Optional:v1.0.1'
}
apply plugin: 'com.google.gms.google-services'
package chat.rocket.android;
import android.os.StrictMode;
import com.facebook.stetho.Stetho;
import com.uphyca.stetho_realm.RealmInspectorModulesProvider;
......
......@@ -5,7 +5,6 @@ import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.support.v4.widget.SlidingPaneLayout;
import android.support.v7.graphics.drawable.DrawerArrowDrawable;
import android.support.v7.widget.Toolbar;
import android.view.View;
import chat.rocket.android.LaunchUtil;
......@@ -30,9 +29,8 @@ import hugo.weaving.DebugLog;
* Entry-point for Rocket.Chat.Android application.
*/
public class MainActivity extends AbstractAuthedActivity implements MainContract.View {
private RoomToolbar toolbar;
private StatusTicker statusTicker;
private MainContract.Presenter presenter;
@Override
......@@ -44,7 +42,7 @@ public class MainActivity extends AbstractAuthedActivity implements MainContract
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (RoomToolbar) findViewById(R.id.activity_main_toolbar);
statusTicker = new StatusTicker();
setupSidebar();
}
......@@ -84,7 +82,6 @@ public class MainActivity extends AbstractAuthedActivity implements MainContract
});
final DrawerArrowDrawable drawerArrowDrawable = new DrawerArrowDrawable(this);
Toolbar toolbar = (Toolbar) findViewById(R.id.activity_main_toolbar);
toolbar.setNavigationIcon(drawerArrowDrawable);
toolbar.setNavigationOnClickListener(view -> {
if (pane.isSlideable() && !pane.isOpen()) {
......@@ -195,11 +192,8 @@ public class MainActivity extends AbstractAuthedActivity implements MainContract
@Override
public void showUnreadCount(long roomsCount, int mentionsCount) {
RoomToolbar toolbar = (RoomToolbar) findViewById(R.id.activity_main_toolbar);
if (toolbar != null) {
toolbar.setUnreadBudge((int) roomsCount, mentionsCount);
}
}
@Override
public void showAddServerScreen() {
......
package chat.rocket.android.fragment.chatroom;
import android.os.Bundle;
import android.support.annotation.DrawableRes;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
......@@ -11,40 +9,51 @@ import android.view.ViewGroup;
import chat.rocket.android.R;
import chat.rocket.android.fragment.AbstractFragment;
import chat.rocket.android.widget.RoomToolbar;
import chat.rocket.core.models.User;
abstract class AbstractChatRoomFragment extends AbstractFragment {
private RoomToolbar roomToolbar;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
roomToolbar = (RoomToolbar) getActivity().findViewById(R.id.activity_main_toolbar);
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
roomToolbar = getActivity().findViewById(R.id.activity_main_toolbar);
return super.onCreateView(inflater, container, savedInstanceState);
}
protected void setToolbarTitle(@StringRes int stringResId) {
if (roomToolbar == null) {
return;
protected void setToolbarTitle(CharSequence title) {
roomToolbar.setTitle(title);
}
roomToolbar.setTitle(stringResId);
protected void showToolbarPrivateChannelIcon() {
roomToolbar.showPrivateChannelIcon();
}
protected void setToolbarTitle(CharSequence title) {
if (roomToolbar == null) {
return;
protected void showToolbarPublicChannelIcon() {
roomToolbar.showPublicChannelIcon();
}
roomToolbar.setTitle(title);
protected void showToolbarUserStatuslIcon(@Nullable String status) {
if (status == null) {
roomToolbar.showUserStatusIcon(RoomToolbar.STATUS_OFFLINE);
} else {
switch (status) {
case User.STATUS_ONLINE:
roomToolbar.showUserStatusIcon(RoomToolbar.STATUS_ONLINE);
break;
case User.STATUS_BUSY:
roomToolbar.showUserStatusIcon(RoomToolbar.STATUS_BUSY);
break;
case User.STATUS_AWAY:
roomToolbar.showUserStatusIcon(RoomToolbar.STATUS_AWAY);
break;
case User.STATUS_OFFLINE:
roomToolbar.showUserStatusIcon(RoomToolbar.STATUS_OFFLINE);
break;
default:
roomToolbar.showUserStatusIcon(RoomToolbar.STATUS_OFFLINE);
break;
}
protected void setToolbarRoomIcon(@DrawableRes int drawableResId) {
if (roomToolbar == null) {
return;
}
roomToolbar.setRoomIcon(drawableResId);
}
}
\ No newline at end of file
......@@ -3,8 +3,8 @@ package chat.rocket.android.fragment.chatroom;
import chat.rocket.android.R;
public class HomeFragment extends AbstractChatRoomFragment {
public HomeFragment() {
}
public HomeFragment() {}
@Override
protected int getLayout() {
......@@ -13,13 +13,6 @@ public class HomeFragment extends AbstractChatRoomFragment {
@Override
protected void onSetupView() {
setToolbarTitle(R.string.home_fragment_title);
}
@Override
public void onResume() {
super.onResume();
setToolbarRoomIcon(0);
setToolbarTitle(R.string.home_fragment_title);
setToolbarTitle(getText(R.string.home_fragment_title));
}
}
\ No newline at end of file
......@@ -2,6 +2,7 @@ package chat.rocket.android.fragment.chatroom;
import android.support.annotation.Nullable;
import chat.rocket.core.models.User;
import java.util.List;
import chat.rocket.android.shared.BaseContract;
import chat.rocket.core.models.Message;
......@@ -15,6 +16,8 @@ public interface RoomContract {
void render(Room room);
void showUserStatus(User user);
void updateHistoryState(boolean hasNext, boolean isLoaded);
void onMessageSendSuccessfully();
......
......@@ -22,6 +22,7 @@ import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import chat.rocket.core.models.User;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
......@@ -525,16 +526,6 @@ public class RoomFragment extends AbstractChatRoomFragment implements
@Override
public void render(Room room) {
String type = room.getType();
if (Room.TYPE_CHANNEL.equals(type)) {
setToolbarRoomIcon(R.drawable.ic_hashtag_gray_24dp);
} else if (Room.TYPE_PRIVATE.equals(type)) {
setToolbarRoomIcon(R.drawable.ic_lock_gray_24dp);
} else if (Room.TYPE_DIRECT_MESSAGE.equals(type)) {
setToolbarRoomIcon(R.drawable.ic_at_gray_24dp);
} else {
setToolbarRoomIcon(0);
}
setToolbarTitle(room.getName());
boolean unreadMessageExists = room.isAlert();
......@@ -542,6 +533,20 @@ public class RoomFragment extends AbstractChatRoomFragment implements
newMessageIndicatorManager.reset();
}
previousUnreadMessageExists = unreadMessageExists;
if (room.isChannel()) {
showToolbarPublicChannelIcon();
return;
}
if (room.isPrivate()) {
showToolbarPrivateChannelIcon();
}
}
@Override
public void showUserStatus(User user) {
showToolbarUserStatuslIcon(user.getStatus());
}
@Override
......
......@@ -5,6 +5,7 @@ import android.support.annotation.Nullable;
import android.support.v4.util.Pair;
import com.hadisatrio.optional.Optional;
import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
......@@ -217,14 +218,29 @@ public class RoomPresenter extends BasePresenter<RoomContract.View>
.map(Optional::get)
.subscribeOn(AndroidSchedulers.from(BackgroundLooper.get()))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
room -> view.render(room),
Logger::report
);
.subscribe(this::processRoom, Logger::report);
addSubscription(subscription);
}
private void processRoom(Room room) {
view.render(room);
if (room.isDirectMessage()) {
getUserByUsername(room.getName());
}
}
private void getUserByUsername(String username) {
final Disposable disposable = userRepository.getByUsername(username)
.distinctUntilChanged()
.filter(Optional::isPresent)
.map(Optional::get)
.subscribeOn(AndroidSchedulers.from(BackgroundLooper.get()))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(view::showUserStatus, Logger::report);
addSubscription(disposable);
}
private void getRoomHistoryStateInfo() {
final Disposable subscription = roomRepository.getHistoryStateByRoomId(roomId)
.distinctUntilChanged()
......
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:viewportHeight="1792.0"
android:viewportWidth="1792.0"
android:width="24dp">
<path
android:fillColor="#30000000"
android:pathData="M991,1024l64,-256h-254l-64,256h254zM1759,520l-56,224q-7,24 -31,24h-327l-64,256h311q15,0 25,12 10,14 6,28l-56,224q-5,24 -31,24h-327l-81,328q-7,24 -31,24h-224q-16,0 -26,-12 -9,-12 -6,-28l78,-312h-254l-81,328q-7,24 -31,24h-225q-15,0 -25,-12 -9,-12 -6,-28l78,-312h-311q-15,0 -25,-12 -9,-12 -6,-28l56,-224q7,-24 31,-24h327l64,-256h-311q-15,0 -25,-12 -10,-14 -6,-28l56,-224q5,-24 31,-24h327l81,-328q7,-24 32,-24h224q15,0 25,12 9,12 6,28l-78,312h254l81,-328q7,-24 32,-24h224q15,0 25,12 9,12 6,28l-78,312h311q15,0 25,12 9,12 6,28z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:viewportHeight="1792.0"
android:viewportWidth="1792.0"
android:width="24dp">
<path
android:fillColor="#30000000"
android:pathData="M640,768h512v-192q0,-106 -75,-181t-181,-75 -181,75 -75,181v192zM1472,864v576q0,40 -28,68t-68,28h-960q-40,0 -68,-28t-28,-68v-576q0,-40 28,-68t68,-28h32v-192q0,-184 132,-316t316,-132 316,132 132,316v192h32q40,0 68,28t28,68z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:viewportHeight="1792.0"
android:viewportWidth="1792.0"
android:width="24dp">
<path
android:fillColor="#30000000"
android:pathData="M1100,775q0,-108 -53.5,-169t-147.5,-61q-63,0 -124,30.5t-110,84.5 -79.5,137 -30.5,180q0,112 53.5,173t150.5,61q96,0 176,-66.5t122.5,-166 42.5,-203.5zM1664,896q0,111 -37,197t-98.5,135 -131.5,74.5 -145,27.5q-6,0 -15.5,0.5t-16.5,0.5q-95,0 -142,-53 -28,-33 -33,-83 -52,66 -131.5,110t-173.5,44q-161,0 -249.5,-95.5t-88.5,-269.5q0,-157 66,-290t179,-210.5 246,-77.5q87,0 155,35.5t106,99.5l2,-19 11,-56q1,-6 5.5,-12t9.5,-6h118q5,0 13,11 5,5 3,16l-120,614q-5,24 -5,48 0,39 12.5,52t44.5,13q28,-1 57,-5.5t73,-24 77,-50 57,-89.5 24,-137q0,-292 -174,-466t-466,-174q-130,0 -248.5,51t-204,136.5 -136.5,204 -51,248.5 51,248.5 136.5,204 204,136.5 248.5,51q228,0 405,-144 11,-9 24,-8t21,12l41,49q8,12 7,24 -2,13 -12,22 -102,83 -227.5,128t-258.5,45q-156,0 -298,-61t-245,-164 -164,-245 -61,-298 61,-298 164,-245 245,-164 298,-61q344,0 556,212t212,556z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:viewportHeight="1792.0"
android:viewportWidth="1792.0"
android:width="24dp">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M1100,775q0,-108 -53.5,-169t-147.5,-61q-63,0 -124,30.5t-110,84.5 -79.5,137 -30.5,180q0,112 53.5,173t150.5,61q96,0 176,-66.5t122.5,-166 42.5,-203.5zM1664,896q0,111 -37,197t-98.5,135 -131.5,74.5 -145,27.5q-6,0 -15.5,0.5t-16.5,0.5q-95,0 -142,-53 -28,-33 -33,-83 -52,66 -131.5,110t-173.5,44q-161,0 -249.5,-95.5t-88.5,-269.5q0,-157 66,-290t179,-210.5 246,-77.5q87,0 155,35.5t106,99.5l2,-19 11,-56q1,-6 5.5,-12t9.5,-6h118q5,0 13,11 5,5 3,16l-120,614q-5,24 -5,48 0,39 12.5,52t44.5,13q28,-1 57,-5.5t73,-24 77,-50 57,-89.5 24,-137q0,-292 -174,-466t-466,-174q-130,0 -248.5,51t-204,136.5 -136.5,204 -51,248.5 51,248.5 136.5,204 204,136.5 248.5,51q228,0 405,-144 11,-9 24,-8t21,12l41,49q8,12 7,24 -2,13 -12,22 -102,83 -227.5,128t-258.5,45q-156,0 -298,-61t-245,-164 -164,-245 -61,-298 61,-298 164,-245 245,-164 298,-61q344,0 556,212t212,556z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:viewportHeight="1792.0"
android:viewportWidth="1792.0"
android:width="24dp">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M991,1024l64,-256h-254l-64,256h254zM1759,520l-56,224q-7,24 -31,24h-327l-64,256h311q15,0 25,12 10,14 6,28l-56,224q-5,24 -31,24h-327l-81,328q-7,24 -31,24h-224q-16,0 -26,-12 -9,-12 -6,-28l78,-312h-254l-81,328q-7,24 -31,24h-225q-15,0 -25,-12 -9,-12 -6,-28l78,-312h-311q-15,0 -25,-12 -9,-12 -6,-28l56,-224q7,-24 31,-24h327l64,-256h-311q-15,0 -25,-12 -10,-14 -6,-28l56,-224q5,-24 31,-24h327l81,-328q7,-24 32,-24h224q15,0 25,12 9,12 6,28l-78,312h254l81,-328q7,-24 32,-24h224q15,0 25,12 9,12 6,28l-78,312h311q15,0 25,12 9,12 6,28z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:viewportHeight="1792.0"
android:viewportWidth="1792.0"
android:width="24dp">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M640,768h512v-192q0,-106 -75,-181t-181,-75 -181,75 -75,181v192zM1472,864v576q0,40 -28,68t-68,28h-960q-40,0 -68,-28t-28,-68v-576q0,-40 28,-68t68,-28h32v-192q0,-184 132,-316t316,-132 316,132 132,316v192h32q40,0 68,28t28,68z"/>
</vector>
......@@ -17,11 +17,7 @@
<chat.rocket.android.widget.RoomToolbar
android:id="@+id/activity_main_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:theme="@style/Widget.RocketChat.RoomToolbar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:titleText="@string/app_name"
app:titleDrawablePadding="@dimen/margin_8" />
android:layout_height="wrap_content" />
</android.support.design.widget.AppBarLayout>
<FrameLayout
......@@ -30,6 +26,5 @@
android:layout_height="match_parent"
android:background="@android:color/white"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>
</LinearLayout>
\ No newline at end of file
......@@ -18,11 +18,7 @@
<chat.rocket.android.widget.RoomToolbar
android:id="@+id/activity_main_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:titleText="@string/app_name"
app:titleDrawablePadding="@dimen/margin_8"
app:theme="@style/Widget.RocketChat.RoomToolbar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
android:layout_height="wrap_content" />
</android.support.design.widget.AppBarLayout>
<FrameLayout
......@@ -31,6 +27,5 @@
android:layout_height="match_parent"
android:clickable="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>
</android.support.v4.widget.SlidingPaneLayout>
......@@ -4,7 +4,6 @@
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:padding="@dimen/margin_16"
android:theme="@style/Theme.AppCompat.Light">
<TextView
......
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Widget.RocketChat.RoomToolbar" parent="Widget.AppCompat.Toolbar">
<item name="titleTextAppearance">@style/TextAppearance.Widget.RocketChat.RoomToolbar.Title</item>
<item name="android:background">@android:color/white</item>
</style>
<style name="TextAppearance.Widget.RocketChat.RoomToolbar.Title"
parent="TextAppearance.Widget.AppCompat.Toolbar.Title">
<item name="android:textColor">#444444</item>
</style>
</resources>
\ No newline at end of file
......@@ -22,7 +22,7 @@ ext {
buildToolsVersion = "26.0.0"
supportLibraryVersion = "25.4.0"
constraintLayoutVersion = "1.0.2"
kotlinVersion = "1.1.3-2"
kotlinVersion = "1.1.4-2"
}
task clean(type: Delete) {
......
......@@ -67,5 +67,7 @@ dependencies {
compile 'com.parse.bolts:bolts-tasks:1.4.0'
provided 'com.hadisatrio:Optional:v1.0.1'
testCompile 'junit:junit:4.12'
}
......@@ -10,7 +10,6 @@ import chat.rocket.persistence.realm.models.ddp.RealmSpotlight.Columns
import hu.akarnokd.rxjava.interop.RxJavaInterop
import io.reactivex.Flowable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.realm.Case
import io.realm.Realm
import io.realm.RealmResults
import io.realm.Sort
......@@ -20,7 +19,7 @@ class RealmSpotlightRepository(private val hostname: String) : RealmRepository()
override fun getSuggestionsFor(term: String, limit: Int): Flowable<List<Spotlight>> {
return Flowable.defer { Flowable.using<RealmResults<RealmSpotlight>, Pair<Realm, Looper>>({
Pair<Realm, Looper>(RealmStore.getRealm(hostname), Looper.myLooper())
Pair(RealmStore.getRealm(hostname), Looper.myLooper())
}, { pair -> RxJavaInterop.toV2Flowable<RealmResults<RealmSpotlight>>(pair.first.where(RealmSpotlight::class.java)
.findAllSorted(Columns.TYPE, Sort.DESCENDING)
.asObservable())
......@@ -35,7 +34,7 @@ class RealmSpotlightRepository(private val hostname: String) : RealmRepository()
val total = realmSpotlightList.size
val spotlightList = ArrayList<Spotlight>(total)
(0..total - 1).mapTo(spotlightList) {
(0 until total).mapTo(spotlightList) {
realmSpotlightList[it].asSpotlight()
}
......
......@@ -2,24 +2,25 @@ package chat.rocket.persistence.realm.repositories;
import android.os.Looper;
import android.support.v4.util.Pair;
import com.hadisatrio.optional.Optional;
import io.reactivex.Flowable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.realm.Case;
import io.realm.RealmResults;
import io.realm.Sort;
import java.util.ArrayList;
import java.util.List;
import chat.rocket.core.SortDirection;
import chat.rocket.core.models.User;
import chat.rocket.core.repositories.UserRepository;
import chat.rocket.persistence.realm.RealmStore;
import chat.rocket.persistence.realm.models.ddp.RealmUser;
import hu.akarnokd.rxjava.interop.RxJavaInterop;
import io.reactivex.Flowable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.realm.Case;
import io.realm.Realm;
import io.realm.RealmResults;
import io.realm.Sort;
public class RealmUserRepository extends RealmRepository implements UserRepository {
private final String hostname;
public RealmUserRepository(String hostname) {
......@@ -28,18 +29,10 @@ public class RealmUserRepository extends RealmRepository implements UserReposito
@Override
public Flowable<Optional<User>> getCurrent() {
return Flowable.defer(() -> Flowable.using(
() -> new Pair<>(RealmStore.getRealm(hostname), Looper.myLooper()),
pair -> RxJavaInterop.toV2Flowable(
pair.first.where(RealmUser.class)
.isNotEmpty(RealmUser.EMAILS)
.findAll()
.<RealmResults<RealmUser>>asObservable()),
pair -> close(pair.first, pair.second)
)
return Flowable.defer(() ->
realmGetCurrent()
.unsubscribeOn(AndroidSchedulers.from(Looper.myLooper()))
.filter(it -> it != null && it.isLoaded()
&& it.isValid())
.filter(it -> it != null && it.isLoaded() && it.isValid())
.map(realmUsers -> {
if (realmUsers.size() > 0) {
return Optional.of(realmUsers.get(0).asUser());
......@@ -49,34 +42,73 @@ public class RealmUserRepository extends RealmRepository implements UserReposito
}));
}
@Override
public Flowable<List<User>> getSortedLikeName(String name, SortDirection direction, int limit) {
return Flowable.defer(() -> Flowable.using(
private Flowable<RealmResults<RealmUser>> realmGetCurrent() {
return Flowable.using(
() -> new Pair<>(RealmStore.getRealm(hostname), Looper.myLooper()),
pair -> RxJavaInterop.toV2Flowable(
pair.first.where(RealmUser.class)
.like(RealmUser.USERNAME, "*" + name + "*", Case.INSENSITIVE)
.findAllSorted(RealmUser.USERNAME,
direction.equals(SortDirection.ASC) ? Sort.ASCENDING : Sort.DESCENDING)
.asObservable()),
pair -> close(pair.first, pair.second)
)
.isNotEmpty(RealmUser.EMAILS)
.findAll()
.<RealmResults<RealmUser>>asObservable()),
pair -> close(pair.first, pair.second));
}
@Override
public Flowable<Optional<User>> getByUsername(String username) {
return Flowable.defer(() ->
realmGetByUsername(username)
.unsubscribeOn(AndroidSchedulers.from(Looper.myLooper()))
.filter(realmUsers -> realmUsers != null && realmUsers.isLoaded()
&& realmUsers.isValid())
.map(realmUsers -> toList(safeSubList(realmUsers, 0, limit))));
.map(optional -> {
if (optional.isPresent()) {
return Optional.of(optional.get().asUser());
}
private List<User> toList(RealmResults<RealmUser> realmUsers) {
int total = realmUsers.size();
return Optional.absent();
}));
}
final List<User> userList = new ArrayList<>(total);
private Flowable<Optional<RealmUser>> realmGetByUsername(String username) {
return Flowable.using(
() -> new Pair<>(RealmStore.getRealm(hostname), Looper.myLooper()),
pair -> realmQueryUsername(pair.first, username),
pair -> close(pair.first, pair.second));
}
for (int i = 0; i < total; i++) {
userList.add(realmUsers.get(i).asUser());
private Flowable<Optional<RealmUser>> realmQueryUsername(Realm realm, String username) {
RealmUser realmUser = realm.where(RealmUser.class)
.equalTo(RealmUser.USERNAME, username)
.findFirst();
if (realmUser == null) {
return Flowable.just(Optional.absent());
}
return userList;
return RxJavaInterop.toV2Flowable(
realmUser
.<RealmUser>asObservable()
.filter(user -> user.isLoaded() && user.isValid())
.map(Optional::of));
}
@Override
public Flowable<List<User>> getSortedLikeName(String name, int limit) {
return Flowable.defer(() ->
realmGetSortedLikeName(name)
.unsubscribeOn(AndroidSchedulers.from(Looper.myLooper()))
.filter(realmUsers -> realmUsers != null && realmUsers.isLoaded()
&& realmUsers.isValid())
.map(realmUsers -> toList(safeSubList(realmUsers, 0, limit))));
}
private Flowable<RealmResults<RealmUser>> realmGetSortedLikeName(String name) {
return Flowable.using(
() -> new Pair<>(RealmStore.getRealm(hostname), Looper.myLooper()),
pair -> RxJavaInterop.toV2Flowable(
pair.first.where(RealmUser.class)
.like(RealmUser.USERNAME, "*" + name + "*", Case.INSENSITIVE)
.findAllSorted(RealmUser.USERNAME, Sort.DESCENDING)
.asObservable()),
pair -> close(pair.first, pair.second));
}
private List<User> toList(List<RealmUser> realmUsers) {
......
package chat.rocket.android.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.support.annotation.DrawableRes;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.graphics.drawable.VectorDrawableCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.widget.TextViewCompat;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v7.widget.AppCompatImageView;
import android.support.v7.widget.Toolbar;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
......@@ -22,87 +21,118 @@ import com.amulyakhare.textdrawable.TextDrawable;
import java.lang.reflect.Field;
public class RoomToolbar extends Toolbar {
private TextView titleTextView;
private TextView toolbarText;
private ImageView roomTypeImage;
private ImageView userStatusImage;
private ImageView badgeImageView;
private Drawable privateChannelDrawable;
private Drawable publicChannelDrawable;
private Drawable userStatusDrawable;
public static final int STATUS_ONLINE = 1;
public static final int STATUS_BUSY = 2;
public static final int STATUS_AWAY = 3;
public static final int STATUS_OFFLINE = 4;
public RoomToolbar(Context context) {
super(context);
initialize(context, null);
initialize(context);
}
public RoomToolbar(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initialize(context, attrs);
initialize(context);
}
public RoomToolbar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initialize(context, attrs);
initialize(context);
}
private void initialize(Context context, @Nullable AttributeSet attrs) {
View.inflate(context, R.layout.room_toolbar, this);
private void initialize(Context context) {
View.inflate(context, R.layout.toolbar, this);
setNavigationIcon();
titleTextView = (TextView) findViewById(R.id.toolbar_title);
toolbarText = findViewById(R.id.text_toolbar);
roomTypeImage = findViewById(R.id.image_room_type);
userStatusImage = findViewById(R.id.image_user_status);
if (titleTextView == null) {
return;
privateChannelDrawable = VectorDrawableCompat.create(getResources(), R.drawable.ic_lock_white_24dp, null);
publicChannelDrawable = VectorDrawableCompat.create(getResources(), R.drawable.ic_hashtag_white_24dp, null);
userStatusDrawable = VectorDrawableCompat.create(getResources(), R.drawable.ic_user_status_black_24dp, null);
}
TypedArray typedArrayBase = context.getTheme().obtainStyledAttributes(new int[]{
R.attr.titleTextAppearance
});
try {
TextViewCompat.setTextAppearance(titleTextView,
typedArrayBase.getResourceId(0,
android.support.v7.appcompat.R.style.TextAppearance_Widget_AppCompat_Toolbar_Title));
} finally {
typedArrayBase.recycle();
}
TypedArray typedArray = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.RoomToolbar,
0, 0);
try {
titleTextView.setText(typedArray.getText(R.styleable.RoomToolbar_titleText));
titleTextView.setCompoundDrawablePadding(
typedArray.getLayoutDimension(R.styleable.RoomToolbar_titleDrawablePadding, 0));
} finally {
typedArray.recycle();
}
private void setNavigationIcon() {
Drawable menuDrawable = VectorDrawableCompat.create(getResources(), R.drawable.ic_menu_white_24dp, null);
super.setNavigationIcon(menuDrawable);
}
@Override
public void setTitle(@StringRes int resId) {
if (titleTextView != null) {
titleTextView.setText(resId);
return;
}
super.setTitle(resId);
toolbarText.setText(getContext().getText(resId));
}
@Override
public void setTitle(CharSequence title) {
if (titleTextView != null) {
titleTextView.setText(title);
return;
toolbarText.setText(title);
}
super.setTitle(title);
public void showPrivateChannelIcon() {
roomTypeImage.setImageDrawable(privateChannelDrawable);
userStatusImage.setVisibility(GONE);
roomTypeImage.setVisibility(VISIBLE);
}
public void setRoomIcon(@DrawableRes int drawableResId) {
if (titleTextView == null) {
return;
public void showPublicChannelIcon() {
roomTypeImage.setImageDrawable(publicChannelDrawable);
userStatusImage.setVisibility(GONE);
roomTypeImage.setVisibility(VISIBLE);
}
public void showUserStatusIcon(int status) {
wrapDrawable(userStatusDrawable);
switch (status) {
case STATUS_ONLINE:
tintDrawable(userStatusDrawable, R.color.color_user_status_online);
break;
case STATUS_BUSY:
tintDrawable(userStatusDrawable, R.color.color_user_status_busy);
break;
case STATUS_AWAY:
tintDrawable(userStatusDrawable, R.color.color_user_status_away);
break;
case STATUS_OFFLINE:
tintDrawable(userStatusDrawable, R.color.color_user_status_offline);
break;
default:
tintDrawable(userStatusDrawable, R.color.color_user_status_offline);
break;
}
userStatusImage.setImageDrawable(userStatusDrawable);
roomTypeImage.setVisibility(GONE);
userStatusImage.setVisibility(VISIBLE);
}
Drawable drawable = drawableResId > 0
? VectorDrawableCompat.create(getResources(), drawableResId, null)
: null;
/**
* Wraps a drawable to be used for example for tinting.
* @param drawable The drawable to wrap.
* @see #tintDrawable(Drawable, int)
*/
private void wrapDrawable(Drawable drawable) {
DrawableCompat.wrap(drawable);
}
titleTextView.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null);
/**
* REMARK: You MUST always wrap the drawable before tint it.
* @param drawable The drawable to tint.
* @param color The color to tint the drawable.
* @see #wrapDrawable(Drawable)
*/
private void tintDrawable(Drawable drawable, int color) {
DrawableCompat.setTint(drawable, ContextCompat.getColor(getContext(), color));
}
public void setUnreadBudge(int numUnreadChannels, int numMentionsSum) {
......@@ -138,11 +168,9 @@ public class RoomToolbar extends Toolbar {
.beginConfig()
.useFont(Typeface.SANS_SERIF)
.endConfig()
.buildRound(icon, ContextCompat.getColor(getContext(), R.color.badge_color));
.buildRound(icon, ContextCompat.getColor(getContext(), android.R.color.white));
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
......@@ -164,10 +192,11 @@ public class RoomToolbar extends Toolbar {
int badgeTop = iconTop + (iconBottom - iconTop) / 8;
int badgeBottom = iconTop + (iconBottom - iconTop) * 3 / 8;
badgeImageView.layout(badgeLeft, badgeTop, badgeRight, badgeBottom);
} catch (Exception exception) {
return;
} catch (NoSuchFieldException noSuchFieldException) {
Log.v("RoomToolbar exception: ", noSuchFieldException.getMessage());
} catch (IllegalAccessException illegalAccessException) {
Log.v("RoomToolbar exception: ", illegalAccessException.getMessage());
}
}
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M20.037,10.206 L17.1666,10.206 L17.1666,13.7939 L20.037,13.7939 L20.037,17.3819
L17.1666,17.3819 L17.1666,20.3719 L13.7222,20.3719 L13.7222,17.3819
L10.2778,17.3819 L10.2778,20.3719 L6.83342,20.3719 L6.83342,17.3819
L3.96302,17.3819 L3.96302,13.794 L6.83335,13.794 L6.83335,10.2061
L3.96302,10.2061 L3.96302,6.61814 L6.83335,6.61814 L6.83335,3.62815
L10.2778,3.62815 L10.2778,6.61808 L13.7222,6.61808 L13.7222,3.62815
L17.1666,3.62815 L17.1666,6.61808 L20.037,6.61808 L20.037,10.206 Z
M10.5639,10.2034 L10.5639,13.7966 L13.4361,13.7966 L13.4361,10.2034
L10.5639,10.2034 Z" />
</vector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M18.4596,11.5696 C18.2364,11.3465,17.9655,11.235,17.6466,11.235 L17.2642,11.235
L17.2642,8.93953 C17.2642,7.47311,16.7384,6.21399,15.6863,5.16197
C14.6343,4.10991,13.3753,3.58388,11.9087,3.58388
C10.4421,3.58388,9.18288,4.10991,8.13098,5.16193
C7.07892,6.21399,6.55305,7.47307,6.55305,8.93953 L6.55305,11.235 L6.17056,11.235
C5.85188,11.235,5.58084,11.3465,5.35767,11.5696
C5.13449,11.7927,5.02295,12.0637,5.02295,12.3827 L5.02295,19.2685
C5.02295,19.5872,5.13453,19.8583,5.35767,20.0815
C5.58084,20.3045,5.85188,20.4161,6.17056,20.4161 L17.6469,20.4161
C17.9658,20.4161,18.2366,20.3046,18.4599,20.0815
C18.6828,19.8583,18.7946,19.5872,18.7946,19.2685 L18.7946,12.3825
C18.7948,12.0638,18.6828,11.7928,18.4596,11.5696 Z M14.9691,11.235
L8.84837,11.235 L8.84837,8.93953 C8.84837,8.09477,9.14729,7.37345,9.745,6.77582
C10.3428,6.17811,11.064,5.87931,11.9088,5.87931
C12.7538,5.87931,13.4748,6.17806,14.0726,6.77582
C14.6702,7.37341,14.9691,8.09477,14.9691,8.93953 L14.9691,11.235 Z" />
</vector>
\ No newline at end of file
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M3,18h18v-2L3,16v2zM3,13h18v-2L3,11v2zM3,6v2h18L21,6L3,6z"/>
</vector>
<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="#FF000000"
android:pathData="M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z" />
</vector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/toolbar_title"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"/>
</merge>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
<ImageView
android:id="@+id/image_user_status"
android:layout_width="10dp"
android:layout_height="10dp"
android:layout_marginRight="10dp"
android:layout_marginEnd="10dp"
android:visibility="gone"/>
<ImageView
android:id="@+id/image_room_type"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginRight="10dp"
android:layout_marginEnd="10dp"
android:visibility="gone"/>
<TextView
android:id="@+id/text_toolbar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title" />
</android.support.v7.widget.Toolbar>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="badge_color">#FFFF0000</color>
<dimen name="badge_size">8dp</dimen>
<color name="badge_color">#FFFFFFFF</color>
<dimen name="badge_size">10dp</dimen>
</resources>
\ No newline at end of file
......@@ -3,6 +3,13 @@
<color name="color_accent">#FF2D91FA</color>
<color name="color_shadow">#FFE6E6E7</color>
<color name="color_icon_composer">#FFA8A8A8</color>
<color name="color_timestamp">#FFA8A8A8</color>
<color name="color_embed_hostname">@color/color_timestamp</color>
<!-- User status colors-->
<color name="color_user_status_online">#FF4CAF50</color> <!-- Green 500 -->
<color name="color_user_status_busy">#FFF44336</color> <!-- Red 500-->
<color name="color_user_status_away">#FFFFC107</color> <!-- Amber 500-->
<color name="color_user_status_offline">#FF607D8B</color> <!-- Blue Grey 500-->
</resources>
\ No newline at end of file
plugins {
id "org.jetbrains.kotlin.jvm" version "1.1.3-2"
id "org.jetbrains.kotlin.jvm" version "1.1.4-2"
}
apply plugin: 'idea'
......
......@@ -29,7 +29,7 @@ class AutocompleteUserInteractor(private val room: Room,
return Flowable.zip<String, List<Message>, List<SpotlightUser>, Triple<String, List<Message>, List<SpotlightUser>>>(
Flowable.just(name),
messageRepository.getAllFrom(room),
userRepository.getSortedLikeName(name, SortDirection.DESC, 5).map { it.toSpotlightUsers() },
userRepository.getSortedLikeName(name, 5).map { it.toSpotlightUsers() },
Function3 { a, b, c -> Triple.create(a, b, c) }
)
.flatMap { triple ->
......
......@@ -14,7 +14,7 @@ class CanCreateRoomInteractor(private val userRepository: UserRepository,
fun canCreate(roomId: String): Single<Boolean> {
return Flowable.zip<Optional<User>, Optional<Session>, String, Boolean>(
userRepository.current,
userRepository.getCurrent(),
sessionInteractor.getDefault(),
Flowable.just(roomId),
Function3 { user, session, room -> user.isPresent && session.isPresent && room != null }
......
......@@ -17,7 +17,7 @@ class EditMessageInteractor(private val permissionInteractor: PermissionInteract
fun isAllowed(message: Message): Single<Boolean> {
return Single.zip<Optional<User>, Optional<Room>, Optional<PublicSetting>, Optional<PublicSetting>, Pair<Optional<Room>, Boolean>>(
userRepository.current.first(Optional.absent()),
userRepository.getCurrent().first(Optional.absent()),
roomRepository.getById(message.roomId).first(Optional.absent()),
publicSettingRepository.getById(PublicSettingsConstants.Message.ALLOW_EDITING),
publicSettingRepository.getById(PublicSettingsConstants.Message.ALLOW_EDITING_BLOCK_TIMEOUT),
......
......@@ -14,7 +14,7 @@ class PermissionInteractor(private val userRepository: UserRepository,
private val permissionRepository: PermissionRepository) {
fun isAllowed(permissionId: String, room: Room): Single<Boolean> {
return userRepository.current
return userRepository.getCurrent()
.first(Optional.absent())
.flatMap {
if (!it.isPresent) {
......
......@@ -3,7 +3,6 @@ package chat.rocket.core.interactors;
import io.reactivex.Flowable;
import java.util.List;
import chat.rocket.core.SortDirection;
import chat.rocket.core.models.User;
import chat.rocket.core.repositories.UserRepository;
......@@ -16,6 +15,6 @@ public class UserInteractor {
}
public Flowable<List<User>> getUserAutocompleteSuggestions(String name) {
return userRepository.getSortedLikeName(name, SortDirection.DESC, 5);
return userRepository.getSortedLikeName(name, 5);
}
}
package chat.rocket.core.repositories;
import com.hadisatrio.optional.Optional;
import io.reactivex.Flowable;
import java.util.List;
import chat.rocket.core.SortDirection;
import chat.rocket.core.models.User;
public interface UserRepository {
Flowable<Optional<User>> getCurrent();
Flowable<List<User>> getSortedLikeName(String name, SortDirection direction, int limit);
}
package chat.rocket.core.repositories
import com.hadisatrio.optional.Optional
import io.reactivex.Flowable
import chat.rocket.core.models.User
interface UserRepository {
fun getCurrent(): Flowable<Optional<User>>
fun getByUsername(username: String): Flowable<Optional<User>>
fun getSortedLikeName(name: String, limit: Int): Flowable<List<User>>
}
\ No newline at end of file
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