Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
A
AloqaIM-Android
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
AloqaIM-Android
Commits
825b0b9f
Commit
825b0b9f
authored
Apr 18, 2017
by
Tiago Cunha
Committed by
GitHub
Apr 18, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #253 from RocketChat/feature/autocomplete
Autocomplete users and channels
parents
5002b314
24be134f
Changes
70
Show whitespace changes
Inline
Side-by-side
Showing
70 changed files
with
2470 additions
and
287 deletions
+2470
-287
build.gradle
android-ddp/build.gradle
+1
-1
build.gradle
app/build.gradle
+3
-3
BackgroundLooper.java
app/src/main/java/chat/rocket/android/BackgroundLooper.java
+2
-3
MethodCallHelper.java
...c/main/java/chat/rocket/android/api/MethodCallHelper.java
+38
-0
RoomFragment.java
...a/chat/rocket/android/fragment/chatroom/RoomFragment.java
+96
-9
AbsoluteUrlHelper.java
...in/java/chat/rocket/android/helper/AbsoluteUrlHelper.java
+1
-2
RocketChatUserStatusProvider.java
...rocket/android/renderer/RocketChatUserStatusProvider.java
+40
-0
UserRenderer.java
.../main/java/chat/rocket/android/renderer/UserRenderer.java
+1
-13
DeafultTempSpotlightRoomCaller.java
.../android/service/temp/DeafultTempSpotlightRoomCaller.java
+18
-0
DefaultTempSpotlightUserCaller.java
.../android/service/temp/DefaultTempSpotlightUserCaller.java
+18
-0
fragment_room_main.xml
app/src/main/res/layout/fragment_room_main.xml
+1
-0
build.gradle
log-wrapper/build.gradle
+1
-1
build.gradle
persistence-realm/build.gradle
+1
-1
Migration.java
...rc/main/java/chat/rocket/persistence/realm/Migration.java
+23
-2
RealmStore.java
...c/main/java/chat/rocket/persistence/realm/RealmStore.java
+3
-1
RocketChatPersistenceRealm.java
.../rocket/persistence/realm/RocketChatPersistenceRealm.java
+1
-9
RealmSpotlightRoom.java
...cket/persistence/realm/models/ddp/RealmSpotlightRoom.java
+51
-0
RealmSpotlightUser.java
...cket/persistence/realm/models/ddp/RealmSpotlightUser.java
+62
-0
RealmRepository.java
...ocket/persistence/realm/repositories/RealmRepository.java
+10
-0
RealmRoomRepository.java
...t/persistence/realm/repositories/RealmRoomRepository.java
+59
-0
RealmSpotlightRoomRepository.java
...ence/realm/repositories/RealmSpotlightRoomRepository.java
+63
-0
RealmSpotlightUserRepository.java
...ence/realm/repositories/RealmSpotlightUserRepository.java
+65
-0
RealmUserRepository.java
...t/persistence/realm/repositories/RealmUserRepository.java
+47
-0
build.gradle
rocket-chat-android-widgets/build.gradle
+8
-1
IconProvider.java
.../java/chat/rocket/android/widget/helper/IconProvider.java
+25
-0
UserStatusProvider.java
...chat/rocket/android/widget/helper/UserStatusProvider.java
+9
-0
ImageKeyboardEditText.java
.../rocket/android/widget/message/ImageKeyboardEditText.java
+2
-10
MessageFormLayout.java
...chat/rocket/android/widget/message/MessageFormLayout.java
+7
-1
AutocompleteAdapter.java
...roid/widget/message/autocomplete/AutocompleteAdapter.java
+64
-0
AutocompleteItem.java
...android/widget/message/autocomplete/AutocompleteItem.java
+9
-0
AutocompleteManager.java
...roid/widget/message/autocomplete/AutocompleteManager.java
+267
-0
AutocompleteSource.java
...droid/widget/message/autocomplete/AutocompleteSource.java
+50
-0
AutocompleteViewHolder.java
...d/widget/message/autocomplete/AutocompleteViewHolder.java
+19
-0
ChannelAdapter.java
...d/widget/message/autocomplete/channel/ChannelAdapter.java
+19
-0
ChannelItem.java
...roid/widget/message/autocomplete/channel/ChannelItem.java
+28
-0
ChannelSource.java
...id/widget/message/autocomplete/channel/ChannelSource.java
+111
-0
ChannelViewHolder.java
...idget/message/autocomplete/channel/ChannelViewHolder.java
+49
-0
UserAdapter.java
...android/widget/message/autocomplete/user/UserAdapter.java
+19
-0
UserItem.java
...et/android/widget/message/autocomplete/user/UserItem.java
+39
-0
UserSource.java
.../android/widget/message/autocomplete/user/UserSource.java
+115
-0
UserViewHolder.java
...roid/widget/message/autocomplete/user/UserViewHolder.java
+128
-0
autocomplete_background.xml
...widgets/src/main/res/drawable/autocomplete_background.xml
+16
-0
autocomplete_box.xml
...-android-widgets/src/main/res/layout/autocomplete_box.xml
+18
-0
autocomplete_channel_view.xml
...widgets/src/main/res/layout/autocomplete_channel_view.xml
+29
-0
autocomplete_user_view.xml
...id-widgets/src/main/res/layout/autocomplete_user_view.xml
+34
-0
strings.xml
rocket-chat-android-widgets/src/main/res/values/strings.xml
+2
-0
build.gradle
rocket-chat-core/build.gradle
+10
-6
SortDirection.java
...at-core/src/main/java/chat/rocket/core/SortDirection.java
+6
-0
AutocompleteChannelInteractor.kt
.../rocket/core/interactors/AutocompleteChannelInteractor.kt
+76
-0
AutocompleteUserInteractor.kt
...hat/rocket/core/interactors/AutocompleteUserInteractor.kt
+93
-0
CanCreateRoomInteractor.java
...chat/rocket/core/interactors/CanCreateRoomInteractor.java
+0
-28
CanCreateRoomInteractor.kt
...a/chat/rocket/core/interactors/CanCreateRoomInteractor.kt
+24
-0
MessageInteractor.java
.../java/chat/rocket/core/interactors/MessageInteractor.java
+0
-91
MessageInteractor.kt
...in/java/chat/rocket/core/interactors/MessageInteractor.kt
+79
-0
RoomInteractor.java
...ain/java/chat/rocket/core/interactors/RoomInteractor.java
+0
-42
RoomInteractor.kt
.../main/java/chat/rocket/core/interactors/RoomInteractor.kt
+45
-0
SessionInteractor.java
.../java/chat/rocket/core/interactors/SessionInteractor.java
+0
-63
SessionInteractor.kt
...in/java/chat/rocket/core/interactors/SessionInteractor.kt
+59
-0
UserInteractor.java
...ain/java/chat/rocket/core/interactors/UserInteractor.java
+21
-0
SpotlightRoom.java
.../src/main/java/chat/rocket/core/models/SpotlightRoom.java
+41
-0
SpotlightUser.java
.../src/main/java/chat/rocket/core/models/SpotlightUser.java
+37
-0
RoomRepository.java
...in/java/chat/rocket/core/repositories/RoomRepository.java
+5
-0
SpotlightRoomRepository.java
...hat/rocket/core/repositories/SpotlightRoomRepository.java
+12
-0
SpotlightUserRepository.java
...hat/rocket/core/repositories/SpotlightUserRepository.java
+12
-0
UserRepository.java
...in/java/chat/rocket/core/repositories/UserRepository.java
+4
-0
TempSpotlightRoomCaller.java
...n/java/chat/rocket/core/temp/TempSpotlightRoomCaller.java
+6
-0
TempSpotlightUserCaller.java
...n/java/chat/rocket/core/temp/TempSpotlightUserCaller.java
+6
-0
Pair.java
...-chat-core/src/main/java/chat/rocket/core/utils/Pair.java
+82
-0
Triple.java
...hat-core/src/main/java/chat/rocket/core/utils/Triple.java
+38
-0
AutocompleteChannelInteractorTest.java
...t/core/interactors/AutocompleteChannelInteractorTest.java
+142
-0
No files found.
android-ddp/build.gradle
View file @
825b0b9f
...
...
@@ -6,7 +6,7 @@ buildscript {
jcenter
()
}
dependencies
{
classpath
'com.android.tools.build:gradle:2.3.
0
'
classpath
'com.android.tools.build:gradle:2.3.
1
'
classpath
'me.tatarka:gradle-retrolambda:3.5.0'
classpath
'me.tatarka.retrolambda.projectlombok:lombok.ast:0.2.3.a2'
}
...
...
app/build.gradle
View file @
825b0b9f
...
...
@@ -10,7 +10,7 @@ buildscript {
mavenCentral
()
}
dependencies
{
classpath
'com.android.tools.build:gradle:2.3.
0
'
classpath
'com.android.tools.build:gradle:2.3.
1
'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
...
...
@@ -33,8 +33,8 @@ android {
applicationId
"chat.rocket.android"
minSdkVersion
16
targetSdkVersion
25
versionCode
17
versionName
"1.0.
8
"
versionCode
20
versionName
"1.0.
10
"
testInstrumentationRunner
"android.support.test.runner.AndroidJUnitRunner"
vectorDrawables
.
useSupportLibrary
=
true
...
...
app/src/main/java/chat/rocket/android/BackgroundLooper.java
View file @
825b0b9f
package
chat
.
rocket
.
android
;
import
android.os.HandlerThread
;
import
android.os.Looper
;
import
android.os.Process
;
...
...
@@ -11,8 +10,8 @@ public class BackgroundLooper {
public
static
Looper
get
()
{
if
(
handlerThread
==
null
)
{
handlerThread
=
new
HandlerThread
(
"BackgroundHandlerThread"
,
Process
.
THREAD_PRIORITY_BACKGROUND
);
handlerThread
=
new
HandlerThread
(
"BackgroundHandlerThread"
,
Process
.
THREAD_PRIORITY_BACKGROUND
);
handlerThread
.
start
();
}
...
...
app/src/main/java/chat/rocket/android/api/MethodCallHelper.java
View file @
825b0b9f
...
...
@@ -16,6 +16,8 @@ import chat.rocket.persistence.realm.models.ddp.RealmPublicSetting;
import
chat.rocket.core.SyncState
;
import
chat.rocket.persistence.realm.models.ddp.RealmMessage
;
import
chat.rocket.persistence.realm.models.ddp.RealmRoom
;
import
chat.rocket.persistence.realm.models.ddp.RealmSpotlightRoom
;
import
chat.rocket.persistence.realm.models.ddp.RealmSpotlightUser
;
import
chat.rocket.persistence.realm.models.internal.MethodCall
;
import
chat.rocket.persistence.realm.models.internal.RealmSession
;
import
chat.rocket.persistence.realm.RealmHelper
;
...
...
@@ -366,6 +368,42 @@ public class MethodCallHelper {
});
}
public
Task
<
Void
>
searchSpotlightUsers
(
String
term
)
{
return
searchSpotlight
(
RealmSpotlightUser
.
class
,
"users"
,
term
);
}
public
Task
<
Void
>
searchSpotlightRooms
(
String
term
)
{
return
searchSpotlight
(
RealmSpotlightRoom
.
class
,
"rooms"
,
term
);
}
private
Task
<
Void
>
searchSpotlight
(
Class
clazz
,
String
key
,
String
term
)
{
return
call
(
"spotlight"
,
TIMEOUT_MS
,
()
->
new
JSONArray
()
.
put
(
term
)
.
put
(
JSONObject
.
NULL
)
.
put
(
new
JSONObject
().
put
(
key
,
true
)))
.
onSuccessTask
(
CONVERT_TO_JSON_OBJECT
)
.
onSuccessTask
(
task
->
{
final
JSONObject
result
=
task
.
getResult
();
if
(!
result
.
has
(
key
))
{
return
null
;
}
Object
items
=
result
.
get
(
key
);
if
(!(
items
instanceof
JSONArray
))
{
return
null
;
}
return
realmHelper
.
executeTransaction
(
realm
->
{
realm
.
delete
(
clazz
);
realm
.
createOrUpdateAllFromJson
(
clazz
,
(
JSONArray
)
items
);
return
null
;
});
});
}
protected
interface
ParamBuilder
{
JSONArray
buildParam
()
throws
JSONException
;
...
...
app/src/main/java/chat/rocket/android/fragment/chatroom/RoomFragment.java
View file @
825b0b9f
package
chat
.
rocket
.
android
.
fragment
.
chatroom
;
import
android.Manifest
;
import
android.annotation.SuppressLint
;
import
android.app.Activity
;
import
android.content.Intent
;
import
android.net.Uri
;
...
...
@@ -13,6 +12,7 @@ import android.support.v13.view.inputmethod.InputConnectionCompat;
import
android.support.v13.view.inputmethod.InputContentInfoCompat
;
import
android.support.v4.app.DialogFragment
;
import
android.support.v4.os.BuildCompat
;
import
android.support.v4.util.Pair
;
import
android.support.v4.view.GravityCompat
;
import
android.support.v4.widget.DrawerLayout
;
import
android.support.v4.widget.SlidingPaneLayout
;
...
...
@@ -20,12 +20,20 @@ import android.support.v7.app.AlertDialog;
import
android.support.v7.widget.LinearLayoutManager
;
import
android.support.v7.widget.RecyclerView
;
import
android.view.View
;
import
android.view.ViewGroup
;
import
com.fernandocejas.arrow.optional.Optional
;
import
com.jakewharton.rxbinding2.support.v4.widget.RxDrawerLayout
;
import
io.reactivex.Single
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.reactivex.disposables.CompositeDisposable
;
import
io.reactivex.disposables.Disposable
;
import
java.lang.reflect.Field
;
import
java.util.ArrayList
;
import
java.util.List
;
import
chat.rocket.android.BackgroundLooper
;
import
chat.rocket.android.R
;
import
chat.rocket.android.api.MethodCallHelper
;
import
chat.rocket.android.fragment.chatroom.dialog.FileUploadProgressDialogFragment
;
...
...
@@ -49,6 +57,14 @@ import chat.rocket.android.layouthelper.extra_action.upload.AudioUploadActionIte
import
chat.rocket.android.layouthelper.extra_action.upload.ImageUploadActionItem
;
import
chat.rocket.android.layouthelper.extra_action.upload.VideoUploadActionItem
;
import
chat.rocket.android.log.RCLog
;
import
chat.rocket.android.renderer.RocketChatUserStatusProvider
;
import
chat.rocket.android.service.temp.DeafultTempSpotlightRoomCaller
;
import
chat.rocket.android.service.temp.DefaultTempSpotlightUserCaller
;
import
chat.rocket.android.widget.message.autocomplete.AutocompleteManager
;
import
chat.rocket.android.widget.message.autocomplete.channel.ChannelSource
;
import
chat.rocket.android.widget.message.autocomplete.user.UserSource
;
import
chat.rocket.core.interactors.AutocompleteChannelInteractor
;
import
chat.rocket.core.interactors.AutocompleteUserInteractor
;
import
chat.rocket.core.interactors.MessageInteractor
;
import
chat.rocket.core.interactors.SessionInteractor
;
import
chat.rocket.core.models.Message
;
...
...
@@ -57,6 +73,8 @@ import chat.rocket.persistence.realm.repositories.RealmMessageRepository;
import
chat.rocket.persistence.realm.repositories.RealmRoomRepository
;
import
chat.rocket.persistence.realm.repositories.RealmServerInfoRepository
;
import
chat.rocket.persistence.realm.repositories.RealmSessionRepository
;
import
chat.rocket.persistence.realm.repositories.RealmSpotlightRoomRepository
;
import
chat.rocket.persistence.realm.repositories.RealmSpotlightUserRepository
;
import
chat.rocket.persistence.realm.repositories.RealmUserRepository
;
import
chat.rocket.android.layouthelper.chatroom.ModelListAdapter
;
import
chat.rocket.persistence.realm.RealmStore
;
...
...
@@ -87,11 +105,19 @@ public class RoomFragment extends AbstractChatRoomFragment
protected
Snackbar
unreadIndicator
;
private
boolean
previousUnreadMessageExists
;
private
MessageListAdapter
adapter
;
private
AutocompleteManager
autocompleteManager
;
private
List
<
AbstractExtraActionItem
>
extraActionItems
;
private
CompositeDisposable
compositeDisposable
=
new
CompositeDisposable
();
protected
RoomContract
.
Presenter
presenter
;
private
RealmRoomRepository
roomRepository
;
private
RealmUserRepository
userRepository
;
private
MethodCallHelper
methodCallHelper
;
private
AbsoluteUrlHelper
absoluteUrlHelper
;
public
RoomFragment
()
{
}
...
...
@@ -117,29 +143,31 @@ public class RoomFragment extends AbstractChatRoomFragment
hostname
=
args
.
getString
(
HOSTNAME
);
roomId
=
args
.
getString
(
ROOM_ID
);
RealmRoomRepository
roomRepository
=
new
RealmRoomRepository
(
hostname
);
roomRepository
=
new
RealmRoomRepository
(
hostname
);
MessageInteractor
messageInteractor
=
new
MessageInteractor
(
new
RealmMessageRepository
(
hostname
),
roomRepository
);
RealmUserRepository
userRepository
=
new
RealmUserRepository
(
hostname
);
userRepository
=
new
RealmUserRepository
(
hostname
);
AbsoluteUrlHelper
absoluteUrlHelper
=
new
AbsoluteUrlHelper
(
absoluteUrlHelper
=
new
AbsoluteUrlHelper
(
hostname
,
new
RealmServerInfoRepository
(),
userRepository
,
new
SessionInteractor
(
new
RealmSessionRepository
(
hostname
))
);
methodCallHelper
=
new
MethodCallHelper
(
getContext
(),
hostname
);
presenter
=
new
RoomPresenter
(
roomId
,
userRepository
,
messageInteractor
,
roomRepository
,
absoluteUrlHelper
,
new
MethodCallHelper
(
getContext
(),
hostname
)
,
methodCallHelper
,
ConnectivityManager
.
getInstance
(
getContext
())
);
...
...
@@ -238,6 +266,14 @@ public class RoomFragment extends AbstractChatRoomFragment
adapter
.
unregisterAdapterDataObserver
(
autoScrollManager
);
}
}
compositeDisposable
.
clear
();
if
(
autocompleteManager
!=
null
)
{
autocompleteManager
.
dispose
();
autocompleteManager
=
null
;
}
super
.
onDestroyView
();
}
...
...
@@ -246,7 +282,6 @@ public class RoomFragment extends AbstractChatRoomFragment
presenter
.
onMessageSelected
(
pairedMessage
.
target
);
}
@SuppressLint
(
"RxLeakedSubscription"
)
private
void
setupSideMenu
()
{
View
sideMenu
=
rootView
.
findViewById
(
R
.
id
.
room_side_menu
);
sideMenu
.
findViewById
(
R
.
id
.
btn_users
).
setOnClickListener
(
view
->
{
...
...
@@ -258,7 +293,7 @@ public class RoomFragment extends AbstractChatRoomFragment
DrawerLayout
drawerLayout
=
(
DrawerLayout
)
rootView
.
findViewById
(
R
.
id
.
drawer_layout
);
SlidingPaneLayout
pane
=
(
SlidingPaneLayout
)
getActivity
().
findViewById
(
R
.
id
.
sliding_pane
);
if
(
drawerLayout
!=
null
&&
pane
!=
null
)
{
RxDrawerLayout
.
drawerOpen
(
drawerLayout
,
GravityCompat
.
END
)
compositeDisposable
.
add
(
RxDrawerLayout
.
drawerOpen
(
drawerLayout
,
GravityCompat
.
END
)
.
compose
(
bindToLifecycle
())
.
subscribe
(
opened
->
{
...
...
@@ -271,6 +306,7 @@ public class RoomFragment extends AbstractChatRoomFragment
}
},
Logger:
:
report
)
);
}
}
...
...
@@ -290,7 +326,58 @@ public class RoomFragment extends AbstractChatRoomFragment
messageFormManager
=
new
MessageFormManager
(
messageFormLayout
,
this
::
showExtraActionSelectionDialog
);
messageFormManager
.
setSendMessageCallback
(
this
::
sendMessage
);
messageFormLayout
.
setEditTextContentListener
(
this
::
onCommitContent
);
messageFormLayout
.
setEditTextCommitContentListener
(
this
::
onCommitContent
);
autocompleteManager
=
new
AutocompleteManager
((
ViewGroup
)
rootView
.
findViewById
(
R
.
id
.
message_list_root
));
autocompleteManager
.
registerSource
(
new
ChannelSource
(
new
AutocompleteChannelInteractor
(
roomRepository
,
new
RealmSpotlightRoomRepository
(
hostname
),
new
DeafultTempSpotlightRoomCaller
(
methodCallHelper
)
),
AndroidSchedulers
.
from
(
BackgroundLooper
.
get
()),
AndroidSchedulers
.
mainThread
()
)
);
Disposable
disposable
=
Single
.
zip
(
absoluteUrlHelper
.
getRocketChatAbsoluteUrl
(),
roomRepository
.
getById
(
roomId
).
first
(
Optional
.
absent
()),
Pair:
:
create
)
.
subscribe
(
pair
->
{
if
(
pair
.
first
.
isPresent
()
&&
pair
.
second
.
isPresent
())
{
autocompleteManager
.
registerSource
(
new
UserSource
(
new
AutocompleteUserInteractor
(
pair
.
second
.
get
(),
userRepository
,
new
RealmMessageRepository
(
hostname
),
new
RealmSpotlightUserRepository
(
hostname
),
new
DefaultTempSpotlightUserCaller
(
methodCallHelper
)
),
pair
.
first
.
get
(),
RocketChatUserStatusProvider
.
getInstance
(),
AndroidSchedulers
.
from
(
BackgroundLooper
.
get
()),
AndroidSchedulers
.
mainThread
()
)
);
}
},
throwable
->
{
}
);
compositeDisposable
.
add
(
disposable
);
autocompleteManager
.
bindTo
(
messageFormLayout
.
getEditText
(),
messageFormLayout
);
}
@Override
...
...
app/src/main/java/chat/rocket/android/helper/AbsoluteUrlHelper.java
View file @
825b0b9f
...
...
@@ -38,8 +38,7 @@ public class AbsoluteUrlHelper {
.
filter
(
Optional:
:
isPresent
)
.
map
(
Optional:
:
get
),
(
info
,
user
,
session
)
->
Optional
.
of
(
new
RocketChatAbsoluteUrl
(
info
,
user
,
session
info
,
user
,
session
))
)
.
first
(
Optional
.
absent
());
...
...
app/src/main/java/chat/rocket/android/renderer/RocketChatUserStatusProvider.java
0 → 100644
View file @
825b0b9f
package
chat
.
rocket
.
android
.
renderer
;
import
android.support.annotation.DrawableRes
;
import
chat.rocket.android.R
;
import
chat.rocket.android.widget.helper.UserStatusProvider
;
import
chat.rocket.core.models.User
;
public
class
RocketChatUserStatusProvider
implements
UserStatusProvider
{
private
static
RocketChatUserStatusProvider
instance
;
private
RocketChatUserStatusProvider
()
{
}
public
static
RocketChatUserStatusProvider
getInstance
()
{
if
(
instance
==
null
)
{
instance
=
new
RocketChatUserStatusProvider
();
}
return
instance
;
}
@Override
@DrawableRes
public
int
getStatusResId
(
String
status
)
{
if
(
User
.
STATUS_ONLINE
.
equals
(
status
))
{
return
R
.
drawable
.
userstatus_online
;
}
else
if
(
User
.
STATUS_AWAY
.
equals
(
status
))
{
return
R
.
drawable
.
userstatus_away
;
}
else
if
(
User
.
STATUS_BUSY
.
equals
(
status
))
{
return
R
.
drawable
.
userstatus_busy
;
}
else
if
(
User
.
STATUS_OFFLINE
.
equals
(
status
))
{
return
R
.
drawable
.
userstatus_offline
;
}
// unknown status is rendered as "offline" status.
return
R
.
drawable
.
userstatus_offline
;
}
}
app/src/main/java/chat/rocket/android/renderer/UserRenderer.java
View file @
825b0b9f
...
...
@@ -4,7 +4,6 @@ import android.content.Context;
import
android.widget.ImageView
;
import
android.widget.TextView
;
import
chat.rocket.android.R
;
import
chat.rocket.android.helper.Avatar
;
import
chat.rocket.android.helper.TextUtils
;
import
chat.rocket.android.widget.AbsoluteUrl
;
...
...
@@ -56,18 +55,7 @@ public class UserRenderer extends AbstractRenderer<User> {
}
String
status
=
object
.
getStatus
();
if
(
User
.
STATUS_ONLINE
.
equals
(
status
))
{
imageView
.
setImageResource
(
R
.
drawable
.
userstatus_online
);
}
else
if
(
User
.
STATUS_AWAY
.
equals
(
status
))
{
imageView
.
setImageResource
(
R
.
drawable
.
userstatus_away
);
}
else
if
(
User
.
STATUS_BUSY
.
equals
(
status
))
{
imageView
.
setImageResource
(
R
.
drawable
.
userstatus_busy
);
}
else
if
(
User
.
STATUS_OFFLINE
.
equals
(
status
))
{
imageView
.
setImageResource
(
R
.
drawable
.
userstatus_offline
);
}
else
{
// unknown status is rendered as "offline" status.
imageView
.
setImageResource
(
R
.
drawable
.
userstatus_offline
);
}
imageView
.
setImageResource
(
RocketChatUserStatusProvider
.
getInstance
().
getStatusResId
(
status
));
return
this
;
}
...
...
app/src/main/java/chat/rocket/android/service/temp/DeafultTempSpotlightRoomCaller.java
0 → 100644
View file @
825b0b9f
package
chat
.
rocket
.
android
.
service
.
temp
;
import
chat.rocket.android.api.MethodCallHelper
;
import
chat.rocket.core.temp.TempSpotlightRoomCaller
;
public
class
DeafultTempSpotlightRoomCaller
implements
TempSpotlightRoomCaller
{
private
final
MethodCallHelper
methodCallHelper
;
public
DeafultTempSpotlightRoomCaller
(
MethodCallHelper
methodCallHelper
)
{
this
.
methodCallHelper
=
methodCallHelper
;
}
@Override
public
void
search
(
String
term
)
{
methodCallHelper
.
searchSpotlightRooms
(
term
);
}
}
app/src/main/java/chat/rocket/android/service/temp/DefaultTempSpotlightUserCaller.java
0 → 100644
View file @
825b0b9f
package
chat
.
rocket
.
android
.
service
.
temp
;
import
chat.rocket.android.api.MethodCallHelper
;
import
chat.rocket.core.temp.TempSpotlightUserCaller
;
public
class
DefaultTempSpotlightUserCaller
implements
TempSpotlightUserCaller
{
private
final
MethodCallHelper
methodCallHelper
;
public
DefaultTempSpotlightUserCaller
(
MethodCallHelper
methodCallHelper
)
{
this
.
methodCallHelper
=
methodCallHelper
;
}
@Override
public
void
search
(
String
term
)
{
methodCallHelper
.
searchSpotlightUsers
(
term
);
}
}
app/src/main/res/layout/fragment_room_main.xml
View file @
825b0b9f
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:id=
"@+id/message_list_root"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
>
...
...
log-wrapper/build.gradle
View file @
825b0b9f
...
...
@@ -5,7 +5,7 @@ buildscript {
jcenter
()
}
dependencies
{
classpath
'com.android.tools.build:gradle:2.3.
0
'
classpath
'com.android.tools.build:gradle:2.3.
1
'
}
}
...
...
persistence-realm/build.gradle
View file @
825b0b9f
...
...
@@ -8,7 +8,7 @@ buildscript {
jcenter
()
}
dependencies
{
classpath
'com.android.tools.build:gradle:2.3.
0
'
classpath
'com.android.tools.build:gradle:2.3.
1
'
classpath
'io.realm:realm-gradle-plugin:2.3.2'
classpath
'me.tatarka:gradle-retrolambda:3.5.0'
classpath
'me.tatarka.retrolambda.projectlombok:lombok.ast:0.2.3.a2'
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/Migration.java
View file @
825b0b9f
package
chat
.
rocket
.
persistence
.
realm
;
import
io.realm.DynamicRealm
;
import
io.realm.FieldAttribute
;
import
io.realm.RealmMigration
;
import
io.realm.RealmObjectSchema
;
import
io.realm.RealmSchema
;
import
chat.rocket.persistence.realm.models.ddp.RealmSpotlightRoom
;
import
chat.rocket.persistence.realm.models.ddp.RealmSpotlightUser
;
public
class
Migration
implements
RealmMigration
{
@Override
public
void
migrate
(
DynamicRealm
dynamicRealm
,
long
oldVersion
,
long
newVersion
)
{
...
...
@@ -12,11 +16,28 @@ public class Migration implements RealmMigration {
RealmSchema
schema
=
dynamicRealm
.
getSchema
();
if
(
oldVersion
==
0
)
{
RealmObjectSchema
roomSchema
=
schema
.
get
(
"RealmRoom"
);
// NOOP
oldVersion
++;
}
if
(
oldVersion
==
1
)
{
schema
.
create
(
"RealmSpotlightUser"
)
.
addField
(
RealmSpotlightUser
.
Columns
.
ID
,
String
.
class
,
FieldAttribute
.
PRIMARY_KEY
)
.
addField
(
RealmSpotlightUser
.
Columns
.
USERNAME
,
String
.
class
)
.
addField
(
RealmSpotlightUser
.
Columns
.
STATUS
,
String
.
class
);
roomSchema
.
addField
(
"f"
,
boolean
.
class
);
schema
.
create
(
"RealmSpotlightRoom"
)
.
addField
(
RealmSpotlightRoom
.
Columns
.
ID
,
String
.
class
,
FieldAttribute
.
PRIMARY_KEY
)
.
addField
(
RealmSpotlightRoom
.
Columns
.
NAME
,
String
.
class
)
.
addField
(
RealmSpotlightRoom
.
Columns
.
TYPE
,
String
.
class
);
oldVersion
++;
}
if
(
oldVersion
==
2
)
{
RealmObjectSchema
roomSchema
=
schema
.
get
(
"RealmSpotlightUser"
);
roomSchema
.
addField
(
RealmSpotlightUser
.
Columns
.
NAME
,
String
.
class
);
}
}
}
persistence-realm/src/main/java/chat/rocket/persistence/realm/RealmStore.java
View file @
825b0b9f
...
...
@@ -14,7 +14,9 @@ public class RealmStore {
return
new
RealmConfiguration
.
Builder
()
.
name
(
name
+
".realm"
)
.
modules
(
new
RocketChatLibraryModule
())
.
deleteRealmIfMigrationNeeded
().
build
();
.
migration
(
new
Migration
())
.
schemaVersion
(
3
)
.
build
();
}
public
static
void
put
(
String
name
)
{
...
...
persistence-realm/src/main/java/chat/rocket/persistence/realm/RocketChatPersistenceRealm.java
View file @
825b0b9f
...
...
@@ -4,19 +4,11 @@ import android.content.Context;
import
io.realm.Realm
;
import
io.realm.RealmConfiguration
;
import
chat.rocket.persistence.realm.modules.RocketChatLibraryModule
;
public
class
RocketChatPersistenceRealm
{
public
static
void
init
(
Context
context
)
{
Realm
.
init
(
context
);
Realm
.
setDefaultConfiguration
(
new
RealmConfiguration
.
Builder
()
.
name
(
"rocket.chat.persistence.realm"
)
.
modules
(
new
RocketChatLibraryModule
())
.
schemaVersion
(
1
)
.
migration
(
new
Migration
())
.
build
());
Realm
.
setDefaultConfiguration
(
new
RealmConfiguration
.
Builder
().
build
());
}
}
persistence-realm/src/main/java/chat/rocket/persistence/realm/models/ddp/RealmSpotlightRoom.java
0 → 100644
View file @
825b0b9f
package
chat
.
rocket
.
persistence
.
realm
.
models
.
ddp
;
import
io.realm.RealmObject
;
import
io.realm.annotations.PrimaryKey
;
import
chat.rocket.core.models.SpotlightRoom
;
public
class
RealmSpotlightRoom
extends
RealmObject
{
public
interface
Columns
{
String
ID
=
"_id"
;
String
NAME
=
"name"
;
String
TYPE
=
"t"
;
}
@PrimaryKey
private
String
_id
;
private
String
name
;
private
String
t
;
public
String
getId
()
{
return
_id
;
}
public
void
setId
(
String
_id
)
{
this
.
_id
=
_id
;
}
public
String
getName
()
{
return
name
;
}
public
void
setName
(
String
name
)
{
this
.
name
=
name
;
}
public
String
getType
()
{
return
t
;
}
public
void
setType
(
String
t
)
{
this
.
t
=
t
;
}
public
SpotlightRoom
asSpotlightRoom
()
{
return
SpotlightRoom
.
builder
()
.
setId
(
_id
)
.
setName
(
name
)
.
setType
(
t
)
.
build
();
}
}
persistence-realm/src/main/java/chat/rocket/persistence/realm/models/ddp/RealmSpotlightUser.java
0 → 100644
View file @
825b0b9f
package
chat
.
rocket
.
persistence
.
realm
.
models
.
ddp
;
import
io.realm.RealmObject
;
import
io.realm.annotations.PrimaryKey
;
import
chat.rocket.core.models.SpotlightUser
;
public
class
RealmSpotlightUser
extends
RealmObject
{
public
interface
Columns
{
String
ID
=
"_id"
;
String
USERNAME
=
"username"
;
String
NAME
=
"name"
;
String
STATUS
=
"status"
;
}
@PrimaryKey
private
String
_id
;
private
String
username
;
private
String
name
;
private
String
status
;
public
String
getId
()
{
return
_id
;
}
public
void
setId
(
String
_id
)
{
this
.
_id
=
_id
;
}
public
String
getUsername
()
{
return
username
;
}
public
void
setUsername
(
String
username
)
{
this
.
username
=
username
;
}
public
String
getName
()
{
return
name
;
}
public
void
setName
(
String
name
)
{
this
.
name
=
name
;
}
public
String
getStatus
()
{
return
status
;
}
public
void
setStatus
(
String
status
)
{
this
.
status
=
status
;
}
public
SpotlightUser
asSpotlightUser
()
{
return
SpotlightUser
.
builder
()
.
setId
(
_id
)
.
setUsername
(
username
)
.
setName
(
name
)
.
setStatus
(
status
)
.
build
();
}
}
persistence-realm/src/main/java/chat/rocket/persistence/realm/repositories/RealmRepository.java
View file @
825b0b9f
...
...
@@ -3,6 +3,10 @@ package chat.rocket.persistence.realm.repositories;
import
android.os.Handler
;
import
android.os.Looper
;
import
io.realm.Realm
;
import
io.realm.RealmObject
;
import
io.realm.RealmResults
;
import
java.util.List
;
public
class
RealmRepository
{
...
...
@@ -12,4 +16,10 @@ public class RealmRepository {
}
new
Handler
(
looper
).
post
(
realm:
:
close
);
}
protected
<
T
extends
RealmObject
>
List
<
T
>
safeSubList
(
RealmResults
<
T
>
realmObjects
,
int
fromIndex
,
int
toIndex
)
{
return
realmObjects
.
subList
(
Math
.
max
(
0
,
fromIndex
),
Math
.
min
(
realmObjects
.
size
(),
toIndex
));
}
}
persistence-realm/src/main/java/chat/rocket/persistence/realm/repositories/RealmRoomRepository.java
View file @
825b0b9f
...
...
@@ -6,11 +6,14 @@ import com.fernandocejas.arrow.optional.Optional;
import
io.reactivex.Flowable
;
import
io.reactivex.Single
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.realm.Case
;
import
io.realm.Realm
;
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.Room
;
import
chat.rocket.core.models.RoomHistoryState
;
import
chat.rocket.core.repositories.RoomRepository
;
...
...
@@ -141,6 +144,50 @@ public class RealmRoomRepository extends RealmRepository implements RoomReposito
});
}
@Override
public
Flowable
<
List
<
Room
>>
getSortedLikeName
(
String
name
,
SortDirection
direction
,
int
limit
)
{
return
Flowable
.
defer
(()
->
Flowable
.
using
(
()
->
new
Pair
<>(
RealmStore
.
getRealm
(
hostname
),
Looper
.
myLooper
()),
pair
->
RxJavaInterop
.
toV2Flowable
(
pair
.
first
.
where
(
RealmRoom
.
class
)
.
like
(
RealmRoom
.
NAME
,
"*"
+
name
+
"*"
,
Case
.
INSENSITIVE
)
.
beginGroup
()
.
equalTo
(
RealmRoom
.
TYPE
,
RealmRoom
.
TYPE_CHANNEL
)
.
or
()
.
equalTo
(
RealmRoom
.
TYPE
,
RealmRoom
.
TYPE_PRIVATE
)
.
endGroup
()
.
findAllSorted
(
RealmRoom
.
NAME
,
direction
.
equals
(
SortDirection
.
ASC
)
?
Sort
.
ASCENDING
:
Sort
.
DESCENDING
)
.
asObservable
()),
pair
->
close
(
pair
.
first
,
pair
.
second
)
)
.
unsubscribeOn
(
AndroidSchedulers
.
from
(
Looper
.
myLooper
()))
.
filter
(
roomSubscriptions
->
roomSubscriptions
!=
null
&&
roomSubscriptions
.
isLoaded
()
&&
roomSubscriptions
.
isValid
())
.
map
(
realmRooms
->
toList
(
safeSubList
(
realmRooms
,
0
,
limit
))));
}
@Override
public
Flowable
<
List
<
Room
>>
getLatestSeen
(
int
limit
)
{
return
Flowable
.
defer
(()
->
Flowable
.
using
(
()
->
new
Pair
<>(
RealmStore
.
getRealm
(
hostname
),
Looper
.
myLooper
()),
pair
->
RxJavaInterop
.
toV2Flowable
(
pair
.
first
.
where
(
RealmRoom
.
class
)
.
beginGroup
()
.
equalTo
(
RealmRoom
.
TYPE
,
RealmRoom
.
TYPE_CHANNEL
)
.
or
()
.
equalTo
(
RealmRoom
.
TYPE
,
RealmRoom
.
TYPE_PRIVATE
)
.
endGroup
()
.
findAllSorted
(
RealmRoom
.
LAST_SEEN
,
Sort
.
ASCENDING
)
.
asObservable
()),
pair
->
close
(
pair
.
first
,
pair
.
second
)
)
.
unsubscribeOn
(
AndroidSchedulers
.
from
(
Looper
.
myLooper
()))
.
filter
(
roomSubscriptions
->
roomSubscriptions
!=
null
&&
roomSubscriptions
.
isLoaded
()
&&
roomSubscriptions
.
isValid
())
.
map
(
realmRooms
->
toList
(
safeSubList
(
realmRooms
,
0
,
limit
))));
}
private
List
<
Room
>
toList
(
RealmResults
<
RealmRoom
>
realmRooms
)
{
int
total
=
realmRooms
.
size
();
...
...
@@ -152,4 +199,16 @@ public class RealmRoomRepository extends RealmRepository implements RoomReposito
return
roomList
;
}
private
List
<
Room
>
toList
(
List
<
RealmRoom
>
realmRooms
)
{
int
total
=
realmRooms
.
size
();
final
List
<
Room
>
roomList
=
new
ArrayList
<>(
total
);
for
(
int
i
=
0
;
i
<
total
;
i
++)
{
roomList
.
add
(
realmRooms
.
get
(
i
).
asRoom
());
}
return
roomList
;
}
}
persistence-realm/src/main/java/chat/rocket/persistence/realm/repositories/RealmSpotlightRoomRepository.java
0 → 100644
View file @
825b0b9f
package
chat
.
rocket
.
persistence
.
realm
.
repositories
;
import
android.os.Looper
;
import
android.support.v4.util.Pair
;
import
io.reactivex.Flowable
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.realm.Case
;
import
io.realm.Sort
;
import
java.util.ArrayList
;
import
java.util.List
;
import
chat.rocket.core.SortDirection
;
import
chat.rocket.core.models.SpotlightRoom
;
import
chat.rocket.core.repositories.SpotlightRoomRepository
;
import
chat.rocket.persistence.realm.RealmStore
;
import
chat.rocket.persistence.realm.models.ddp.RealmRoom
;
import
chat.rocket.persistence.realm.models.ddp.RealmSpotlightRoom
;
import
hu.akarnokd.rxjava.interop.RxJavaInterop
;
public
class
RealmSpotlightRoomRepository
extends
RealmRepository
implements
SpotlightRoomRepository
{
private
final
String
hostname
;
public
RealmSpotlightRoomRepository
(
String
hostname
)
{
this
.
hostname
=
hostname
;
}
@Override
public
Flowable
<
List
<
SpotlightRoom
>>
getSuggestionsFor
(
String
name
,
SortDirection
direction
,
int
limit
)
{
return
Flowable
.
defer
(()
->
Flowable
.
using
(
()
->
new
Pair
<>(
RealmStore
.
getRealm
(
hostname
),
Looper
.
myLooper
()),
pair
->
RxJavaInterop
.
toV2Flowable
(
pair
.
first
.
where
(
RealmSpotlightRoom
.
class
)
.
like
(
RealmSpotlightRoom
.
Columns
.
NAME
,
"*"
+
name
+
"*"
,
Case
.
INSENSITIVE
)
.
beginGroup
()
.
equalTo
(
RealmSpotlightRoom
.
Columns
.
TYPE
,
RealmRoom
.
TYPE_CHANNEL
)
.
or
()
.
equalTo
(
RealmSpotlightRoom
.
Columns
.
TYPE
,
RealmRoom
.
TYPE_PRIVATE
)
.
endGroup
()
.
findAllSorted
(
RealmSpotlightRoom
.
Columns
.
NAME
,
direction
.
equals
(
SortDirection
.
ASC
)
?
Sort
.
ASCENDING
:
Sort
.
DESCENDING
)
.
asObservable
()),
pair
->
close
(
pair
.
first
,
pair
.
second
)
)
.
unsubscribeOn
(
AndroidSchedulers
.
from
(
Looper
.
myLooper
()))
.
filter
(
it
->
it
!=
null
&&
it
.
isLoaded
()
&&
it
.
isValid
())
.
map
(
realmSpotlightRooms
->
toList
(
safeSubList
(
realmSpotlightRooms
,
0
,
limit
))));
}
private
List
<
SpotlightRoom
>
toList
(
List
<
RealmSpotlightRoom
>
realmSpotlightRooms
)
{
int
total
=
realmSpotlightRooms
.
size
();
final
List
<
SpotlightRoom
>
spotlightRooms
=
new
ArrayList
<>(
total
);
for
(
int
i
=
0
;
i
<
total
;
i
++)
{
spotlightRooms
.
add
(
realmSpotlightRooms
.
get
(
i
).
asSpotlightRoom
());
}
return
spotlightRooms
;
}
}
persistence-realm/src/main/java/chat/rocket/persistence/realm/repositories/RealmSpotlightUserRepository.java
0 → 100644
View file @
825b0b9f
package
chat
.
rocket
.
persistence
.
realm
.
repositories
;
import
android.os.Looper
;
import
android.support.v4.util.Pair
;
import
io.reactivex.Flowable
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.realm.Case
;
import
io.realm.Sort
;
import
java.util.ArrayList
;
import
java.util.List
;
import
chat.rocket.core.SortDirection
;
import
chat.rocket.core.models.SpotlightUser
;
import
chat.rocket.core.repositories.SpotlightUserRepository
;
import
chat.rocket.persistence.realm.RealmStore
;
import
chat.rocket.persistence.realm.models.ddp.RealmSpotlightUser
;
import
hu.akarnokd.rxjava.interop.RxJavaInterop
;
public
class
RealmSpotlightUserRepository
extends
RealmRepository
implements
SpotlightUserRepository
{
private
final
String
hostname
;
public
RealmSpotlightUserRepository
(
String
hostname
)
{
this
.
hostname
=
hostname
;
}
@Override
public
Flowable
<
List
<
SpotlightUser
>>
getSuggestionsFor
(
String
name
,
SortDirection
direction
,
int
limit
)
{
return
Flowable
.
defer
(()
->
Flowable
.
using
(
()
->
new
Pair
<>(
RealmStore
.
getRealm
(
hostname
),
Looper
.
myLooper
()),
pair
->
RxJavaInterop
.
toV2Flowable
(
pair
.
first
.
where
(
RealmSpotlightUser
.
class
)
.
beginGroup
()
.
like
(
RealmSpotlightUser
.
Columns
.
USERNAME
,
"*"
+
name
+
"*"
,
Case
.
INSENSITIVE
)
.
isNull
(
RealmSpotlightUser
.
Columns
.
NAME
)
.
endGroup
()
.
or
()
.
beginGroup
()
.
like
(
RealmSpotlightUser
.
Columns
.
NAME
,
"*"
+
name
+
"*"
,
Case
.
INSENSITIVE
)
.
isNotNull
(
RealmSpotlightUser
.
Columns
.
USERNAME
)
.
endGroup
()
.
findAllSorted
(
RealmSpotlightUser
.
Columns
.
USERNAME
,
direction
.
equals
(
SortDirection
.
ASC
)
?
Sort
.
ASCENDING
:
Sort
.
DESCENDING
)
.
asObservable
()),
pair
->
close
(
pair
.
first
,
pair
.
second
)
)
.
unsubscribeOn
(
AndroidSchedulers
.
from
(
Looper
.
myLooper
()))
.
filter
(
it
->
it
!=
null
&&
it
.
isLoaded
()
&&
it
.
isValid
())
.
map
(
realmSpotlightUsers
->
toList
(
safeSubList
(
realmSpotlightUsers
,
0
,
limit
))));
}
private
List
<
SpotlightUser
>
toList
(
List
<
RealmSpotlightUser
>
realmSpotlightUsers
)
{
int
total
=
realmSpotlightUsers
.
size
();
final
List
<
SpotlightUser
>
spotlightUsers
=
new
ArrayList
<>(
total
);
for
(
int
i
=
0
;
i
<
total
;
i
++)
{
spotlightUsers
.
add
(
realmSpotlightUsers
.
get
(
i
).
asSpotlightUser
());
}
return
spotlightUsers
;
}
}
persistence-realm/src/main/java/chat/rocket/persistence/realm/repositories/RealmUserRepository.java
View file @
825b0b9f
...
...
@@ -5,8 +5,13 @@ import android.support.v4.util.Pair;
import
com.fernandocejas.arrow.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
;
...
...
@@ -43,4 +48,46 @@ public class RealmUserRepository extends RealmRepository implements UserReposito
return
Optional
.<
User
>
absent
();
}));
}
@Override
public
Flowable
<
List
<
User
>>
getSortedLikeName
(
String
name
,
SortDirection
direction
,
int
limit
)
{
return
Flowable
.
defer
(()
->
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
)
)
.
unsubscribeOn
(
AndroidSchedulers
.
from
(
Looper
.
myLooper
()))
.
filter
(
realmUsers
->
realmUsers
!=
null
&&
realmUsers
.
isLoaded
()
&&
realmUsers
.
isValid
())
.
map
(
realmUsers
->
toList
(
safeSubList
(
realmUsers
,
0
,
limit
))));
}
private
List
<
User
>
toList
(
RealmResults
<
RealmUser
>
realmUsers
)
{
int
total
=
realmUsers
.
size
();
final
List
<
User
>
userList
=
new
ArrayList
<>(
total
);
for
(
int
i
=
0
;
i
<
total
;
i
++)
{
userList
.
add
(
realmUsers
.
get
(
i
).
asUser
());
}
return
userList
;
}
private
List
<
User
>
toList
(
List
<
RealmUser
>
realmUsers
)
{
int
total
=
realmUsers
.
size
();
final
List
<
User
>
userList
=
new
ArrayList
<>(
total
);
for
(
int
i
=
0
;
i
<
total
;
i
++)
{
userList
.
add
(
realmUsers
.
get
(
i
).
asUser
());
}
return
userList
;
}
}
rocket-chat-android-widgets/build.gradle
View file @
825b0b9f
...
...
@@ -5,7 +5,7 @@ buildscript {
jcenter
()
}
dependencies
{
classpath
'com.android.tools.build:gradle:2.3.
0
'
classpath
'com.android.tools.build:gradle:2.3.
1
'
}
}
...
...
@@ -32,6 +32,7 @@ android {
ext
{
supportVersion
=
'25.2.0'
frescoVersion
=
'1.1.0'
rxbindingVersion
=
'2.0.0'
}
dependencies
{
...
...
@@ -39,6 +40,8 @@ dependencies {
compile
"com.android.support:support-annotations:$supportVersion"
compile
"com.android.support:appcompat-v7:$supportVersion"
compile
"com.android.support:recyclerview-v7:$supportVersion"
compile
"com.android.support:cardview-v7:$supportVersion"
compile
"com.android.support:support-v13:$supportVersion"
compile
"com.android.support:design:$supportVersion"
...
...
@@ -58,5 +61,9 @@ dependencies {
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
"org.mockito:mockito-core:2.7.19"
}
rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/helper/IconProvider.java
0 → 100644
View file @
825b0b9f
package
chat
.
rocket
.
android
.
widget
.
helper
;
import
android.support.annotation.StringRes
;
import
java.util.HashMap
;
import
chat.rocket.android.widget.R
;
public
class
IconProvider
{
private
static
HashMap
<
String
,
Integer
>
ICON_TABLE
=
new
HashMap
<
String
,
Integer
>()
{
{
put
(
"c"
,
R
.
string
.
fa_hashtag
);
put
(
"p"
,
R
.
string
.
fa_lock
);
put
(
"d"
,
R
.
string
.
fa_at
);
}
};
@StringRes
public
static
int
getIcon
(
String
type
)
{
if
(
ICON_TABLE
.
containsKey
(
type
))
{
return
ICON_TABLE
.
get
(
type
);
}
return
ICON_TABLE
.
get
(
"c"
);
}
}
rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/helper/UserStatusProvider.java
0 → 100644
View file @
825b0b9f
package
chat
.
rocket
.
android
.
widget
.
helper
;
import
android.support.annotation.DrawableRes
;
public
interface
UserStatusProvider
{
@DrawableRes
int
getStatusResId
(
String
status
);
}
rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/ImageKeyboardEditText.java
View file @
825b0b9f
package
chat
.
rocket
.
android
.
widget
.
message
;
import
android.annotation.TargetApi
;
import
android.content.Context
;
import
android.os.Build
;
import
android.os.Bundle
;
import
android.support.v13.view.inputmethod.EditorInfoCompat
;
import
android.support.v13.view.inputmethod.InputConnectionCompat
;
import
android.support.v13.view.inputmethod.InputContentInfoCompat
;
import
android.support.v7.widget.AppCompatEditText
;
import
android.util.AttributeSet
;
import
android.view.inputmethod.EditorInfo
;
import
android.view.inputmethod.InputConnection
;
import
android.widget.EditText
;
public
class
ImageKeyboardEditText
extends
EditText
{
public
class
ImageKeyboardEditText
extends
AppCompat
EditText
{
private
final
String
[]
mimeTypes
=
{
"image/gif"
};
...
...
@@ -43,12 +41,6 @@ public class ImageKeyboardEditText extends EditText {
super
(
context
,
attrs
,
defStyleAttr
);
}
@TargetApi
(
Build
.
VERSION_CODES
.
LOLLIPOP
)
public
ImageKeyboardEditText
(
Context
context
,
AttributeSet
attrs
,
int
defStyleAttr
,
int
defStyleRes
)
{
super
(
context
,
attrs
,
defStyleAttr
,
defStyleRes
);
}
@Override
public
InputConnection
onCreateInputConnection
(
EditorInfo
editorInfo
)
{
final
InputConnection
inputConnection
=
super
.
onCreateInputConnection
(
editorInfo
);
...
...
rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/MessageFormLayout.java
View file @
825b0b9f
...
...
@@ -12,6 +12,7 @@ import android.util.AttributeSet;
import
android.view.LayoutInflater
;
import
android.view.View
;
import
android.view.ViewGroup
;
import
android.widget.EditText
;
import
android.widget.LinearLayout
;
import
android.widget.TextView
;
...
...
@@ -115,6 +116,10 @@ public class MessageFormLayout extends LinearLayout {
addView
(
composer
);
}
public
EditText
getEditText
()
{
return
(
EditText
)
composer
.
findViewById
(
R
.
id
.
editor
);
}
public
void
setExtraActionSelectionClickListener
(
ExtraActionSelectionClickListener
extraActionSelectionClickListener
)
{
this
.
extraActionSelectionClickListener
=
extraActionSelectionClickListener
;
...
...
@@ -153,7 +158,8 @@ public class MessageFormLayout extends LinearLayout {
composer
.
findViewById
(
R
.
id
.
btn_submit
).
setEnabled
(
enabled
);
}
public
void
setEditTextContentListener
(
ImageKeyboardEditText
.
OnCommitContentListener
listener
)
{
public
void
setEditTextCommitContentListener
(
ImageKeyboardEditText
.
OnCommitContentListener
listener
)
{
this
.
listener
=
listener
;
}
...
...
rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/autocomplete/AutocompleteAdapter.java
0 → 100644
View file @
825b0b9f
package
chat
.
rocket
.
android
.
widget
.
message
.
autocomplete
;
import
android.support.v7.widget.RecyclerView
;
import
android.view.ViewGroup
;
import
java.util.ArrayList
;
import
java.util.List
;
public
abstract
class
AutocompleteAdapter
<
I
extends
AutocompleteItem
,
H
extends
AutocompleteViewHolder
<
I
>>
extends
RecyclerView
.
Adapter
<
H
>
{
private
static
final
int
TYPE_EMPTY
=
0
;
private
static
final
int
TYPE_ITEM
=
1
;
private
List
<
I
>
autocompleteItems
=
new
ArrayList
<>();
protected
AutocompleteViewHolder
.
OnClickListener
<
I
>
onClickListener
;
public
void
setAutocompleteItems
(
List
<
I
>
autocompleteItems
)
{
this
.
autocompleteItems
.
clear
();
this
.
autocompleteItems
.
addAll
(
autocompleteItems
);
notifyDataSetChanged
();
}
public
H
onCreateViewHolder
(
ViewGroup
parent
,
int
viewType
)
{
H
holder
=
getViewHolder
(
parent
);
if
(
viewType
==
TYPE_EMPTY
)
{
holder
.
showAsEmpty
();
}
return
holder
;
}
@Override
public
void
onBindViewHolder
(
H
holder
,
int
position
)
{
if
(
getItemViewType
(
position
)
==
TYPE_EMPTY
)
{
return
;
}
holder
.
bind
(
autocompleteItems
.
get
(
position
));
}
@Override
public
int
getItemCount
()
{
int
count
=
autocompleteItems
.
size
();
if
(
count
==
0
)
{
return
1
;
}
return
count
;
}
@Override
public
int
getItemViewType
(
int
position
)
{
if
(
autocompleteItems
.
size
()
==
0
)
{
return
TYPE_EMPTY
;
}
return
TYPE_ITEM
;
}
public
abstract
H
getViewHolder
(
ViewGroup
parent
);
public
void
setOnClickListener
(
AutocompleteViewHolder
.
OnClickListener
<
I
>
onClickListener
)
{
this
.
onClickListener
=
onClickListener
;
}
}
rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/autocomplete/AutocompleteItem.java
0 → 100644
View file @
825b0b9f
package
chat
.
rocket
.
android
.
widget
.
message
.
autocomplete
;
import
android.support.annotation.NonNull
;
public
interface
AutocompleteItem
{
@NonNull
String
getSuggestion
();
}
rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/autocomplete/AutocompleteManager.java
0 → 100644
View file @
825b0b9f
package
chat
.
rocket
.
android
.
widget
.
message
.
autocomplete
;
import
android.support.v7.widget.LinearLayoutManager
;
import
android.support.v7.widget.RecyclerView
;
import
android.util.TypedValue
;
import
android.view.LayoutInflater
;
import
android.view.View
;
import
android.view.ViewGroup
;
import
android.view.ViewTreeObserver
;
import
android.widget.EditText
;
import
android.widget.RelativeLayout
;
import
com.jakewharton.rxbinding2.widget.RxTextView
;
import
com.jakewharton.rxbinding2.widget.TextViewAfterTextChangeEvent
;
import
io.reactivex.android.schedulers.AndroidSchedulers
;
import
io.reactivex.annotations.NonNull
;
import
io.reactivex.disposables.CompositeDisposable
;
import
io.reactivex.disposables.Disposable
;
import
io.reactivex.functions.Consumer
;
import
io.reactivex.functions.Function
;
import
io.reactivex.internal.util.AppendOnlyLinkedArrayList
;
import
java.util.HashMap
;
import
java.util.Map
;
import
java.util.concurrent.TimeUnit
;
import
chat.rocket.android.widget.R
;
public
class
AutocompleteManager
{
private
final
Map
<
String
,
AutocompleteSource
>
autocompleteSourceMap
=
new
HashMap
<>();
private
AutocompleteSource
currentSource
;
private
Disposable
afterTextChangeDisposable
;
private
CompositeDisposable
sourceDisposable
=
new
CompositeDisposable
();
private
EditText
editText
;
private
String
text
;
private
int
fromIndex
;
private
int
toIndex
;
private
final
View
contentHolder
;
private
final
RecyclerView
recyclerView
;
private
float
contentHolderInitialY
;
private
final
float
yOffset
;
private
final
AutocompleteSource
.
OnAutocompleteSelected
onAutocompleteSelected
=
new
AutocompleteSource
.
OnAutocompleteSelected
()
{
@Override
public
void
onSelected
(
String
autocompleteSuggestion
)
{
replaceSelected
(
autocompleteSuggestion
);
}
};
public
AutocompleteManager
(
ViewGroup
parent
)
{
contentHolder
=
LayoutInflater
.
from
(
parent
.
getContext
()).
inflate
(
R
.
layout
.
autocomplete_box
,
parent
,
false
);
contentHolder
.
setVisibility
(
View
.
GONE
);
recyclerView
=
(
RecyclerView
)
contentHolder
.
findViewById
(
R
.
id
.
autocomplete_list
);
recyclerView
.
setLayoutManager
(
new
LinearLayoutManager
(
parent
.
getContext
()));
parent
.
addView
(
contentHolder
);
yOffset
=
TypedValue
.
applyDimension
(
TypedValue
.
COMPLEX_UNIT_DIP
,
32
,
contentHolder
.
getContext
().
getResources
().
getDisplayMetrics
()
);
}
public
void
registerSource
(
AutocompleteSource
autocompleteSource
)
{
autocompleteSourceMap
.
put
(
autocompleteSource
.
getTrigger
(),
autocompleteSource
);
}
public
void
bindTo
(
EditText
editText
,
View
anchor
)
{
this
.
editText
=
editText
;
if
(
contentHolder
.
getLayoutParams
()
instanceof
RelativeLayout
.
LayoutParams
)
{
RelativeLayout
.
LayoutParams
layoutParams
=
(
RelativeLayout
.
LayoutParams
)
contentHolder
.
getLayoutParams
();
layoutParams
.
addRule
(
RelativeLayout
.
ABOVE
,
anchor
.
getId
());
contentHolder
.
getViewTreeObserver
().
addOnGlobalLayoutListener
(
new
ViewTreeObserver
.
OnGlobalLayoutListener
()
{
@Override
public
void
onGlobalLayout
()
{
contentHolderInitialY
=
contentHolder
.
getY
();
animateHide
();
contentHolder
.
getViewTreeObserver
().
removeOnGlobalLayoutListener
(
this
);
}
});
}
afterTextChangeDisposable
=
RxTextView
.
afterTextChangeEvents
(
editText
)
.
debounce
(
300
,
TimeUnit
.
MILLISECONDS
)
.
filter
(
new
AppendOnlyLinkedArrayList
.
NonThrowingPredicate
<
TextViewAfterTextChangeEvent
>()
{
@Override
public
boolean
test
(
TextViewAfterTextChangeEvent
textViewAfterTextChangeEvent
)
{
return
textViewAfterTextChangeEvent
.
editable
()
!=
null
;
}
})
.
map
(
new
Function
<
TextViewAfterTextChangeEvent
,
String
>()
{
@Override
public
String
apply
(
@NonNull
TextViewAfterTextChangeEvent
textViewAfterTextChangeEvent
)
throws
Exception
{
//noinspection ConstantConditions
return
textViewAfterTextChangeEvent
.
editable
().
toString
();
}
})
.
observeOn
(
AndroidSchedulers
.
mainThread
())
.
doOnNext
(
new
Consumer
<
String
>()
{
@Override
public
void
accept
(
@NonNull
String
s
)
throws
Exception
{
// let's do stateful things
tryToAutocomplete
(
s
);
}
})
.
subscribe
();
}
public
void
dispose
()
{
if
(
afterTextChangeDisposable
!=
null
)
{
afterTextChangeDisposable
.
dispose
();
afterTextChangeDisposable
=
null
;
}
editText
=
null
;
cleanState
();
}
private
void
tryToAutocomplete
(
String
text
)
{
if
(
editText
==
null
)
{
cleanState
();
return
;
}
final
int
selectionStart
=
editText
.
getSelectionStart
();
final
int
selectionEnd
=
editText
.
getSelectionEnd
();
if
(
selectionStart
!=
selectionEnd
)
{
// selecting text
cleanState
();
return
;
}
final
String
toCompleteText
=
getToCompleteText
(
text
,
selectionStart
);
final
AutocompleteSource
source
=
getSource
(
toCompleteText
);
if
(
source
==
null
)
{
cleanState
();
return
;
}
// render and stuff
if
(
source
!=
currentSource
)
{
cleanState
();
currentSource
=
source
;
// set adapter on something
recyclerView
.
setAdapter
(
currentSource
.
getAdapter
());
currentSource
.
setOnAutocompleteSelected
(
onAutocompleteSelected
);
}
this
.
text
=
text
;
animateShow
();
sourceDisposable
.
clear
();
sourceDisposable
.
add
(
currentSource
.
loadList
(
toCompleteText
));
}
private
void
cleanState
()
{
animateHide
();
sourceDisposable
.
clear
();
text
=
null
;
if
(
currentSource
!=
null
)
{
currentSource
.
dispose
();
currentSource
=
null
;
}
}
private
String
getToCompleteText
(
String
text
,
int
cursorPosition
)
{
if
(
text
==
null
||
text
.
length
()
==
0
||
cursorPosition
<
0
||
cursorPosition
>
text
.
length
())
{
return
""
;
}
final
String
[]
textParts
=
text
.
split
(
" "
);
int
currentPos
=
0
;
for
(
String
textPart
:
textParts
)
{
int
currentLength
=
currentPos
+
textPart
.
length
();
if
(
cursorPosition
>=
currentPos
&&
cursorPosition
<=
currentLength
)
{
fromIndex
=
currentPos
;
toIndex
=
cursorPosition
;
return
textPart
.
substring
(
0
,
cursorPosition
-
currentPos
);
}
currentPos
=
currentLength
+
1
;
}
return
""
;
}
private
AutocompleteSource
getSource
(
String
toCompleteText
)
{
if
(
toCompleteText
==
null
||
toCompleteText
.
length
()
==
0
)
{
return
null
;
}
final
String
trigger
=
toCompleteText
.
substring
(
0
,
1
);
return
autocompleteSourceMap
.
get
(
trigger
);
}
private
void
replaceSelected
(
String
autocompleteSuggestion
)
{
final
String
preText
=
text
.
substring
(
0
,
fromIndex
);
final
String
postText
=
text
.
substring
(
toIndex
);
StringBuilder
stringBuilder
=
new
StringBuilder
(
text
.
length
()
+
autocompleteSuggestion
.
length
());
stringBuilder
.
append
(
preText
)
.
append
(
autocompleteSuggestion
)
.
append
(
' '
);
final
int
selectionPos
=
stringBuilder
.
length
();
stringBuilder
.
append
(
postText
);
editText
.
setText
(
stringBuilder
.
toString
());
editText
.
setSelection
(
selectionPos
);
}
private
void
animateHide
()
{
contentHolder
.
animate
().
cancel
();
contentHolder
.
animate
()
.
alpha
(
0
)
.
translationY
(
contentHolderInitialY
+
yOffset
)
.
setDuration
(
150
)
.
withEndAction
(
new
Runnable
()
{
@Override
public
void
run
()
{
contentHolder
.
setVisibility
(
View
.
GONE
);
}
});
}
private
void
animateShow
()
{
contentHolder
.
animate
().
cancel
();
contentHolder
.
animate
()
.
alpha
(
1
)
.
translationY
(
contentHolderInitialY
)
.
setDuration
(
150
)
.
withStartAction
(
new
Runnable
()
{
@Override
public
void
run
()
{
contentHolder
.
setVisibility
(
View
.
VISIBLE
);
}
});
}
}
rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/autocomplete/AutocompleteSource.java
0 → 100644
View file @
825b0b9f
package
chat
.
rocket
.
android
.
widget
.
message
.
autocomplete
;
import
android.support.annotation.NonNull
;
import
io.reactivex.disposables.Disposable
;
public
abstract
class
AutocompleteSource
<
A
extends
AutocompleteAdapter
,
I
extends
AutocompleteItem
>
{
protected
A
adapter
;
private
AutocompleteSource
.
OnAutocompleteSelected
autocompleteSelected
;
private
AutocompleteViewHolder
.
OnClickListener
autocompleteListener
=
new
AutocompleteViewHolder
.
OnClickListener
<
I
>()
{
@Override
public
void
onClick
(
I
autocompleteItem
)
{
if
(
autocompleteSelected
!=
null
)
{
autocompleteSelected
.
onSelected
(
getAutocompleteSuggestion
(
autocompleteItem
));
}
}
};
@NonNull
public
abstract
String
getTrigger
();
@NonNull
public
A
getAdapter
()
{
if
(
adapter
==
null
)
{
adapter
=
createAdapter
();
adapter
.
setOnClickListener
(
autocompleteListener
);
}
return
adapter
;
}
@NonNull
public
abstract
Disposable
loadList
(
String
text
);
public
abstract
void
dispose
();
public
void
setOnAutocompleteSelected
(
AutocompleteSource
.
OnAutocompleteSelected
autocompleteSelected
)
{
this
.
autocompleteSelected
=
autocompleteSelected
;
}
protected
abstract
A
createAdapter
();
protected
abstract
String
getAutocompleteSuggestion
(
I
autocompleteItem
);
public
interface
OnAutocompleteSelected
{
void
onSelected
(
String
autocompleteSuggestion
);
}
}
rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/autocomplete/AutocompleteViewHolder.java
0 → 100644
View file @
825b0b9f
package
chat
.
rocket
.
android
.
widget
.
message
.
autocomplete
;
import
android.support.v7.widget.RecyclerView
;
import
android.view.View
;
public
abstract
class
AutocompleteViewHolder
<
I
extends
AutocompleteItem
>
extends
RecyclerView
.
ViewHolder
{
public
AutocompleteViewHolder
(
View
itemView
)
{
super
(
itemView
);
}
public
abstract
void
bind
(
I
autocompleteItem
);
public
abstract
void
showAsEmpty
();
public
interface
OnClickListener
<
I
extends
AutocompleteItem
>
{
void
onClick
(
I
autocompleteItem
);
}
}
rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/autocomplete/channel/ChannelAdapter.java
0 → 100644
View file @
825b0b9f
package
chat
.
rocket
.
android
.
widget
.
message
.
autocomplete
.
channel
;
import
android.view.LayoutInflater
;
import
android.view.View
;
import
android.view.ViewGroup
;
import
chat.rocket.android.widget.R
;
import
chat.rocket.android.widget.message.autocomplete.AutocompleteAdapter
;
public
class
ChannelAdapter
extends
AutocompleteAdapter
<
ChannelItem
,
ChannelViewHolder
>
{
@Override
public
ChannelViewHolder
getViewHolder
(
ViewGroup
parent
)
{
View
view
=
LayoutInflater
.
from
(
parent
.
getContext
())
.
inflate
(
R
.
layout
.
autocomplete_channel_view
,
parent
,
false
);
return
new
ChannelViewHolder
(
view
,
onClickListener
);
}
}
rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/autocomplete/channel/ChannelItem.java
0 → 100644
View file @
825b0b9f
package
chat
.
rocket
.
android
.
widget
.
message
.
autocomplete
.
channel
;
import
android.support.annotation.NonNull
;
import
android.support.annotation.StringRes
;
import
chat.rocket.android.widget.helper.IconProvider
;
import
chat.rocket.android.widget.message.autocomplete.AutocompleteItem
;
import
chat.rocket.core.models.SpotlightRoom
;
public
class
ChannelItem
implements
AutocompleteItem
{
private
final
SpotlightRoom
spotlightRoom
;
public
ChannelItem
(
@NonNull
SpotlightRoom
spotlightRoom
)
{
this
.
spotlightRoom
=
spotlightRoom
;
}
@NonNull
@Override
public
String
getSuggestion
()
{
return
spotlightRoom
.
getName
();
}
@StringRes
public
int
getIcon
()
{
return
IconProvider
.
getIcon
(
spotlightRoom
.
getType
());
}
}
rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/autocomplete/channel/ChannelSource.java
0 → 100644
View file @
825b0b9f
package
chat
.
rocket
.
android
.
widget
.
message
.
autocomplete
.
channel
;
import
android.support.annotation.NonNull
;
import
io.reactivex.Flowable
;
import
io.reactivex.Scheduler
;
import
io.reactivex.disposables.Disposable
;
import
io.reactivex.functions.Consumer
;
import
io.reactivex.functions.Function
;
import
org.reactivestreams.Publisher
;
import
java.util.ArrayList
;
import
java.util.List
;
import
chat.rocket.android.widget.message.autocomplete.AutocompleteSource
;
import
chat.rocket.core.interactors.AutocompleteChannelInteractor
;
import
chat.rocket.core.models.SpotlightRoom
;
public
class
ChannelSource
extends
AutocompleteSource
<
ChannelAdapter
,
ChannelItem
>
{
private
final
AutocompleteChannelInteractor
autocompleteChannelInteractor
;
private
final
Scheduler
bgScheduler
;
private
final
Scheduler
fgScheduler
;
public
ChannelSource
(
AutocompleteChannelInteractor
autocompleteChannelInteractor
,
Scheduler
bgScheduler
,
Scheduler
fgScheduler
)
{
this
.
autocompleteChannelInteractor
=
autocompleteChannelInteractor
;
this
.
bgScheduler
=
bgScheduler
;
this
.
fgScheduler
=
fgScheduler
;
}
@NonNull
@Override
public
String
getTrigger
()
{
return
"#"
;
}
@NonNull
@Override
public
Disposable
loadList
(
String
text
)
{
return
Flowable
.
just
(
text
)
.
map
(
new
Function
<
String
,
String
>()
{
@Override
public
String
apply
(
@io
.
reactivex
.
annotations
.
NonNull
String
s
)
throws
Exception
{
return
s
.
substring
(
1
);
}
})
.
flatMap
(
new
Function
<
String
,
Publisher
<
List
<
SpotlightRoom
>>>()
{
@Override
public
Publisher
<
List
<
SpotlightRoom
>>
apply
(
@io
.
reactivex
.
annotations
.
NonNull
String
s
)
throws
Exception
{
return
autocompleteChannelInteractor
.
getSuggestionsFor
(
s
);
}
})
.
distinctUntilChanged
()
.
map
(
new
Function
<
List
<
SpotlightRoom
>,
List
<
ChannelItem
>>()
{
@Override
public
List
<
ChannelItem
>
apply
(
@io
.
reactivex
.
annotations
.
NonNull
List
<
SpotlightRoom
>
spotlightRooms
)
throws
Exception
{
return
toChannelItemList
(
spotlightRooms
);
}
})
.
subscribeOn
(
bgScheduler
)
.
observeOn
(
fgScheduler
)
.
subscribe
(
new
Consumer
<
List
<
ChannelItem
>>()
{
@Override
public
void
accept
(
@io
.
reactivex
.
annotations
.
NonNull
List
<
ChannelItem
>
channelItems
)
throws
Exception
{
if
(
adapter
!=
null
)
{
adapter
.
setAutocompleteItems
(
channelItems
);
}
}
},
new
Consumer
<
Throwable
>()
{
@Override
public
void
accept
(
@io
.
reactivex
.
annotations
.
NonNull
Throwable
throwable
)
throws
Exception
{
}
}
);
}
@Override
public
void
dispose
()
{
adapter
=
null
;
}
@Override
protected
ChannelAdapter
createAdapter
()
{
return
new
ChannelAdapter
();
}
@Override
protected
String
getAutocompleteSuggestion
(
ChannelItem
autocompleteItem
)
{
return
getTrigger
()
+
autocompleteItem
.
getSuggestion
();
}
private
List
<
ChannelItem
>
toChannelItemList
(
List
<
SpotlightRoom
>
spotlightRooms
)
{
int
size
=
spotlightRooms
.
size
();
List
<
ChannelItem
>
channelItems
=
new
ArrayList
<>(
size
);
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
channelItems
.
add
(
new
ChannelItem
(
spotlightRooms
.
get
(
i
)));
}
return
channelItems
;
}
}
rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/autocomplete/channel/ChannelViewHolder.java
0 → 100644
View file @
825b0b9f
package
chat
.
rocket
.
android
.
widget
.
message
.
autocomplete
.
channel
;
import
android.view.View
;
import
android.widget.TextView
;
import
chat.rocket.android.widget.R
;
import
chat.rocket.android.widget.message.autocomplete.AutocompleteViewHolder
;
public
class
ChannelViewHolder
extends
AutocompleteViewHolder
<
ChannelItem
>
{
private
final
TextView
titleTextView
;
private
final
TextView
iconTextView
;
public
ChannelViewHolder
(
View
itemView
,
final
AutocompleteViewHolder
.
OnClickListener
<
ChannelItem
>
onClickListener
)
{
super
(
itemView
);
titleTextView
=
(
TextView
)
itemView
.
findViewById
(
R
.
id
.
title
);
iconTextView
=
(
TextView
)
itemView
.
findViewById
(
R
.
id
.
icon
);
itemView
.
setOnClickListener
(
new
View
.
OnClickListener
()
{
@Override
public
void
onClick
(
View
v
)
{
if
(
onClickListener
!=
null
)
{
onClickListener
.
onClick
((
ChannelItem
)
v
.
getTag
());
}
}
});
}
@Override
public
void
bind
(
ChannelItem
channelItem
)
{
itemView
.
setTag
(
channelItem
);
if
(
titleTextView
!=
null
)
{
titleTextView
.
setText
(
channelItem
.
getSuggestion
());
}
if
(
iconTextView
!=
null
)
{
iconTextView
.
setText
(
channelItem
.
getIcon
());
}
}
@Override
public
void
showAsEmpty
()
{
iconTextView
.
setVisibility
(
View
.
GONE
);
titleTextView
.
setText
(
R
.
string
.
no_channel_found
);
}
}
rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/autocomplete/user/UserAdapter.java
0 → 100644
View file @
825b0b9f
package
chat
.
rocket
.
android
.
widget
.
message
.
autocomplete
.
user
;
import
android.view.LayoutInflater
;
import
android.view.View
;
import
android.view.ViewGroup
;
import
chat.rocket.android.widget.R
;
import
chat.rocket.android.widget.message.autocomplete.AutocompleteAdapter
;
public
class
UserAdapter
extends
AutocompleteAdapter
<
UserItem
,
UserViewHolder
>
{
@Override
public
UserViewHolder
getViewHolder
(
ViewGroup
parent
)
{
View
view
=
LayoutInflater
.
from
(
parent
.
getContext
())
.
inflate
(
R
.
layout
.
autocomplete_user_view
,
parent
,
false
);
return
new
UserViewHolder
(
view
,
onClickListener
);
}
}
rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/autocomplete/user/UserItem.java
0 → 100644
View file @
825b0b9f
package
chat
.
rocket
.
android
.
widget
.
message
.
autocomplete
.
user
;
import
android.support.annotation.DrawableRes
;
import
android.support.annotation.NonNull
;
import
chat.rocket.android.widget.AbsoluteUrl
;
import
chat.rocket.android.widget.helper.UserStatusProvider
;
import
chat.rocket.android.widget.message.autocomplete.AutocompleteItem
;
import
chat.rocket.core.models.SpotlightUser
;
public
class
UserItem
implements
AutocompleteItem
{
private
final
SpotlightUser
user
;
private
final
AbsoluteUrl
absoluteUrl
;
private
final
UserStatusProvider
userStatusProvider
;
public
UserItem
(
@NonNull
SpotlightUser
user
,
AbsoluteUrl
absoluteUrl
,
UserStatusProvider
userStatusProvider
)
{
this
.
user
=
user
;
this
.
absoluteUrl
=
absoluteUrl
;
this
.
userStatusProvider
=
userStatusProvider
;
}
@NonNull
@Override
public
String
getSuggestion
()
{
//noinspection ConstantConditions
return
user
.
getUsername
();
}
public
AbsoluteUrl
getAbsoluteUrl
()
{
return
absoluteUrl
;
}
@DrawableRes
public
int
getStatusResId
()
{
return
userStatusProvider
.
getStatusResId
(
user
.
getStatus
());
}
}
rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/autocomplete/user/UserSource.java
0 → 100644
View file @
825b0b9f
package
chat
.
rocket
.
android
.
widget
.
message
.
autocomplete
.
user
;
import
android.support.annotation.NonNull
;
import
io.reactivex.Flowable
;
import
io.reactivex.Scheduler
;
import
io.reactivex.disposables.Disposable
;
import
io.reactivex.functions.Consumer
;
import
io.reactivex.functions.Function
;
import
org.reactivestreams.Publisher
;
import
java.util.ArrayList
;
import
java.util.List
;
import
chat.rocket.android.widget.AbsoluteUrl
;
import
chat.rocket.android.widget.helper.UserStatusProvider
;
import
chat.rocket.android.widget.message.autocomplete.AutocompleteSource
;
import
chat.rocket.core.interactors.AutocompleteUserInteractor
;
import
chat.rocket.core.models.SpotlightUser
;
public
class
UserSource
extends
AutocompleteSource
<
UserAdapter
,
UserItem
>
{
private
final
AutocompleteUserInteractor
autocompleteUserInteractor
;
private
final
AbsoluteUrl
absoluteUrl
;
private
final
UserStatusProvider
userStatusProvider
;
private
final
Scheduler
bgScheduler
;
private
final
Scheduler
fgScheduler
;
public
UserSource
(
AutocompleteUserInteractor
autocompleteUserInteractor
,
AbsoluteUrl
absoluteUrl
,
UserStatusProvider
userStatusProvider
,
Scheduler
bgScheduler
,
Scheduler
fgScheduler
)
{
this
.
autocompleteUserInteractor
=
autocompleteUserInteractor
;
this
.
absoluteUrl
=
absoluteUrl
;
this
.
userStatusProvider
=
userStatusProvider
;
this
.
bgScheduler
=
bgScheduler
;
this
.
fgScheduler
=
fgScheduler
;
}
@NonNull
@Override
public
String
getTrigger
()
{
return
"@"
;
}
@NonNull
@Override
public
Disposable
loadList
(
String
text
)
{
return
Flowable
.
just
(
text
)
.
map
(
new
Function
<
String
,
String
>()
{
@Override
public
String
apply
(
@io
.
reactivex
.
annotations
.
NonNull
String
s
)
throws
Exception
{
return
s
.
substring
(
1
);
}
})
.
flatMap
(
new
Function
<
String
,
Publisher
<
List
<
SpotlightUser
>>>()
{
@Override
public
Publisher
<
List
<
SpotlightUser
>>
apply
(
@io
.
reactivex
.
annotations
.
NonNull
String
s
)
throws
Exception
{
return
autocompleteUserInteractor
.
getSuggestionsFor
(
s
);
}
})
.
distinctUntilChanged
()
.
map
(
new
Function
<
List
<
SpotlightUser
>,
List
<
UserItem
>>()
{
@Override
public
List
<
UserItem
>
apply
(
@io
.
reactivex
.
annotations
.
NonNull
List
<
SpotlightUser
>
users
)
throws
Exception
{
return
toUserItemList
(
users
);
}
})
.
subscribeOn
(
bgScheduler
)
.
observeOn
(
fgScheduler
)
.
subscribe
(
new
Consumer
<
List
<
UserItem
>>()
{
@Override
public
void
accept
(
@io
.
reactivex
.
annotations
.
NonNull
List
<
UserItem
>
userItems
)
throws
Exception
{
if
(
adapter
!=
null
)
{
adapter
.
setAutocompleteItems
(
userItems
);
}
}
},
new
Consumer
<
Throwable
>()
{
@Override
public
void
accept
(
@io
.
reactivex
.
annotations
.
NonNull
Throwable
throwable
)
throws
Exception
{
}
}
);
}
@Override
public
void
dispose
()
{
adapter
=
null
;
}
@Override
protected
UserAdapter
createAdapter
()
{
return
new
UserAdapter
();
}
@Override
protected
String
getAutocompleteSuggestion
(
UserItem
autocompleteItem
)
{
return
getTrigger
()
+
autocompleteItem
.
getSuggestion
();
}
private
List
<
UserItem
>
toUserItemList
(
List
<
SpotlightUser
>
users
)
{
int
size
=
users
.
size
();
List
<
UserItem
>
userItems
=
new
ArrayList
<>(
size
);
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
userItems
.
add
(
new
UserItem
(
users
.
get
(
i
),
absoluteUrl
,
userStatusProvider
));
}
return
userItems
;
}
}
rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/autocomplete/user/UserViewHolder.java
0 → 100644
View file @
825b0b9f
package
chat
.
rocket
.
android
.
widget
.
message
.
autocomplete
.
user
;
import
android.content.Context
;
import
android.graphics.Typeface
;
import
android.graphics.drawable.Drawable
;
import
android.text.TextUtils
;
import
android.view.View
;
import
android.widget.ImageView
;
import
android.widget.TextView
;
import
com.amulyakhare.textdrawable.TextDrawable
;
import
java.io.UnsupportedEncodingException
;
import
java.net.URLEncoder
;
import
chat.rocket.android.widget.AbsoluteUrl
;
import
chat.rocket.android.widget.R
;
import
chat.rocket.android.widget.RocketChatAvatar
;
import
chat.rocket.android.widget.message.autocomplete.AutocompleteViewHolder
;
public
class
UserViewHolder
extends
AutocompleteViewHolder
<
UserItem
>
{
private
static
final
int
[]
COLORS
=
new
int
[]{
0xFFF44336
,
0xFFE91E63
,
0xFF9C27B0
,
0xFF673AB7
,
0xFF3F51B5
,
0xFF2196F3
,
0xFF03A9F4
,
0xFF00BCD4
,
0xFF009688
,
0xFF4CAF50
,
0xFF8BC34A
,
0xFFCDDC39
,
0xFFFFC107
,
0xFFFF9800
,
0xFFFF5722
,
0xFF795548
,
0xFF9E9E9E
,
0xFF607D8B
};
private
final
TextView
titleTextView
;
private
final
RocketChatAvatar
avatar
;
private
final
ImageView
status
;
public
UserViewHolder
(
View
itemView
,
final
AutocompleteViewHolder
.
OnClickListener
<
UserItem
>
onClickListener
)
{
super
(
itemView
);
titleTextView
=
(
TextView
)
itemView
.
findViewById
(
R
.
id
.
title
);
avatar
=
(
RocketChatAvatar
)
itemView
.
findViewById
(
R
.
id
.
avatar
);
status
=
(
ImageView
)
itemView
.
findViewById
(
R
.
id
.
status
);
itemView
.
setOnClickListener
(
new
View
.
OnClickListener
()
{
@Override
public
void
onClick
(
View
v
)
{
if
(
onClickListener
!=
null
)
{
onClickListener
.
onClick
((
UserItem
)
v
.
getTag
());
}
}
});
}
@Override
public
void
bind
(
UserItem
userItem
)
{
itemView
.
setTag
(
userItem
);
final
String
suggestion
=
userItem
.
getSuggestion
();
if
(
titleTextView
!=
null
)
{
titleTextView
.
setText
(
suggestion
);
}
if
(
avatar
!=
null
)
{
avatar
.
loadImage
(
getImageUrl
(
suggestion
,
userItem
.
getAbsoluteUrl
()),
getTextDrawable
(
itemView
.
getContext
(),
suggestion
)
);
}
if
(
status
!=
null
)
{
status
.
setImageResource
(
userItem
.
getStatusResId
());
}
}
@Override
public
void
showAsEmpty
()
{
status
.
setVisibility
(
View
.
GONE
);
avatar
.
setVisibility
(
View
.
GONE
);
titleTextView
.
setText
(
R
.
string
.
no_user_found
);
}
private
String
getImageUrl
(
String
username
,
AbsoluteUrl
absoluteUrl
)
{
//from Rocket.Chat:packages/rocketchat-ui/lib/avatar.coffee
//REMARK! this is often SVG image! (see: Rocket.Chat:server/startup/avatar.coffee)
try
{
final
String
avatarUrl
=
"/avatar/"
+
URLEncoder
.
encode
(
username
,
"UTF-8"
)
+
".jpg"
;
if
(
absoluteUrl
==
null
)
{
return
avatarUrl
;
}
return
absoluteUrl
.
from
(
avatarUrl
);
}
catch
(
UnsupportedEncodingException
exception
)
{
return
null
;
}
}
private
Drawable
getTextDrawable
(
Context
context
,
String
username
)
{
if
(
username
==
null
)
{
return
null
;
}
int
round
=
(
int
)
(
4
*
context
.
getResources
().
getDisplayMetrics
().
density
);
return
TextDrawable
.
builder
()
.
beginConfig
()
.
useFont
(
Typeface
.
SANS_SERIF
)
.
endConfig
()
.
buildRoundRect
(
getInitialsForUser
(
username
),
getColorForUser
(
username
),
round
);
}
private
int
getColorForUser
(
String
username
)
{
return
COLORS
[
username
.
length
()
%
COLORS
.
length
];
}
private
String
getInitialsForUser
(
String
username
)
{
String
name
=
username
.
replaceAll
(
"[^A-Za-z0-9]"
,
"."
)
.
replaceAll
(
"\\.+"
,
"."
)
.
replaceAll
(
"(^\\.)|(\\.$)"
,
""
);
String
[]
initials
=
name
.
split
(
"\\."
);
if
(
initials
.
length
>=
2
)
{
return
(
firstChar
(
initials
[
0
])
+
firstChar
(
initials
[
initials
.
length
-
1
])).
toUpperCase
();
}
else
{
String
name2
=
name
.
replaceAll
(
"[^A-Za-z0-9]"
,
""
);
return
(
name2
.
length
()
<
2
)
?
name2
:
name2
.
substring
(
0
,
2
).
toUpperCase
();
}
}
private
static
String
firstChar
(
String
str
)
{
return
TextUtils
.
isEmpty
(
str
)
?
""
:
str
.
substring
(
0
,
1
);
}
}
rocket-chat-android-widgets/src/main/res/drawable/autocomplete_background.xml
0 → 100644
View file @
825b0b9f
<?xml version="1.0" encoding="utf-8"?>
<layer-list
xmlns:android=
"http://schemas.android.com/apk/res/android"
>
<item>
<shape
android:shape=
"rectangle"
>
<solid
android:color=
"@android:color/darker_gray"
/>
</shape>
</item>
<item
android:bottom=
"1dp"
>
<shape
android:shape=
"rectangle"
>
<solid
android:color=
"@android:color/white"
/>
</shape>
</item>
</layer-list>
\ No newline at end of file
rocket-chat-android-widgets/src/main/res/layout/autocomplete_box.xml
0 → 100644
View file @
825b0b9f
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:app=
"http://schemas.android.com/apk/res-auto"
android:orientation=
"vertical"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_marginRight=
"8dp"
android:layout_marginLeft=
"8dp"
android:layout_marginBottom=
"-8dp"
app:cardCornerRadius=
"4dp"
app:contentPadding=
"4dp"
>
<android.support.v7.widget.RecyclerView
android:id=
"@+id/autocomplete_list"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
/>
</android.support.v7.widget.CardView>
\ No newline at end of file
rocket-chat-android-widgets/src/main/res/layout/autocomplete_channel_view.xml
0 → 100644
View file @
825b0b9f
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:tools=
"http://schemas.android.com/tools"
android:orientation=
"horizontal"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:background=
"@android:color/white"
android:gravity=
"center_vertical"
android:paddingLeft=
"16dp"
android:paddingRight=
"16dp"
android:paddingTop=
"8dp"
android:paddingBottom=
"8dp"
>
<io.github.yusukeiwaki.android.widget.FontAwesomeTextView
android:id=
"@+id/icon"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_gravity=
"center"
android:layout_marginEnd=
"8dp"
android:layout_marginRight=
"8dp"
tools:text=
"#"
/>
<TextView
android:id=
"@+id/title"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
tools:text=
"YOLO"
/>
</LinearLayout>
\ No newline at end of file
rocket-chat-android-widgets/src/main/res/layout/autocomplete_user_view.xml
0 → 100644
View file @
825b0b9f
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:tools=
"http://schemas.android.com/tools"
android:orientation=
"horizontal"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:background=
"@android:color/white"
android:gravity=
"center_vertical"
android:paddingLeft=
"16dp"
android:paddingRight=
"16dp"
android:paddingTop=
"8dp"
android:paddingBottom=
"8dp"
>
<ImageView
android:id=
"@+id/status"
android:layout_width=
"8dp"
android:layout_height=
"8dp"
android:layout_marginEnd=
"8dp"
android:layout_marginRight=
"8dp"
/>
<chat.rocket.android.widget.RocketChatAvatar
android:id=
"@+id/avatar"
android:layout_width=
"16dp"
android:layout_height=
"16dp"
android:layout_marginEnd=
"8dp"
android:layout_marginRight=
"8dp"
/>
<TextView
android:id=
"@+id/title"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
tools:text=
"YOLO"
/>
</LinearLayout>
\ No newline at end of file
rocket-chat-android-widgets/src/main/res/values/strings.xml
View file @
825b0b9f
...
...
@@ -2,4 +2,6 @@
<resources>
<string
name=
"message_composer_message_hint"
>
Message
</string>
<string
name=
"click_to_load"
>
Click to load
</string>
<string
name=
"no_channel_found"
>
No channel found
</string>
<string
name=
"no_user_found"
>
No user found
</string>
</resources>
\ No newline at end of file
rocket-chat-core/build.gradle
View file @
825b0b9f
plugins
{
id
"net.ltgt.apt"
version
"0.9"
id
"me.tatarka.retrolambda"
version
"3.5.0"
id
"org.jetbrains.kotlin.jvm"
version
"1.1.1"
}
apply
plugin:
'idea'
...
...
@@ -9,6 +8,8 @@ apply plugin: 'java'
dependencies
{
compile
fileTree
(
dir:
'libs'
,
include:
[
'*.jar'
])
compile
'org.jetbrains.kotlin:kotlin-stdlib-jre7:1.1.1'
compile
'com.google.code.findbugs:jsr305:3.0.1'
compile
'io.reactivex.rxjava2:rxjava:2.0.6'
...
...
@@ -16,9 +17,12 @@ dependencies {
compile
'com.fernandocejas:arrow:1.0.0'
compile
'com.google.auto.value:auto-value:1.3'
apt
'com.google.auto.value:auto-value:1.3'
apt
'com.gabrielittner.auto.value:auto-value-with:1.0.0'
kapt
'com.google.auto.value:auto-value:1.3'
kapt
'com.gabrielittner.auto.value:auto-value-with:1.0.0'
testCompile
'junit:junit:4.12'
testCompile
"org.mockito:mockito-core:2.7.19"
}
sourceCompatibility
=
"1.
8
"
targetCompatibility
=
"1.
8
"
sourceCompatibility
=
"1.
7
"
targetCompatibility
=
"1.
7
"
rocket-chat-core/src/main/java/chat/rocket/core/SortDirection.java
0 → 100644
View file @
825b0b9f
package
chat
.
rocket
.
core
;
public
enum
SortDirection
{
ASC
,
DESC
}
rocket-chat-core/src/main/java/chat/rocket/core/interactors/AutocompleteChannelInteractor.kt
0 → 100644
View file @
825b0b9f
package
chat.rocket.core.interactors
import
io.reactivex.Flowable
import
java.util.ArrayList
import
chat.rocket.core.SortDirection
import
chat.rocket.core.models.Room
import
chat.rocket.core.models.SpotlightRoom
import
chat.rocket.core.repositories.RoomRepository
import
chat.rocket.core.repositories.SpotlightRoomRepository
import
chat.rocket.core.temp.TempSpotlightRoomCaller
import
chat.rocket.core.utils.Pair
import
chat.rocket.core.utils.Triple
import
io.reactivex.functions.BiFunction
import
io.reactivex.functions.Function3
class
AutocompleteChannelInteractor
(
private
val
roomRepository
:
RoomRepository
,
private
val
spotlightRoomRepository
:
SpotlightRoomRepository
,
private
val
tempSpotlightRoomCaller
:
TempSpotlightRoomCaller
)
{
fun
getSuggestionsFor
(
name
:
String
):
Flowable
<
List
<
SpotlightRoom
>>
{
return
Flowable
.
zip
<
String
,
List
<
SpotlightRoom
>,
List
<
SpotlightRoom
>,
Triple
<
String
,
List
<
SpotlightRoom
>,
List
<
SpotlightRoom
>>>(
Flowable
.
just
(
name
),
roomRepository
.
getLatestSeen
(
5
).
map
{
toSpotlightRooms
(
it
)
},
roomRepository
.
getSortedLikeName
(
name
,
SortDirection
.
DESC
,
5
).
map
{
toSpotlightRooms
(
it
)
},
Function3
{
a
,
b
,
c
->
Triple
.
create
(
a
,
b
,
c
)
}
)
.
flatMap
{
triple
->
if
(
triple
.
first
.
isEmpty
())
{
return
@flatMap
Flowable
.
just
(
triple
.
second
)
}
val
spotlightRooms
=
ArrayList
<
SpotlightRoom
>()
spotlightRooms
.
addAll
(
triple
.
second
.
filter
{
it
.
name
.
contains
(
triple
.
first
,
true
)
})
spotlightRooms
.
addAll
(
triple
.
third
)
val
workedList
=
spotlightRooms
.
distinct
().
take
(
5
)
if
(
workedList
.
size
==
5
)
{
return
@flatMap
Flowable
.
just
<
List
<
SpotlightRoom
>>(
workedList
)
}
tempSpotlightRoomCaller
.
search
(
triple
.
first
)
spotlightRoomRepository
.
getSuggestionsFor
(
triple
.
first
,
SortDirection
.
DESC
,
5
)
.
withLatestFrom
<
List
<
SpotlightRoom
>,
Pair
<
List
<
SpotlightRoom
>,
List
<
SpotlightRoom
>>>(
Flowable
.
just
(
workedList
),
BiFunction
{
a
,
b
->
Pair
.
create
(
a
,
b
)
}
)
.
map
{
pair
->
val
spotlightRooms1
=
ArrayList
<
SpotlightRoom
>()
spotlightRooms1
.
addAll
(
pair
.
second
)
spotlightRooms1
.
addAll
(
pair
.
first
)
return
@map
spotlightRooms1
.
distinct
().
take
(
5
)
}
}
}
private
fun
toSpotlightRooms
(
rooms
:
List
<
Room
>):
List
<
SpotlightRoom
>
{
val
size
=
rooms
.
size
val
spotlightRooms
=
ArrayList
<
SpotlightRoom
>(
size
)
for
(
i
in
0
..
size
-
1
)
{
val
room
=
rooms
[
i
]
spotlightRooms
.
add
(
SpotlightRoom
.
builder
()
.
setId
(
room
.
id
)
.
setName
(
room
.
name
)
.
setType
(
room
.
type
)
.
build
())
}
return
spotlightRooms
}
}
rocket-chat-core/src/main/java/chat/rocket/core/interactors/AutocompleteUserInteractor.kt
0 → 100644
View file @
825b0b9f
package
chat.rocket.core.interactors
import
chat.rocket.core.SortDirection
import
chat.rocket.core.models.Message
import
chat.rocket.core.models.Room
import
chat.rocket.core.models.SpotlightUser
import
chat.rocket.core.models.User
import
chat.rocket.core.repositories.MessageRepository
import
chat.rocket.core.repositories.SpotlightUserRepository
import
chat.rocket.core.repositories.UserRepository
import
chat.rocket.core.temp.TempSpotlightUserCaller
import
chat.rocket.core.utils.Triple
import
io.reactivex.Flowable
import
io.reactivex.functions.Function3
import
java.util.ArrayList
class
AutocompleteUserInteractor
(
private
val
room
:
Room
,
private
val
userRepository
:
UserRepository
,
private
val
messageRepository
:
MessageRepository
,
private
val
spotlightUserRepository
:
SpotlightUserRepository
,
private
val
tempSpotlightUserCaller
:
TempSpotlightUserCaller
)
{
private
val
groupMentions
=
listOf
(
SpotlightUser
.
builder
().
setId
(
"all"
).
setUsername
(
"all"
).
setStatus
(
"online"
).
build
(),
SpotlightUser
.
builder
().
setId
(
"here"
).
setUsername
(
"here"
).
setStatus
(
"online"
).
build
()
)
fun
getSuggestionsFor
(
name
:
String
):
Flowable
<
List
<
SpotlightUser
>>
{
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
()
},
Function3
{
a
,
b
,
c
->
Triple
.
create
(
a
,
b
,
c
)
}
)
.
flatMap
{
triple
->
val
recentUsers
=
triple
.
second
.
takeUsers
(
5
).
toSpotlightUsers
()
if
(
triple
.
first
.
isEmpty
())
{
return
@flatMap
Flowable
.
just
(
recentUsers
+
groupMentions
)
}
val
workedUsers
=
(
recentUsers
.
filter
{
it
.
username
.
contains
(
triple
.
first
,
true
)
}
+
triple
.
third
).
distinct
().
take
(
5
)
if
(
workedUsers
.
size
==
5
)
{
return
@flatMap
Flowable
.
just
(
workedUsers
+
groupMentions
.
filter
{
it
.
username
.
contains
(
triple
.
first
,
true
)
})
}
tempSpotlightUserCaller
.
search
(
triple
.
first
)
spotlightUserRepository
.
getSuggestionsFor
(
triple
.
first
,
SortDirection
.
DESC
,
5
)
.
withLatestFrom
<
List
<
SpotlightUser
>,
List
<
SpotlightUser
>,
Triple
<
List
<
SpotlightUser
>,
List
<
SpotlightUser
>,
List
<
SpotlightUser
>>>(
Flowable
.
just
(
workedUsers
),
Flowable
.
just
(
groupMentions
.
filter
{
it
.
username
.
contains
(
triple
.
first
,
true
)
}),
Function3
{
a
,
b
,
c
->
Triple
.
create
(
a
,
b
,
c
)
}
)
.
map
{
triple
->
val
spotlightUsers
=
triple
.
first
+
triple
.
second
return
@map
spotlightUsers
.
distinct
().
take
(
5
)
+
triple
.
third
}
}
}
}
fun
List
<
User
>.
toSpotlightUsers
():
List
<
SpotlightUser
>
{
val
size
=
this
.
size
val
spotlightUsers
=
ArrayList
<
SpotlightUser
>(
size
)
for
(
i
in
0
..
size
-
1
)
{
val
user
=
this
[
i
]
spotlightUsers
.
add
(
SpotlightUser
.
builder
()
.
setId
(
user
.
id
)
.
setUsername
(
user
.
username
)
.
setStatus
(
user
.
status
)
.
build
())
}
return
spotlightUsers
}
fun
List
<
Message
>.
takeUsers
(
n
:
Int
):
List
<
User
>
{
val
users
=
ArrayList
<
User
>()
this
.
forEach
{
if
(
it
.
user
!=
null
&&
!
users
.
contains
(
it
.
user
!!
))
{
users
.
add
(
it
.
user
!!
)
if
(
users
.
size
==
n
)
{
return
@forEach
}
}
}
return
users
}
rocket-chat-core/src/main/java/chat/rocket/core/interactors/CanCreateRoomInteractor.java
deleted
100644 → 0
View file @
5002b314
package
chat
.
rocket
.
core
.
interactors
;
import
io.reactivex.Flowable
;
import
io.reactivex.Single
;
import
chat.rocket.core.repositories.UserRepository
;
public
class
CanCreateRoomInteractor
{
private
final
UserRepository
userRepository
;
private
final
SessionInteractor
sessionInteractor
;
public
CanCreateRoomInteractor
(
UserRepository
userRepository
,
SessionInteractor
sessionInteractor
)
{
this
.
userRepository
=
userRepository
;
this
.
sessionInteractor
=
sessionInteractor
;
}
public
Single
<
Boolean
>
canCreate
(
String
roomId
)
{
return
Flowable
.
zip
(
userRepository
.
getCurrent
(),
sessionInteractor
.
getDefault
(),
Flowable
.
just
(
roomId
),
(
user
,
session
,
room
)
->
user
!=
null
&&
session
!=
null
&&
room
!=
null
)
.
first
(
false
);
}
}
rocket-chat-core/src/main/java/chat/rocket/core/interactors/CanCreateRoomInteractor.kt
0 → 100644
View file @
825b0b9f
package
chat.rocket.core.interactors
import
chat.rocket.core.models.Session
import
chat.rocket.core.models.User
import
io.reactivex.Flowable
import
io.reactivex.Single
import
chat.rocket.core.repositories.UserRepository
import
com.fernandocejas.arrow.optional.Optional
import
io.reactivex.functions.Function3
class
CanCreateRoomInteractor
(
private
val
userRepository
:
UserRepository
,
private
val
sessionInteractor
:
SessionInteractor
)
{
fun
canCreate
(
roomId
:
String
):
Single
<
Boolean
>
{
return
Flowable
.
zip
<
Optional
<
User
>,
Optional
<
Session
>,
String
,
Boolean
>(
userRepository
.
current
,
sessionInteractor
.
getDefault
(),
Flowable
.
just
(
roomId
),
Function3
{
user
,
session
,
room
->
user
.
isPresent
&&
session
.
isPresent
&&
room
!=
null
}
)
.
first
(
false
)
}
}
rocket-chat-core/src/main/java/chat/rocket/core/interactors/MessageInteractor.java
deleted
100644 → 0
View file @
5002b314
package
chat
.
rocket
.
core
.
interactors
;
import
com.fernandocejas.arrow.optional.Optional
;
import
io.reactivex.Flowable
;
import
io.reactivex.Single
;
import
java.util.List
;
import
java.util.UUID
;
import
chat.rocket.core.SyncState
;
import
chat.rocket.core.models.Message
;
import
chat.rocket.core.models.Room
;
import
chat.rocket.core.models.RoomHistoryState
;
import
chat.rocket.core.models.User
;
import
chat.rocket.core.repositories.MessageRepository
;
import
chat.rocket.core.repositories.RoomRepository
;
public
class
MessageInteractor
{
private
final
MessageRepository
messageRepository
;
private
final
RoomRepository
roomRepository
;
public
MessageInteractor
(
MessageRepository
messageRepository
,
RoomRepository
roomRepository
)
{
this
.
messageRepository
=
messageRepository
;
this
.
roomRepository
=
roomRepository
;
}
public
Single
<
Boolean
>
loadMessages
(
Room
room
)
{
final
RoomHistoryState
roomHistoryState
=
RoomHistoryState
.
builder
()
.
setRoomId
(
room
.
getRoomId
())
.
setSyncState
(
SyncState
.
NOT_SYNCED
)
.
setCount
(
100
)
.
setReset
(
true
)
.
setComplete
(
false
)
.
setTimestamp
(
0
)
.
build
();
return
roomRepository
.
setHistoryState
(
roomHistoryState
);
}
public
Single
<
Boolean
>
loadMoreMessages
(
Room
room
)
{
return
roomRepository
.
getHistoryStateByRoomId
(
room
.
getRoomId
())
.
filter
(
Optional:
:
isPresent
)
.
map
(
Optional:
:
get
)
.
filter
(
roomHistoryState
->
{
int
syncState
=
roomHistoryState
.
getSyncState
();
return
!
roomHistoryState
.
isComplete
()
&&
(
syncState
==
SyncState
.
SYNCED
||
syncState
==
SyncState
.
FAILED
);
})
.
map
(
Optional:
:
of
)
.
first
(
Optional
.
absent
())
.
flatMap
(
historyStateOptional
->
{
if
(!
historyStateOptional
.
isPresent
())
{
return
Single
.
just
(
false
);
}
return
roomRepository
.
setHistoryState
(
historyStateOptional
.
get
().
withSyncState
(
SyncState
.
NOT_SYNCED
));
});
}
public
Single
<
Boolean
>
send
(
Room
destination
,
User
sender
,
String
messageText
)
{
final
Message
message
=
Message
.
builder
()
.
setId
(
UUID
.
randomUUID
().
toString
())
.
setSyncState
(
SyncState
.
NOT_SYNCED
)
.
setTimestamp
(
System
.
currentTimeMillis
())
.
setRoomId
(
destination
.
getRoomId
())
.
setMessage
(
messageText
)
.
setGroupable
(
false
)
.
setUser
(
sender
)
.
build
();
return
messageRepository
.
save
(
message
);
}
public
Single
<
Boolean
>
resend
(
Message
message
,
User
sender
)
{
return
messageRepository
.
save
(
message
.
withSyncState
(
SyncState
.
NOT_SYNCED
)
.
withUser
(
sender
));
}
public
Single
<
Boolean
>
delete
(
Message
message
)
{
return
messageRepository
.
delete
(
message
);
}
public
Single
<
Integer
>
unreadCountFor
(
Room
room
,
User
user
)
{
return
messageRepository
.
unreadCountFor
(
room
,
user
);
}
public
Flowable
<
List
<
Message
>>
getAllFrom
(
Room
room
)
{
return
messageRepository
.
getAllFrom
(
room
);
}
}
rocket-chat-core/src/main/java/chat/rocket/core/interactors/MessageInteractor.kt
0 → 100644
View file @
825b0b9f
package
chat.rocket.core.interactors
import
com.fernandocejas.arrow.optional.Optional
import
io.reactivex.Flowable
import
io.reactivex.Single
import
java.util.UUID
import
chat.rocket.core.SyncState
import
chat.rocket.core.models.Message
import
chat.rocket.core.models.Room
import
chat.rocket.core.models.RoomHistoryState
import
chat.rocket.core.models.User
import
chat.rocket.core.repositories.MessageRepository
import
chat.rocket.core.repositories.RoomRepository
class
MessageInteractor
(
private
val
messageRepository
:
MessageRepository
,
private
val
roomRepository
:
RoomRepository
)
{
fun
loadMessages
(
room
:
Room
):
Single
<
Boolean
>
{
val
roomHistoryState
=
RoomHistoryState
.
builder
()
.
setRoomId
(
room
.
roomId
)
.
setSyncState
(
SyncState
.
NOT_SYNCED
)
.
setCount
(
100
)
.
setReset
(
true
)
.
setComplete
(
false
)
.
setTimestamp
(
0
)
.
build
()
return
roomRepository
.
setHistoryState
(
roomHistoryState
)
}
fun
loadMoreMessages
(
room
:
Room
):
Single
<
Boolean
>
{
return
roomRepository
.
getHistoryStateByRoomId
(
room
.
roomId
)
.
filter
{
it
.
isPresent
}
.
map
{
it
.
get
()
}
.
filter
{
roomHistoryState
->
val
syncState
=
roomHistoryState
.
syncState
!
roomHistoryState
.
isComplete
&&
(
syncState
==
SyncState
.
SYNCED
||
syncState
==
SyncState
.
FAILED
)
}
.
map
{
Optional
.
of
(
it
)
}
.
first
(
Optional
.
absent
())
.
flatMap
{
historyStateOptional
->
if
(!
historyStateOptional
.
isPresent
)
{
return
@flatMap
Single
.
just
(
false
)
}
roomRepository
.
setHistoryState
(
historyStateOptional
.
get
().
withSyncState
(
SyncState
.
NOT_SYNCED
))
}
}
fun
send
(
destination
:
Room
,
sender
:
User
,
messageText
:
String
):
Single
<
Boolean
>
{
val
message
=
Message
.
builder
()
.
setId
(
UUID
.
randomUUID
().
toString
())
.
setSyncState
(
SyncState
.
NOT_SYNCED
)
.
setTimestamp
(
System
.
currentTimeMillis
())
.
setRoomId
(
destination
.
roomId
)
.
setMessage
(
messageText
)
.
setGroupable
(
false
)
.
setUser
(
sender
)
.
build
()
return
messageRepository
.
save
(
message
)
}
fun
resend
(
message
:
Message
,
sender
:
User
):
Single
<
Boolean
>
{
return
messageRepository
.
save
(
message
.
withSyncState
(
SyncState
.
NOT_SYNCED
).
withUser
(
sender
))
}
fun
delete
(
message
:
Message
):
Single
<
Boolean
>
{
return
messageRepository
.
delete
(
message
)
}
fun
unreadCountFor
(
room
:
Room
,
user
:
User
):
Single
<
Int
>
{
return
messageRepository
.
unreadCountFor
(
room
,
user
)
}
fun
getAllFrom
(
room
:
Room
):
Flowable
<
List
<
Message
>>
{
return
messageRepository
.
getAllFrom
(
room
)
}
}
rocket-chat-core/src/main/java/chat/rocket/core/interactors/RoomInteractor.java
deleted
100644 → 0
View file @
5002b314
package
chat
.
rocket
.
core
.
interactors
;
import
io.reactivex.Flowable
;
import
java.util.List
;
import
chat.rocket.core.models.Room
;
import
chat.rocket.core.repositories.RoomRepository
;
public
class
RoomInteractor
{
private
final
RoomRepository
roomRepository
;
public
RoomInteractor
(
RoomRepository
roomRepository
)
{
this
.
roomRepository
=
roomRepository
;
}
public
Flowable
<
Integer
>
getTotalUnreadMentionsCount
()
{
return
roomRepository
.
getAll
()
.
flatMap
(
rooms
->
Flowable
.
fromIterable
(
rooms
)
.
filter
(
room
->
room
.
isOpen
()
&&
room
.
isAlert
())
.
map
(
Room:
:
getUnread
)
.
defaultIfEmpty
(
0
)
.
reduce
((
unreadCount
,
unreadCount2
)
->
unreadCount
+
unreadCount2
)
.
toFlowable
());
}
public
Flowable
<
Long
>
getTotalUnreadRoomsCount
()
{
return
roomRepository
.
getAll
()
.
flatMap
(
rooms
->
Flowable
.
fromIterable
(
rooms
)
.
filter
(
room
->
room
.
isOpen
()
&&
room
.
isAlert
())
.
count
()
.
toFlowable
());
}
public
Flowable
<
List
<
Room
>>
getOpenRooms
()
{
return
roomRepository
.
getAll
()
.
flatMap
(
rooms
->
Flowable
.
fromIterable
(
rooms
)
.
filter
(
Room:
:
isOpen
)
.
toList
()
.
toFlowable
());
}
}
rocket-chat-core/src/main/java/chat/rocket/core/interactors/RoomInteractor.kt
0 → 100644
View file @
825b0b9f
package
chat.rocket.core.interactors
import
io.reactivex.Flowable
import
chat.rocket.core.SortDirection
import
chat.rocket.core.models.Room
import
chat.rocket.core.repositories.RoomRepository
class
RoomInteractor
(
private
val
roomRepository
:
RoomRepository
)
{
fun
getTotalUnreadMentionsCount
():
Flowable
<
Int
>
{
return
roomRepository
.
all
.
flatMap
{
rooms
->
Flowable
.
fromIterable
(
rooms
)
.
filter
{
room
->
room
.
isOpen
&&
room
.
isAlert
}
.
map
{
it
.
unread
}
.
defaultIfEmpty
(
0
)
.
reduce
{
unreadCount
,
unreadCount2
->
unreadCount
+
unreadCount2
}
.
toFlowable
()
}
}
fun
getTotalUnreadRoomsCount
():
Flowable
<
Long
>
{
return
roomRepository
.
all
.
flatMap
{
rooms
->
Flowable
.
fromIterable
(
rooms
)
.
filter
{
room
->
room
.
isOpen
&&
room
.
isAlert
}
.
count
()
.
toFlowable
()
}
}
fun
getOpenRooms
():
Flowable
<
List
<
Room
>>
{
return
roomRepository
.
all
.
flatMap
{
rooms
->
Flowable
.
fromIterable
(
rooms
)
.
filter
{
it
.
isOpen
}
.
toList
()
.
toFlowable
()
}
}
fun
getRoomsWithNameLike
(
name
:
String
):
Flowable
<
List
<
Room
>>
{
return
roomRepository
.
getSortedLikeName
(
name
,
SortDirection
.
DESC
,
5
)
}
}
rocket-chat-core/src/main/java/chat/rocket/core/interactors/SessionInteractor.java
deleted
100644 → 0
View file @
5002b314
package
chat
.
rocket
.
core
.
interactors
;
import
com.fernandocejas.arrow.optional.Optional
;
import
io.reactivex.Flowable
;
import
io.reactivex.Single
;
import
chat.rocket.core.models.Session
;
import
chat.rocket.core.repositories.SessionRepository
;
public
class
SessionInteractor
{
private
static
final
int
DEFAULT_ID
=
0
;
private
final
SessionRepository
sessionRepository
;
public
SessionInteractor
(
SessionRepository
sessionRepository
)
{
this
.
sessionRepository
=
sessionRepository
;
}
public
Flowable
<
Optional
<
Session
>>
getDefault
()
{
return
sessionRepository
.
getById
(
DEFAULT_ID
);
}
public
Flowable
<
Session
.
State
>
getSessionState
()
{
return
getDefault
()
.
map
(
sessionOptional
->
getStateFrom
(
sessionOptional
.
orNull
()));
}
public
Single
<
Boolean
>
retryLogin
()
{
return
getDefault
()
.
filter
(
Optional:
:
isPresent
)
.
map
(
Optional:
:
get
)
.
filter
(
session
->
session
.
getToken
()
!=
null
&&
(!
session
.
isTokenVerified
()
||
session
.
getError
()
!=
null
))
.
map
(
session
->
Optional
.
of
(
session
.
withTokenVerified
(
false
).
withError
(
null
)))
.
first
(
Optional
.
absent
())
.
flatMap
(
sessionOptional
->
{
if
(!
sessionOptional
.
isPresent
())
{
return
Single
.
just
(
false
);
}
return
sessionRepository
.
save
(
sessionOptional
.
get
());
});
}
private
Session
.
State
getStateFrom
(
Session
session
)
{
if
(
session
==
null
)
{
return
Session
.
State
.
UNAVAILABLE
;
}
final
String
token
=
session
.
getToken
();
if
(
token
==
null
||
token
.
length
()
==
0
)
{
return
Session
.
State
.
UNAVAILABLE
;
}
final
String
error
=
session
.
getError
();
if
(
error
==
null
||
error
.
length
()
==
0
)
{
return
Session
.
State
.
VALID
;
}
return
Session
.
State
.
INVALID
;
}
}
rocket-chat-core/src/main/java/chat/rocket/core/interactors/SessionInteractor.kt
0 → 100644
View file @
825b0b9f
package
chat.rocket.core.interactors
import
com.fernandocejas.arrow.optional.Optional
import
io.reactivex.Flowable
import
io.reactivex.Single
import
chat.rocket.core.models.Session
import
chat.rocket.core.repositories.SessionRepository
class
SessionInteractor
(
private
val
sessionRepository
:
SessionRepository
)
{
companion
object
{
private
val
DEFAULT_ID
=
0
}
fun
getDefault
():
Flowable
<
Optional
<
Session
>>
{
return
sessionRepository
.
getById
(
DEFAULT_ID
)
}
fun
getSessionState
():
Flowable
<
Session
.
State
>
{
return
getDefault
()
.
map
{
sessionOptional
->
getStateFrom
(
sessionOptional
.
orNull
())
}
}
fun
retryLogin
():
Single
<
Boolean
>
{
return
getDefault
()
.
filter
{
it
.
isPresent
}
.
map
{
it
.
get
()
}
.
filter
{
session
->
session
.
token
!=
null
&&
(!
session
.
isTokenVerified
||
session
.
error
!=
null
)
}
.
map
{
session
->
Optional
.
of
(
session
.
withTokenVerified
(
false
).
withError
(
null
))
}
.
first
(
Optional
.
absent
())
.
flatMap
{
sessionOptional
->
if
(!
sessionOptional
.
isPresent
)
{
return
@flatMap
Single
.
just
(
false
)
}
sessionRepository
.
save
(
sessionOptional
.
get
())
}
}
private
fun
getStateFrom
(
session
:
Session
?):
Session
.
State
{
if
(
session
==
null
)
{
return
Session
.
State
.
UNAVAILABLE
}
val
token
=
session
.
token
if
(
token
==
null
||
token
.
isEmpty
())
{
return
Session
.
State
.
UNAVAILABLE
}
val
error
=
session
.
error
if
(
error
==
null
||
error
.
isEmpty
())
{
return
Session
.
State
.
VALID
}
return
Session
.
State
.
INVALID
}
}
rocket-chat-core/src/main/java/chat/rocket/core/interactors/UserInteractor.java
0 → 100644
View file @
825b0b9f
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
;
public
class
UserInteractor
{
private
final
UserRepository
userRepository
;
public
UserInteractor
(
UserRepository
userRepository
)
{
this
.
userRepository
=
userRepository
;
}
public
Flowable
<
List
<
User
>>
getUserAutocompleteSuggestions
(
String
name
)
{
return
userRepository
.
getSortedLikeName
(
name
,
SortDirection
.
DESC
,
5
);
}
}
rocket-chat-core/src/main/java/chat/rocket/core/models/SpotlightRoom.java
0 → 100644
View file @
825b0b9f
package
chat
.
rocket
.
core
.
models
;
import
com.google.auto.value.AutoValue
;
@AutoValue
public
abstract
class
SpotlightRoom
{
public
abstract
String
getId
();
public
abstract
String
getName
();
public
abstract
String
getType
();
public
boolean
isChannel
()
{
return
Room
.
TYPE_CHANNEL
.
equals
(
getType
());
}
public
boolean
isPrivate
()
{
return
Room
.
TYPE_PRIVATE
.
equals
(
getType
());
}
public
boolean
isDirectMessage
()
{
return
Room
.
TYPE_DIRECT_MESSAGE
.
equals
(
getType
());
}
public
static
Builder
builder
()
{
return
new
AutoValue_SpotlightRoom
.
Builder
();
}
@AutoValue
.
Builder
public
abstract
static
class
Builder
{
public
abstract
Builder
setId
(
String
id
);
public
abstract
Builder
setName
(
String
name
);
public
abstract
Builder
setType
(
String
type
);
public
abstract
SpotlightRoom
build
();
}
}
rocket-chat-core/src/main/java/chat/rocket/core/models/SpotlightUser.java
0 → 100644
View file @
825b0b9f
package
chat
.
rocket
.
core
.
models
;
import
com.google.auto.value.AutoValue
;
import
javax.annotation.Nullable
;
@AutoValue
public
abstract
class
SpotlightUser
{
public
abstract
String
getId
();
public
abstract
String
getUsername
();
@Nullable
public
abstract
String
getName
();
@Nullable
public
abstract
String
getStatus
();
public
static
Builder
builder
()
{
return
new
AutoValue_SpotlightUser
.
Builder
();
}
@AutoValue
.
Builder
public
abstract
static
class
Builder
{
public
abstract
Builder
setId
(
String
id
);
public
abstract
Builder
setUsername
(
String
username
);
public
abstract
Builder
setName
(
String
name
);
public
abstract
Builder
setStatus
(
String
status
);
public
abstract
SpotlightUser
build
();
}
}
rocket-chat-core/src/main/java/chat/rocket/core/repositories/RoomRepository.java
View file @
825b0b9f
...
...
@@ -5,6 +5,7 @@ import io.reactivex.Flowable;
import
io.reactivex.Single
;
import
java.util.List
;
import
chat.rocket.core.SortDirection
;
import
chat.rocket.core.models.Room
;
import
chat.rocket.core.models.RoomHistoryState
;
...
...
@@ -17,4 +18,8 @@ public interface RoomRepository {
Flowable
<
Optional
<
RoomHistoryState
>>
getHistoryStateByRoomId
(
String
roomId
);
Single
<
Boolean
>
setHistoryState
(
RoomHistoryState
roomHistoryState
);
Flowable
<
List
<
Room
>>
getSortedLikeName
(
String
name
,
SortDirection
direction
,
int
limit
);
Flowable
<
List
<
Room
>>
getLatestSeen
(
int
limit
);
}
rocket-chat-core/src/main/java/chat/rocket/core/repositories/SpotlightRoomRepository.java
0 → 100644
View file @
825b0b9f
package
chat
.
rocket
.
core
.
repositories
;
import
io.reactivex.Flowable
;
import
java.util.List
;
import
chat.rocket.core.SortDirection
;
import
chat.rocket.core.models.SpotlightRoom
;
public
interface
SpotlightRoomRepository
{
Flowable
<
List
<
SpotlightRoom
>>
getSuggestionsFor
(
String
name
,
SortDirection
direction
,
int
limit
);
}
rocket-chat-core/src/main/java/chat/rocket/core/repositories/SpotlightUserRepository.java
0 → 100644
View file @
825b0b9f
package
chat
.
rocket
.
core
.
repositories
;
import
io.reactivex.Flowable
;
import
java.util.List
;
import
chat.rocket.core.SortDirection
;
import
chat.rocket.core.models.SpotlightUser
;
public
interface
SpotlightUserRepository
{
Flowable
<
List
<
SpotlightUser
>>
getSuggestionsFor
(
String
name
,
SortDirection
direction
,
int
limit
);
}
rocket-chat-core/src/main/java/chat/rocket/core/repositories/UserRepository.java
View file @
825b0b9f
...
...
@@ -3,9 +3,13 @@ package chat.rocket.core.repositories;
import
com.fernandocejas.arrow.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
);
}
rocket-chat-core/src/main/java/chat/rocket/core/temp/TempSpotlightRoomCaller.java
0 → 100644
View file @
825b0b9f
package
chat
.
rocket
.
core
.
temp
;
public
interface
TempSpotlightRoomCaller
{
void
search
(
String
term
);
}
rocket-chat-core/src/main/java/chat/rocket/core/temp/TempSpotlightUserCaller.java
0 → 100644
View file @
825b0b9f
package
chat
.
rocket
.
core
.
temp
;
public
interface
TempSpotlightUserCaller
{
void
search
(
String
term
);
}
rocket-chat-core/src/main/java/chat/rocket/core/utils/Pair.java
0 → 100644
View file @
825b0b9f
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/util/Pair.java
package
chat
.
rocket
.
core
.
utils
;
/**
* Container to ease passing around a tuple of two objects. This object provides a sensible
* implementation of equals(), returning true if equals() is true on each of the contained
* objects.
*/
public
class
Pair
<
F
,
S
>
{
public
final
F
first
;
public
final
S
second
;
/**
* Constructor for a Pair.
* @param first the first object in the Pair
* @param second the second object in the pair
*/
public
Pair
(
F
first
,
S
second
)
{
this
.
first
=
first
;
this
.
second
=
second
;
}
/**
* Checks the two objects for equality by delegating to their respective
* {@link Object#equals(Object)} methods.
* @param o the {@link Pair} to which this one is to be checked for equality
* @return true if the underlying objects of the Pair are both considered equal
*/
@Override
public
boolean
equals
(
Object
o
)
{
if
(!(
o
instanceof
Pair
))
{
return
false
;
}
Pair
<?,
?>
p
=
(
Pair
<?,
?>)
o
;
return
equals
(
p
.
first
,
first
)
&&
equals
(
p
.
second
,
second
);
}
/**
* Compute a hash code using the hash codes of the underlying objects
* @return a hashcode of the Pair
*/
@Override
public
int
hashCode
()
{
return
(
first
==
null
?
0
:
first
.
hashCode
())
^
(
second
==
null
?
0
:
second
.
hashCode
());
}
@Override
public
String
toString
()
{
return
"Pair{"
+
String
.
valueOf
(
first
)
+
" "
+
String
.
valueOf
(
second
)
+
"}"
;
}
private
boolean
equals
(
Object
var0
,
Object
var1
)
{
return
var0
==
var1
||
var0
!=
null
&&
var0
.
equals
(
var1
);
}
/**
* Convenience method for creating an appropriately typed pair.
* @param a the first object in the Pair
* @param b the second object in the pair
* @return a Pair that is templatized with the types of a and b
*/
public
static
<
A
,
B
>
Pair
<
A
,
B
>
create
(
A
a
,
B
b
)
{
return
new
Pair
<
A
,
B
>(
a
,
b
);
}
}
\ No newline at end of file
rocket-chat-core/src/main/java/chat/rocket/core/utils/Triple.java
0 → 100644
View file @
825b0b9f
package
chat
.
rocket
.
core
.
utils
;
public
class
Triple
<
F
,
S
,
T
>
{
public
final
F
first
;
public
final
S
second
;
public
final
T
third
;
public
Triple
(
F
first
,
S
second
,
T
third
)
{
this
.
first
=
first
;
this
.
second
=
second
;
this
.
third
=
third
;
}
@Override
public
boolean
equals
(
Object
o
)
{
if
(!(
o
instanceof
Triple
))
{
return
false
;
}
Triple
<?,
?,
?>
t
=
(
Triple
<?,
?,
?>)
o
;
return
equals
(
t
.
first
,
first
)
&&
equals
(
t
.
second
,
second
)
&&
equals
(
t
.
third
,
third
);
}
@Override
public
int
hashCode
()
{
return
(
first
==
null
?
0
:
first
.
hashCode
())
^
(
second
==
null
?
0
:
second
.
hashCode
())
^
(
third
==
null
?
0
:
third
.
hashCode
());
}
private
boolean
equals
(
Object
var0
,
Object
var1
)
{
return
var0
==
var1
||
var0
!=
null
&&
var0
.
equals
(
var1
);
}
public
static
<
A
,
B
,
C
>
Triple
<
A
,
B
,
C
>
create
(
A
a
,
B
b
,
C
c
)
{
return
new
Triple
<
A
,
B
,
C
>(
a
,
b
,
c
);
}
}
rocket-chat-core/src/test/java/chat/rocket/core/interactors/AutocompleteChannelInteractorTest.java
0 → 100644
View file @
825b0b9f
package
chat
.
rocket
.
core
.
interactors
;
import
static
org
.
mockito
.
Mockito
.*;
import
io.reactivex.Flowable
;
import
io.reactivex.subscribers.TestSubscriber
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.mockito.Mock
;
import
org.mockito.junit.MockitoJUnitRunner
;
import
java.util.ArrayList
;
import
java.util.List
;
import
chat.rocket.core.SortDirection
;
import
chat.rocket.core.models.Room
;
import
chat.rocket.core.models.SpotlightRoom
;
import
chat.rocket.core.repositories.RoomRepository
;
import
chat.rocket.core.repositories.SpotlightRoomRepository
;
import
chat.rocket.core.temp.TempSpotlightRoomCaller
;
@RunWith
(
MockitoJUnitRunner
.
class
)
public
class
AutocompleteChannelInteractorTest
{
@Mock
RoomRepository
roomRepository
;
@Mock
SpotlightRoomRepository
spotlightRoomRepository
;
@Mock
TempSpotlightRoomCaller
tempSpotlightRoomCaller
;
private
AutocompleteChannelInteractor
autocompleteChannelInteractor
;
@Before
public
void
setUp
()
{
autocompleteChannelInteractor
=
new
AutocompleteChannelInteractor
(
roomRepository
,
spotlightRoomRepository
,
tempSpotlightRoomCaller
);
}
@Test
public
void
getSuggestionsForEmptyStringReturnLatestSeenOnly
()
throws
Exception
{
List
<
Room
>
rooms
=
new
ArrayList
<>();
rooms
.
add
(
getRoom
(
"id1"
,
"Name1"
,
"c"
));
when
(
roomRepository
.
getLatestSeen
(
anyInt
())).
thenReturn
(
Flowable
.
just
(
rooms
));
rooms
=
new
ArrayList
<>();
rooms
.
add
(
getRoom
(
"id2"
,
"Name2"
,
"c"
));
when
(
roomRepository
.
getSortedLikeName
(
anyString
(),
any
(
SortDirection
.
class
),
anyInt
()))
.
thenReturn
(
Flowable
.
just
(
rooms
));
TestSubscriber
<
List
<
SpotlightRoom
>>
testSubscriber
=
new
TestSubscriber
<>();
autocompleteChannelInteractor
.
getSuggestionsFor
(
""
).
subscribe
(
testSubscriber
);
List
<
SpotlightRoom
>
spotlightRooms
=
new
ArrayList
<>();
spotlightRooms
.
add
(
getSpotlightRoom
(
"id1"
,
"Name1"
,
"c"
));
testSubscriber
.
assertResult
(
spotlightRooms
);
}
@Test
public
void
getSuggestionsForNonEmptyStringReturnLatestSeenAndFromRooms
()
throws
Exception
{
List
<
Room
>
rooms
=
new
ArrayList
<>();
rooms
.
add
(
getRoom
(
"id1"
,
"Name1"
,
"c"
));
rooms
.
add
(
getRoom
(
"id1.1"
,
"Ame1.1"
,
"c"
));
when
(
roomRepository
.
getLatestSeen
(
anyInt
())).
thenReturn
(
Flowable
.
just
(
rooms
));
rooms
=
new
ArrayList
<>();
rooms
.
add
(
getRoom
(
"id1"
,
"Name1"
,
"c"
));
rooms
.
add
(
getRoom
(
"id2"
,
"Name2"
,
"c"
));
rooms
.
add
(
getRoom
(
"id3"
,
"Name3"
,
"c"
));
rooms
.
add
(
getRoom
(
"id4"
,
"Name4"
,
"c"
));
rooms
.
add
(
getRoom
(
"id5"
,
"Name5"
,
"c"
));
when
(
roomRepository
.
getSortedLikeName
(
anyString
(),
any
(
SortDirection
.
class
),
anyInt
()))
.
thenReturn
(
Flowable
.
just
(
rooms
));
TestSubscriber
<
List
<
SpotlightRoom
>>
testSubscriber
=
new
TestSubscriber
<>();
autocompleteChannelInteractor
.
getSuggestionsFor
(
"N"
).
subscribe
(
testSubscriber
);
List
<
SpotlightRoom
>
spotlightRooms
=
new
ArrayList
<>();
spotlightRooms
.
add
(
getSpotlightRoom
(
"id1"
,
"Name1"
,
"c"
));
spotlightRooms
.
add
(
getSpotlightRoom
(
"id2"
,
"Name2"
,
"c"
));
spotlightRooms
.
add
(
getSpotlightRoom
(
"id3"
,
"Name3"
,
"c"
));
spotlightRooms
.
add
(
getSpotlightRoom
(
"id4"
,
"Name4"
,
"c"
));
spotlightRooms
.
add
(
getSpotlightRoom
(
"id5"
,
"Name5"
,
"c"
));
testSubscriber
.
assertResult
(
spotlightRooms
);
}
@Test
public
void
getSuggestionsForMayGetFromNetwork
()
throws
Exception
{
List
<
Room
>
rooms
=
new
ArrayList
<>();
rooms
.
add
(
getRoom
(
"id1"
,
"Name1"
,
"c"
));
rooms
.
add
(
getRoom
(
"id1.1"
,
"Ame1.1"
,
"c"
));
when
(
roomRepository
.
getLatestSeen
(
anyInt
())).
thenReturn
(
Flowable
.
just
(
rooms
));
rooms
=
new
ArrayList
<>();
rooms
.
add
(
getRoom
(
"id1"
,
"Name1"
,
"c"
));
rooms
.
add
(
getRoom
(
"id2"
,
"Name2"
,
"c"
));
when
(
roomRepository
.
getSortedLikeName
(
anyString
(),
any
(
SortDirection
.
class
),
anyInt
()))
.
thenReturn
(
Flowable
.
just
(
rooms
));
List
<
SpotlightRoom
>
spotlightRooms
=
new
ArrayList
<>();
spotlightRooms
.
add
(
getSpotlightRoom
(
"id3"
,
"Name3"
,
"c"
));
when
(
spotlightRoomRepository
.
getSuggestionsFor
(
anyString
(),
any
(
SortDirection
.
class
),
anyInt
()))
.
thenReturn
(
Flowable
.
just
(
spotlightRooms
));
TestSubscriber
<
List
<
SpotlightRoom
>>
testSubscriber
=
new
TestSubscriber
<>();
autocompleteChannelInteractor
.
getSuggestionsFor
(
"N"
).
subscribe
(
testSubscriber
);
verify
(
tempSpotlightRoomCaller
,
times
(
1
)).
search
(
anyString
());
spotlightRooms
=
new
ArrayList
<>();
spotlightRooms
.
add
(
getSpotlightRoom
(
"id1"
,
"Name1"
,
"c"
));
spotlightRooms
.
add
(
getSpotlightRoom
(
"id2"
,
"Name2"
,
"c"
));
spotlightRooms
.
add
(
getSpotlightRoom
(
"id3"
,
"Name3"
,
"c"
));
testSubscriber
.
assertResult
(
spotlightRooms
);
}
private
Room
getRoom
(
String
id
,
String
name
,
String
type
)
{
Room
room
=
mock
(
Room
.
class
);
when
(
room
.
getId
()).
thenReturn
(
id
);
when
(
room
.
getName
()).
thenReturn
(
name
);
when
(
room
.
getType
()).
thenReturn
(
type
);
return
room
;
}
private
SpotlightRoom
getSpotlightRoom
(
String
id
,
String
name
,
String
type
)
{
return
SpotlightRoom
.
builder
()
.
setId
(
id
).
setName
(
name
).
setType
(
type
).
build
();
}
}
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment