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
f6b9138a
Commit
f6b9138a
authored
Nov 28, 2016
by
Yusuke Iwaki
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
FIX #56 implement "load more"
parent
5c6e524c
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
256 additions
and
19 deletions
+256
-19
MethodCallHelper.java
...c/main/java/chat/rocket/android/api/MethodCallHelper.java
+2
-2
RoomFragment.java
...a/chat/rocket/android/fragment/chatroom/RoomFragment.java
+64
-7
LoadMoreScrollListener.java
...va/chat/rocket/android/helper/LoadMoreScrollListener.java
+39
-0
ExtRealmModelListAdapter.java
...rocket/android/layouthelper/ExtRealmModelListAdapter.java
+74
-0
MessageListAdapter.java
...ket/android/layouthelper/chatroom/MessageListAdapter.java
+26
-4
LoadMessageProcedureObserver.java
...ndroid/service/observer/LoadMessageProcedureObserver.java
+4
-2
fragment_room.xml
app/src/main/res/layout/fragment_room.xml
+1
-1
list_item_message_header.xml
app/src/main/res/layout/list_item_message_header.xml
+7
-0
list_item_message_loading.xml
app/src/main/res/layout/list_item_message_loading.xml
+16
-0
list_item_message_start_of_conversation.xml
...in/res/layout/list_item_message_start_of_conversation.xml
+18
-0
strings.xml
app/src/main/res/values/strings.xml
+2
-0
RealmModelListAdapter.java
...at/rocket/android/realm_helper/RealmModelListAdapter.java
+3
-3
No files found.
app/src/main/java/chat/rocket/android/api/MethodCallHelper.java
View file @
f6b9138a
...
...
@@ -238,7 +238,7 @@ public class MethodCallHelper {
/**
* Load messages for room.
*/
public
Task
<
Void
>
loadHistory
(
final
String
roomId
,
final
long
timestamp
,
public
Task
<
JSONArray
>
loadHistory
(
final
String
roomId
,
final
long
timestamp
,
final
int
count
,
final
long
lastSeen
)
{
return
call
(
"loadHistory"
,
TIMEOUT_MS
,
()
->
new
JSONArray
()
.
put
(
roomId
)
...
...
@@ -261,7 +261,7 @@ public class MethodCallHelper {
realm
.
createOrUpdateAllFromJson
(
Message
.
class
,
messages
);
}
return
null
;
});
})
.
onSuccessTask
(
_task
->
Task
.
forResult
(
messages
))
;
});
}
...
...
app/src/main/java/chat/rocket/android/fragment/chatroom/RoomFragment.java
View file @
f6b9138a
...
...
@@ -5,6 +5,7 @@ import android.support.annotation.Nullable;
import
android.support.v7.widget.LinearLayoutManager
;
import
android.support.v7.widget.RecyclerView
;
import
chat.rocket.android.R
;
import
chat.rocket.android.helper.LoadMoreScrollListener
;
import
chat.rocket.android.helper.LogcatIfError
;
import
chat.rocket.android.layouthelper.chatroom.MessageListAdapter
;
import
chat.rocket.android.model.ServerConfig
;
...
...
@@ -15,10 +16,10 @@ import chat.rocket.android.model.internal.LoadMessageProcedure;
import
chat.rocket.android.realm_helper.RealmHelper
;
import
chat.rocket.android.realm_helper.RealmObjectObserver
;
import
chat.rocket.android.realm_helper.RealmStore
;
import
io.realm.Realm
;
import
io.realm.RealmResults
;
import
chat.rocket.android.service.RocketChatService
;
import
io.realm.Sort
;
import
org.json.JSONObject
;
import
timber.log.Timber
;
/**
* Chat room screen.
...
...
@@ -29,6 +30,8 @@ public class RoomFragment extends AbstractChatRoomFragment {
private
String
roomId
;
private
RealmObjectObserver
<
RoomSubscription
>
roomObserver
;
private
String
hostname
;
private
LoadMoreScrollListener
scrollListener
;
private
RealmObjectObserver
<
LoadMessageProcedure
>
procedureObserver
;
/**
* create fragment with roomId.
...
...
@@ -61,7 +64,13 @@ public class RoomFragment extends AbstractChatRoomFragment {
.
createObjectObserver
(
realm
->
realm
.
where
(
RoomSubscription
.
class
).
equalTo
(
"rid"
,
roomId
))
.
setOnUpdateListener
(
this
::
onRenderRoom
);
initialRequest
();
procedureObserver
=
realmHelper
.
createObjectObserver
(
realm
->
realm
.
where
(
LoadMessageProcedure
.
class
).
equalTo
(
"roomId"
,
roomId
))
.
setOnUpdateListener
(
this
::
onUpdateLoadMessageProcedure
);
if
(
savedInstanceState
==
null
)
{
initialRequest
();
}
}
@Override
protected
int
getLayout
()
{
...
...
@@ -77,36 +86,84 @@ public class RoomFragment extends AbstractChatRoomFragment {
context
->
new
MessageListAdapter
(
context
,
hostname
)
));
RecyclerView
.
LayoutManager
layoutManager
=
new
LinearLayoutManager
(
getContext
(),
Linear
LayoutManager
layoutManager
=
new
LinearLayoutManager
(
getContext
(),
LinearLayoutManager
.
VERTICAL
,
true
);
listView
.
setLayoutManager
(
layoutManager
);
scrollListener
=
new
LoadMoreScrollListener
(
layoutManager
,
40
)
{
@Override
public
void
requestMoreItem
()
{
loadMoreRequest
();
}
};
listView
.
addOnScrollListener
(
scrollListener
);
}
private
void
onRenderRoom
(
RoomSubscription
roomSubscription
)
{
activityToolbar
.
setTitle
(
roomSubscription
.
getName
());
}
private
void
onUpdateLoadMessageProcedure
(
LoadMessageProcedure
procedure
)
{
if
(
procedure
==
null
)
{
return
;
}
RecyclerView
listView
=
(
RecyclerView
)
rootView
.
findViewById
(
R
.
id
.
recyclerview
);
if
(
listView
!=
null
&&
listView
.
getAdapter
()
instanceof
MessageListAdapter
)
{
MessageListAdapter
adapter
=
(
MessageListAdapter
)
listView
.
getAdapter
();
final
int
syncstate
=
procedure
.
getSyncstate
();
final
boolean
hasNext
=
procedure
.
isHasNext
();
Timber
.
d
(
"hasNext: %s syncstate: %d"
,
hasNext
,
syncstate
);
if
(
syncstate
==
SyncState
.
SYNCED
||
syncstate
==
SyncState
.
FAILED
)
{
scrollListener
.
setLoadingDone
();
adapter
.
updateFooter
(
hasNext
,
true
);
}
else
{
adapter
.
updateFooter
(
hasNext
,
false
);
}
}
}
private
void
initialRequest
()
{
realmHelper
.
executeTransaction
(
realm
->
{
realm
.
createOrUpdateObjectFromJson
(
LoadMessageProcedure
.
class
,
new
JSONObject
()
.
put
(
"roomId"
,
roomId
)
.
put
(
"syncstate"
,
SyncState
.
NOT_SYNCED
)
.
put
(
"count"
,
5
0
)
.
put
(
"count"
,
10
0
)
.
put
(
"reset"
,
true
));
return
null
;
}).
onSuccessTask
(
task
->
{
RocketChatService
.
keepalive
(
getContext
());
return
task
;
}).
continueWith
(
new
LogcatIfError
());
}
private
RealmResults
<
Message
>
queryItems
(
Realm
realm
)
{
return
realm
.
where
(
Message
.
class
).
equalTo
(
"rid"
,
roomId
).
findAllSorted
(
"ts"
);
private
void
loadMoreRequest
()
{
realmHelper
.
executeTransaction
(
realm
->
{
LoadMessageProcedure
procedure
=
realm
.
where
(
LoadMessageProcedure
.
class
)
.
equalTo
(
"roomId"
,
roomId
)
.
beginGroup
()
.
equalTo
(
"syncstate"
,
SyncState
.
SYNCED
)
.
or
()
.
equalTo
(
"syncstate"
,
SyncState
.
FAILED
)
.
endGroup
()
.
equalTo
(
"hasNext"
,
true
)
.
findFirst
();
if
(
procedure
!=
null
)
{
procedure
.
setSyncstate
(
SyncState
.
NOT_SYNCED
);
}
return
null
;
}).
onSuccessTask
(
task
->
{
RocketChatService
.
keepalive
(
getContext
());
return
task
;
}).
continueWith
(
new
LogcatIfError
());
}
@Override
public
void
onResume
()
{
super
.
onResume
();
roomObserver
.
sub
();
procedureObserver
.
sub
();
}
@Override
public
void
onPause
()
{
procedureObserver
.
unsub
();
roomObserver
.
unsub
();
super
.
onPause
();
}
...
...
app/src/main/java/chat/rocket/android/helper/LoadMoreScrollListener.java
0 → 100644
View file @
f6b9138a
package
chat
.
rocket
.
android
.
helper
;
import
android.support.v7.widget.LinearLayoutManager
;
import
android.support.v7.widget.RecyclerView
;
public
abstract
class
LoadMoreScrollListener
extends
RecyclerView
.
OnScrollListener
{
private
final
LinearLayoutManager
layoutManager
;
private
final
int
loadThreshold
;
private
boolean
isLoading
;
public
LoadMoreScrollListener
(
LinearLayoutManager
layoutManager
,
int
loadThreshold
)
{
this
.
layoutManager
=
layoutManager
;
this
.
loadThreshold
=
loadThreshold
;
setLoadingDone
();
}
@Override
public
void
onScrolled
(
RecyclerView
recyclerView
,
int
dx
,
int
dy
)
{
super
.
onScrolled
(
recyclerView
,
dx
,
dy
);
final
int
visibleItemCount
=
recyclerView
.
getChildCount
();
final
int
totalItemCount
=
layoutManager
.
getItemCount
();
final
int
firstVisibleItem
=
layoutManager
.
findFirstVisibleItemPosition
();
if
(!
isLoading
&&
firstVisibleItem
+
visibleItemCount
>=
totalItemCount
-
loadThreshold
&&
visibleItemCount
<
totalItemCount
&&
dy
<
0
)
{
isLoading
=
true
;
requestMoreItem
();
}
}
public
void
setLoadingDone
()
{
isLoading
=
false
;
}
public
abstract
void
requestMoreItem
();
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/layouthelper/ExtRealmModelListAdapter.java
0 → 100644
View file @
f6b9138a
package
chat
.
rocket
.
android
.
layouthelper
;
import
android.content.Context
;
import
android.support.annotation.LayoutRes
;
import
chat.rocket.android.realm_helper.RealmModelListAdapter
;
import
chat.rocket.android.realm_helper.RealmModelViewHolder
;
import
io.realm.RealmObject
;
/**
* RealmModelListAdapter with header and footer.
*/
public
abstract
class
ExtRealmModelListAdapter
<
T
extends
RealmObject
,
VM
,
VH
extends
RealmModelViewHolder
<
VM
>>
extends
RealmModelListAdapter
<
T
,
VM
,
VH
>
{
protected
static
final
int
VIEW_TYPE_HEADER
=
-
1
;
protected
static
final
int
VIEW_TYPE_FOOTER
=
-
2
;
protected
ExtRealmModelListAdapter
(
Context
context
)
{
super
(
context
);
}
@Override
public
int
getItemCount
()
{
return
super
.
getItemCount
()
+
2
;
}
protected
void
notifyHeaderChanged
()
{
notifyItemChanged
(
0
);
}
protected
void
notifyFooterChanged
()
{
notifyItemChanged
(
super
.
getItemCount
()
+
1
);
}
protected
void
notifyRealmModelItemChanged
(
int
position
)
{
notifyItemChanged
(
position
+
1
);
}
@Override
public
int
getItemViewType
(
int
position
)
{
if
(
position
==
0
)
{
return
VIEW_TYPE_HEADER
;
}
if
(
position
==
super
.
getItemCount
()
+
1
)
{
return
VIEW_TYPE_FOOTER
;
}
// rely on getRealmModelViewType(VM model).
return
super
.
getItemViewType
(
position
-
1
);
}
protected
abstract
@LayoutRes
int
getHeaderLayout
();
protected
abstract
@LayoutRes
int
getFooterLayout
();
protected
abstract
@LayoutRes
int
getRealmModelLayout
(
int
viewType
);
@Override
protected
final
int
getLayout
(
int
viewType
)
{
if
(
viewType
==
VIEW_TYPE_HEADER
)
{
return
getHeaderLayout
();
}
if
(
viewType
==
VIEW_TYPE_FOOTER
)
{
return
getFooterLayout
();
}
return
getRealmModelLayout
(
viewType
);
}
@Override
public
final
void
onBindViewHolder
(
VH
holder
,
int
position
)
{
if
(
position
==
0
||
position
==
super
.
getItemCount
()
+
1
)
{
return
;
}
// rely on VH.bind().
super
.
onBindViewHolder
(
holder
,
position
-
1
);
}
}
app/src/main/java/chat/rocket/android/layouthelper/chatroom/MessageListAdapter.java
View file @
f6b9138a
...
...
@@ -3,8 +3,8 @@ package chat.rocket.android.layouthelper.chatroom;
import
android.content.Context
;
import
android.view.View
;
import
chat.rocket.android.R
;
import
chat.rocket.android.layouthelper.ExtRealmModelListAdapter
;
import
chat.rocket.android.model.ddp.Message
;
import
chat.rocket.android.realm_helper.RealmModelListAdapter
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.List
;
...
...
@@ -13,20 +13,42 @@ import java.util.List;
* target list adapter for chat room.
*/
public
class
MessageListAdapter
extends
RealmModelListAdapter
<
Message
,
PairedMessage
,
MessageViewHolder
>
{
extends
ExtRealmModelListAdapter
<
Message
,
PairedMessage
,
MessageViewHolder
>
{
private
final
String
hostname
;
private
boolean
hasNext
;
private
boolean
isLoaded
;
public
MessageListAdapter
(
Context
context
,
String
hostname
)
{
super
(
context
);
this
.
hostname
=
hostname
;
}
/**
* update Footer state considering hasNext and isLoaded.
*/
public
void
updateFooter
(
boolean
hasNext
,
boolean
isLoaded
)
{
this
.
hasNext
=
hasNext
;
this
.
isLoaded
=
isLoaded
;
notifyFooterChanged
();
}
@Override
protected
int
getHeaderLayout
()
{
return
R
.
layout
.
list_item_message_header
;
}
@Override
protected
int
getFooterLayout
()
{
if
(!
hasNext
||
isLoaded
)
{
return
R
.
layout
.
list_item_message_start_of_conversation
;
}
else
{
return
R
.
layout
.
list_item_message_loading
;
}
}
@Override
protected
int
getRealmModelViewType
(
PairedMessage
model
)
{
return
0
;
}
@Override
protected
int
getLayout
(
int
viewType
)
{
@Override
protected
int
get
RealmModel
Layout
(
int
viewType
)
{
return
R
.
layout
.
list_item_message
;
}
...
...
app/src/main/java/chat/rocket/android/service/observer/LoadMessageProcedureObserver.java
View file @
f6b9138a
...
...
@@ -57,14 +57,16 @@ public class LoadMessageProcedureObserver extends AbstractModelObserver<LoadMess
realm
.
where
(
Message
.
class
)
.
equalTo
(
"rid"
,
roomId
)
.
equalTo
(
"syncstate"
,
SyncState
.
SYNCED
)
.
findAllSorted
(
"ts"
,
Sort
.
ASCENDING
).
la
st
(
null
));
.
findAllSorted
(
"ts"
,
Sort
.
ASCENDING
).
fir
st
(
null
));
long
lastTs
=
lastMessage
!=
null
?
lastMessage
.
getTs
()
:
0
;
int
messageCount
=
_task
.
getResult
().
length
();
return
realmHelper
.
executeTransaction
(
realm
->
realm
.
createOrUpdateObjectFromJson
(
LoadMessageProcedure
.
class
,
new
JSONObject
()
.
put
(
"roomId"
,
roomId
)
.
put
(
"syncstate"
,
SyncState
.
SYNCED
)
.
put
(
"timestamp"
,
lastTs
)
.
put
(
"hasNext"
,
lastTs
>
0
)));
.
put
(
"reset"
,
false
)
.
put
(
"hasNext"
,
messageCount
==
count
)));
})
).
continueWithTask
(
task
->
{
if
(
task
.
isFaulted
())
{
...
...
app/src/main/res/layout/fragment_room.xml
View file @
f6b9138a
...
...
@@ -10,7 +10,7 @@
/>
<android.support.design.widget.FloatingActionButton
android:id=
"@+id/
btn
_compose"
android:id=
"@+id/
fab
_compose"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_gravity=
"end|bottom"
...
...
app/src/main/res/layout/list_item_message_header.xml
0 → 100644
View file @
f6b9138a
<?xml version="1.0" encoding="utf-8"?>
<Space
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:id=
"@+id/space"
android:layout_width=
"match_parent"
android:layout_height=
"88dp"
/>
\ No newline at end of file
app/src/main/res/layout/list_item_message_loading.xml
0 → 100644
View file @
f6b9138a
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:orientation=
"vertical"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:theme=
"@style/AppTheme"
>
<chat.rocket.android.widget.WaitingView
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_gravity=
"center"
android:layout_margin=
"@dimen/margin_8"
/>
</FrameLayout>
\ No newline at end of file
app/src/main/res/layout/list_item_message_start_of_conversation.xml
0 → 100644
View file @
f6b9138a
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:orientation=
"vertical"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:theme=
"@style/AppTheme"
>
<TextView
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_margin=
"@dimen/margin_16"
android:text=
"@string/start_of_conversation"
android:textAppearance=
"@style/TextAppearance.AppCompat.Body1"
android:layout_gravity=
"center"
/>
</FrameLayout>
\ No newline at end of file
app/src/main/res/values/strings.xml
View file @
f6b9138a
...
...
@@ -7,4 +7,6 @@
<string
name=
"user_status_busy"
>
Busy
</string>
<string
name=
"user_status_invisible"
>
Invisible
</string>
<string
name=
"fragment_sidebar_main_logout_title"
>
Logout
</string>
<string
name=
"start_of_conversation"
>
Start of conversation
</string>
</resources>
realm-helpers/src/main/java/chat/rocket/android/realm_helper/RealmModelListAdapter.java
View file @
f6b9138a
...
...
@@ -16,7 +16,7 @@ public abstract class RealmModelListAdapter<T extends RealmObject, VM,
RealmModelListAdapter
<
T
,
VM
,
VH
>
getNewInstance
(
Context
context
);
}
pr
ivate
final
LayoutInflater
inflater
;
pr
otected
final
LayoutInflater
inflater
;
private
RealmListObserver
<
T
>
realmListObserver
;
private
List
<
VM
>
adapterData
;
...
...
@@ -54,11 +54,11 @@ public abstract class RealmModelListAdapter<T extends RealmObject, VM,
protected
abstract
List
<
VM
>
mapResultsToViewModel
(
List
<
T
>
results
);
@Override
public
final
int
getItemViewType
(
int
position
)
{
@Override
public
int
getItemViewType
(
int
position
)
{
return
getRealmModelViewType
(
getItem
(
position
));
}
@Override
public
VH
onCreateViewHolder
(
ViewGroup
parent
,
int
viewType
)
{
@Override
public
final
VH
onCreateViewHolder
(
ViewGroup
parent
,
int
viewType
)
{
View
itemView
=
inflater
.
inflate
(
getLayout
(
viewType
),
parent
,
false
);
return
onCreateRealmModelViewHolder
(
viewType
,
itemView
);
}
...
...
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