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
dd9f79dd
Commit
dd9f79dd
authored
Dec 16, 2016
by
Yusuke Iwaki
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
upload file to S3
parent
c4b60e82
Changes
19
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
832 additions
and
20 deletions
+832
-20
FileUploadingHelper.java
...ain/java/chat/rocket/android/api/FileUploadingHelper.java
+40
-0
MethodCallHelper.java
...c/main/java/chat/rocket/android/api/MethodCallHelper.java
+29
-10
RoomFragment.java
...a/chat/rocket/android/fragment/chatroom/RoomFragment.java
+46
-1
FileUploadProgressDialogFragment.java
...ent/chatroom/dialog/FileUploadProgressDialogFragment.java
+94
-0
OkHttpHelper.java
...rc/main/java/chat/rocket/android/helper/OkHttpHelper.java
+10
-0
FileUploadHelper.java
...ocket/android/layouthelper/chatroom/FileUploadHelper.java
+94
-0
MessageComposerManager.java
...android/layouthelper/chatroom/MessageComposerManager.java
+26
-8
PublicSetting.java
...ain/java/chat/rocket/android/model/ddp/PublicSetting.java
+30
-0
FileUploading.java
...ava/chat/rocket/android/model/internal/FileUploading.java
+103
-0
FileUploadingRenderer.java
...a/chat/rocket/android/renderer/FileUploadingRenderer.java
+55
-0
RocketChatWebSocketThread.java
...hat/rocket/android/service/RocketChatWebSocketThread.java
+3
-1
S3FileUploadingObserver.java
...ket/android/service/observer/S3FileUploadingObserver.java
+178
-0
SessionObserver.java
...chat/rocket/android/service/observer/SessionObserver.java
+5
-0
ic_insert_photo_white_24dp.xml
app/src/main/res/drawable/ic_insert_photo_white_24dp.xml
+10
-0
progress_bar.xml
app/src/main/res/drawable/progress_bar.xml
+28
-0
dialog_file_uploading.xml
app/src/main/res/layout/dialog_file_uploading.xml
+64
-0
fragment_room_main.xml
app/src/main/res/layout/fragment_room_main.xml
+10
-0
strings.xml
app/src/main/res/values/strings.xml
+2
-0
styles.xml
app/src/main/res/values/styles.xml
+5
-0
No files found.
app/src/main/java/chat/rocket/android/api/FileUploadingHelper.java
0 → 100644
View file @
dd9f79dd
package
chat
.
rocket
.
android
.
api
;
import
android.content.Context
;
import
bolts.Task
;
import
chat.rocket.android.realm_helper.RealmHelper
;
import
org.json.JSONArray
;
import
org.json.JSONObject
;
/**
* MethodCall for uploading file.
*/
public
class
FileUploadingHelper
extends
MethodCallHelper
{
public
FileUploadingHelper
(
Context
context
,
String
serverConfigId
)
{
super
(
context
,
serverConfigId
);
}
public
FileUploadingHelper
(
RealmHelper
realmHelper
,
DDPClientWraper
ddpClient
)
{
super
(
realmHelper
,
ddpClient
);
}
public
Task
<
JSONObject
>
uploadRequest
(
String
filename
,
long
filesize
,
String
mimeType
,
String
roomId
)
{
return
call
(
"slingshot/uploadRequest"
,
TIMEOUT_MS
,
()
->
new
JSONArray
()
.
put
(
"rocketchat-uploads"
)
.
put
(
new
JSONObject
()
.
put
(
"name"
,
filename
)
.
put
(
"size"
,
filesize
)
.
put
(
"type"
,
mimeType
))
.
put
(
new
JSONObject
().
put
(
"rid"
,
roomId
)))
.
onSuccessTask
(
CONVERT_TO_JSON_OBJECT
);
}
public
Task
<
JSONObject
>
sendFileMessage
(
String
roomId
,
String
repository
,
JSONObject
fileObj
)
{
return
call
(
"sendFileMessage"
,
TIMEOUT_MS
,
()
->
new
JSONArray
()
.
put
(
roomId
)
.
put
(
repository
)
.
put
(
fileObj
))
.
onSuccessTask
(
CONVERT_TO_JSON_OBJECT
);
}
}
app/src/main/java/chat/rocket/android/api/MethodCallHelper.java
View file @
dd9f79dd
...
...
@@ -8,6 +8,7 @@ import chat.rocket.android.helper.CheckSum;
import
chat.rocket.android.helper.TextUtils
;
import
chat.rocket.android.model.SyncState
;
import
chat.rocket.android.model.ddp.Message
;
import
chat.rocket.android.model.ddp.PublicSetting
;
import
chat.rocket.android.model.ddp.RoomSubscription
;
import
chat.rocket.android.model.internal.MethodCall
;
import
chat.rocket.android.model.internal.Session
;
...
...
@@ -26,10 +27,10 @@ import org.json.JSONObject;
*/
public
class
MethodCallHelper
{
pr
ivate
final
Context
context
;
pr
ivate
final
RealmHelper
realmHelper
;
pr
ivate
final
DDPClientWraper
ddpClient
;
pr
ivate
static
final
long
TIMEOUT_MS
=
4000
;
pr
otected
final
Context
context
;
pr
otected
final
RealmHelper
realmHelper
;
pr
otected
final
DDPClientWraper
ddpClient
;
pr
otected
static
final
long
TIMEOUT_MS
=
4000
;
@Deprecated
/**
...
...
@@ -92,15 +93,15 @@ public class MethodCallHelper {
});
}
pr
ivate
interface
ParamBuilder
{
pr
otected
interface
ParamBuilder
{
JSONArray
buildParam
()
throws
JSONException
;
}
pr
ivate
Task
<
String
>
call
(
String
methodName
,
long
timeout
)
{
pr
otected
final
Task
<
String
>
call
(
String
methodName
,
long
timeout
)
{
return
injectErrorHandler
(
executeMethodCall
(
methodName
,
null
,
timeout
));
}
pr
ivate
Task
<
String
>
call
(
String
methodName
,
long
timeout
,
ParamBuilder
paramBuilder
)
{
pr
otected
final
Task
<
String
>
call
(
String
methodName
,
long
timeout
,
ParamBuilder
paramBuilder
)
{
try
{
final
JSONArray
params
=
paramBuilder
.
buildParam
();
return
injectErrorHandler
(
executeMethodCall
(
methodName
,
...
...
@@ -110,10 +111,10 @@ public class MethodCallHelper {
}
}
pr
ivate
static
final
Continuation
<
String
,
Task
<
JSONObject
>>
CONVERT_TO_JSON_OBJECT
=
pr
otected
static
final
Continuation
<
String
,
Task
<
JSONObject
>>
CONVERT_TO_JSON_OBJECT
=
task
->
Task
.
forResult
(
new
JSONObject
(
task
.
getResult
()));
pr
ivate
static
final
Continuation
<
String
,
Task
<
JSONArray
>>
CONVERT_TO_JSON_ARRAY
=
pr
otected
static
final
Continuation
<
String
,
Task
<
JSONArray
>>
CONVERT_TO_JSON_ARRAY
=
task
->
Task
.
forResult
(
new
JSONArray
(
task
.
getResult
()));
/**
...
...
@@ -321,7 +322,7 @@ public class MethodCallHelper {
/**
* Send message object.
*/
p
ublic
Task
<
JSONObject
>
sendMessage
(
final
JSONObject
messageJson
)
{
p
rivate
Task
<
JSONObject
>
sendMessage
(
final
JSONObject
messageJson
)
{
return
call
(
"sendMessage"
,
TIMEOUT_MS
,
()
->
new
JSONArray
().
put
(
messageJson
))
.
onSuccessTask
(
CONVERT_TO_JSON_OBJECT
)
.
onSuccessTask
(
task
->
Task
.
forResult
(
Message
.
customizeJson
(
task
.
getResult
())));
...
...
@@ -334,4 +335,22 @@ public class MethodCallHelper {
return
call
(
"readMessages"
,
TIMEOUT_MS
,
()
->
new
JSONArray
().
put
(
roomId
))
.
onSuccessTask
(
task
->
Task
.
forResult
(
null
));
}
public
Task
<
Void
>
getPublicSettings
()
{
return
call
(
"public-settings/get"
,
TIMEOUT_MS
)
.
onSuccessTask
(
CONVERT_TO_JSON_ARRAY
)
.
onSuccessTask
(
task
->
{
final
JSONArray
settings
=
task
.
getResult
();
for
(
int
i
=
0
;
i
<
settings
.
length
();
i
++)
{
PublicSetting
.
customizeJson
(
settings
.
getJSONObject
(
i
));
}
return
realmHelper
.
executeTransaction
(
realm
->
{
realm
.
delete
(
PublicSetting
.
class
);
realm
.
createOrUpdateAllFromJson
(
PublicSetting
.
class
,
settings
);
return
null
;
});
});
}
}
app/src/main/java/chat/rocket/android/fragment/chatroom/RoomFragment.java
View file @
dd9f79dd
package
chat
.
rocket
.
android
.
fragment
.
chatroom
;
import
android.app.Activity
;
import
android.content.Intent
;
import
android.os.Bundle
;
import
android.support.annotation.Nullable
;
import
android.support.design.widget.FloatingActionButton
;
...
...
@@ -12,10 +14,13 @@ import android.support.v7.widget.RecyclerView;
import
android.view.View
;
import
chat.rocket.android.R
;
import
chat.rocket.android.api.MethodCallHelper
;
import
chat.rocket.android.fragment.chatroom.dialog.FileUploadProgressDialogFragment
;
import
chat.rocket.android.fragment.chatroom.dialog.UsersOfRoomDialogFragment
;
import
chat.rocket.android.helper.LoadMoreScrollListener
;
import
chat.rocket.android.helper.LogcatIfError
;
import
chat.rocket.android.helper.OnBackPressListener
;
import
chat.rocket.android.helper.TextUtils
;
import
chat.rocket.android.layouthelper.chatroom.FileUploadHelper
;
import
chat.rocket.android.layouthelper.chatroom.MessageComposerManager
;
import
chat.rocket.android.layouthelper.chatroom.MessageListAdapter
;
import
chat.rocket.android.layouthelper.chatroom.PairedMessage
;
...
...
@@ -45,6 +50,8 @@ import org.json.JSONObject;
public
class
RoomFragment
extends
AbstractChatRoomFragment
implements
OnBackPressListener
,
RealmModelListAdapter
.
OnItemClickListener
<
PairedMessage
>
{
private
static
final
int
RC_UPL
=
0x12
;
private
String
serverConfigId
;
private
RealmHelper
realmHelper
;
private
String
roomId
;
...
...
@@ -128,6 +135,7 @@ public class RoomFragment extends AbstractChatRoomFragment
setupSideMenu
();
setupMessageComposer
();
setupFileUploader
();
}
@Override
public
void
onItemClick
(
PairedMessage
pairedMessage
)
{
...
...
@@ -196,7 +204,7 @@ public class RoomFragment extends AbstractChatRoomFragment
final
MessageComposer
messageComposer
=
(
MessageComposer
)
rootView
.
findViewById
(
R
.
id
.
message_composer
);
messageComposerManager
=
new
MessageComposerManager
(
fabCompose
,
messageComposer
);
messageComposerManager
.
setCallback
(
messageText
->
messageComposerManager
.
set
SendMessage
Callback
(
messageText
->
realmHelper
.
executeTransaction
(
realm
->
realm
.
createOrUpdateObjectFromJson
(
Message
.
class
,
new
JSONObject
()
.
put
(
"_id"
,
UUID
.
randomUUID
().
toString
())
...
...
@@ -204,6 +212,43 @@ public class RoomFragment extends AbstractChatRoomFragment
.
put
(
"ts"
,
System
.
currentTimeMillis
())
.
put
(
"rid"
,
roomId
)
.
put
(
"msg"
,
messageText
))));
messageComposerManager
.
setVisibilityChangedListener
(
shown
->
{
FloatingActionButton
fab
=
(
FloatingActionButton
)
rootView
.
findViewById
(
R
.
id
.
fab_upload_file
);
if
(
shown
)
{
fab
.
hide
();
}
else
{
fab
.
show
();
}
});
}
private
void
setupFileUploader
()
{
rootView
.
findViewById
(
R
.
id
.
fab_upload_file
).
setOnClickListener
(
view
->
{
Intent
intent
=
new
Intent
();
intent
.
setType
(
"image/*"
);
intent
.
setAction
(
Intent
.
ACTION_GET_CONTENT
);
startActivityForResult
(
Intent
.
createChooser
(
intent
,
"Select Picture to Upload"
),
RC_UPL
);
});
}
@Override
public
void
onActivityResult
(
int
requestCode
,
int
resultCode
,
Intent
data
)
{
super
.
onActivityResult
(
requestCode
,
resultCode
,
data
);
if
(
requestCode
!=
RC_UPL
||
resultCode
!=
Activity
.
RESULT_OK
)
{
return
;
}
if
(
data
==
null
||
data
.
getData
()
==
null
)
{
return
;
}
String
uplId
=
new
FileUploadHelper
(
getContext
(),
realmHelper
,
roomId
)
.
requestUploading
(
data
.
getData
());
if
(!
TextUtils
.
isEmpty
(
uplId
))
{
FileUploadProgressDialogFragment
.
create
(
serverConfigId
,
roomId
,
uplId
)
.
show
(
getFragmentManager
(),
FileUploadProgressDialogFragment
.
class
.
getSimpleName
());
}
else
{
//show error.
}
}
private
void
onRenderRoom
(
RoomSubscription
roomSubscription
)
{
...
...
app/src/main/java/chat/rocket/android/fragment/chatroom/dialog/FileUploadProgressDialogFragment.java
0 → 100644
View file @
dd9f79dd
package
chat
.
rocket
.
android
.
fragment
.
chatroom
.
dialog
;
import
android.content.DialogInterface
;
import
android.os.Bundle
;
import
android.support.annotation.NonNull
;
import
android.support.annotation.Nullable
;
import
android.widget.ProgressBar
;
import
android.widget.TextView
;
import
android.widget.Toast
;
import
chat.rocket.android.R
;
import
chat.rocket.android.model.SyncState
;
import
chat.rocket.android.model.internal.FileUploading
;
import
chat.rocket.android.realm_helper.RealmObjectObserver
;
import
chat.rocket.android.renderer.FileUploadingRenderer
;
/**
* dialog fragment to display progress of file uploading.
*/
public
class
FileUploadProgressDialogFragment
extends
AbstractChatroomDialogFragment
{
private
String
uplId
;
private
RealmObjectObserver
<
FileUploading
>
fileUploadingObserver
;
public
FileUploadProgressDialogFragment
()
{}
public
static
FileUploadProgressDialogFragment
create
(
String
serverConfigId
,
String
roomId
,
String
uplId
)
{
Bundle
args
=
new
Bundle
();
args
.
putString
(
"serverConfigId"
,
serverConfigId
);
args
.
putString
(
"roomId"
,
roomId
);
args
.
putString
(
"uplId"
,
uplId
);
FileUploadProgressDialogFragment
fragment
=
new
FileUploadProgressDialogFragment
();
fragment
.
setArguments
(
args
);
return
fragment
;
}
@Override
protected
void
handleArgs
(
@NonNull
Bundle
args
)
{
super
.
handleArgs
(
args
);
uplId
=
args
.
getString
(
"uplId"
);
}
@Override
public
void
onCreate
(
@Nullable
Bundle
savedInstanceState
)
{
super
.
onCreate
(
savedInstanceState
);
fileUploadingObserver
=
realmHelper
.
createObjectObserver
(
realm
->
realm
.
where
(
FileUploading
.
class
).
equalTo
(
"uplId"
,
uplId
))
.
setOnUpdateListener
(
this
::
onRenderFileUploadingState
);
}
@Override
protected
int
getLayout
()
{
return
R
.
layout
.
dialog_file_uploading
;
}
@Override
protected
void
onSetupDialog
()
{
}
private
void
onRenderFileUploadingState
(
FileUploading
state
)
{
if
(
state
==
null
)
{
return
;
}
int
syncstate
=
state
.
getSyncstate
();
if
(
syncstate
==
SyncState
.
SYNCED
)
{
dismiss
();
}
else
if
(
syncstate
==
SyncState
.
FAILED
)
{
Toast
.
makeText
(
getContext
(),
state
.
getError
(),
Toast
.
LENGTH_SHORT
).
show
();
//TODO: prompt retry.
dismiss
();
}
else
{
new
FileUploadingRenderer
(
getContext
(),
state
)
.
progressInto
((
ProgressBar
)
getDialog
().
findViewById
(
R
.
id
.
progressBar
))
.
progressTextInto
(
(
TextView
)
getDialog
().
findViewById
(
R
.
id
.
txt_filesize_uploaded
),
(
TextView
)
getDialog
().
findViewById
(
R
.
id
.
txt_filesize_total
));
}
}
@Override
public
void
onResume
()
{
super
.
onResume
();
fileUploadingObserver
.
sub
();
}
@Override
public
void
onPause
()
{
fileUploadingObserver
.
unsub
();
super
.
onPause
();
}
@Override
public
void
onCancel
(
DialogInterface
dialog
)
{
//TODO: should cancel uploading? or continue with showing notification with progress?
}
}
app/src/main/java/chat/rocket/android/helper/OkHttpHelper.java
View file @
dd9f79dd
...
...
@@ -8,8 +8,18 @@ import okhttp3.OkHttpClient;
* Helper class for OkHttp client.
*/
public
class
OkHttpHelper
{
private
static
OkHttpClient
sHttpClientForUplFile
;
private
static
OkHttpClient
sHttpClientForWS
;
public
static
OkHttpClient
getClientForUploadFile
()
{
if
(
sHttpClientForUplFile
==
null
)
{
sHttpClientForUplFile
=
new
OkHttpClient
.
Builder
()
.
addNetworkInterceptor
(
new
StethoInterceptor
())
.
build
();
}
return
sHttpClientForUplFile
;
}
/**
* acquire OkHttpClient instance for WebSocket connection.
*/
...
...
app/src/main/java/chat/rocket/android/layouthelper/chatroom/FileUploadHelper.java
0 → 100644
View file @
dd9f79dd
package
chat
.
rocket
.
android
.
layouthelper
.
chatroom
;
import
android.content.ContentResolver
;
import
android.content.Context
;
import
android.database.Cursor
;
import
android.net.Uri
;
import
android.os.ParcelFileDescriptor
;
import
android.provider.OpenableColumns
;
import
android.support.annotation.Nullable
;
import
android.webkit.MimeTypeMap
;
import
chat.rocket.android.helper.LogcatIfError
;
import
chat.rocket.android.log.RCLog
;
import
chat.rocket.android.model.SyncState
;
import
chat.rocket.android.model.internal.FileUploading
;
import
chat.rocket.android.realm_helper.RealmHelper
;
import
java.io.FileNotFoundException
;
import
java.io.IOException
;
import
java.util.UUID
;
import
org.json.JSONObject
;
/**
* utility class for uploading file.
*/
public
class
FileUploadHelper
{
private
final
Context
context
;
private
final
RealmHelper
realmHelper
;
private
final
String
roomId
;
public
FileUploadHelper
(
Context
context
,
RealmHelper
realmHelper
,
String
roomId
)
{
this
.
context
=
context
;
this
.
realmHelper
=
realmHelper
;
this
.
roomId
=
roomId
;
}
/**
* requestUploading file.
* returns id for observing progress.
*/
public
@Nullable
String
requestUploading
(
Uri
uri
)
{
try
(
Cursor
cursor
=
context
.
getContentResolver
().
query
(
uri
,
null
,
null
,
null
,
null
))
{
if
(
cursor
!=
null
&&
cursor
.
moveToFirst
())
{
String
filename
=
cursor
.
getString
(
cursor
.
getColumnIndex
(
OpenableColumns
.
DISPLAY_NAME
));
long
filesize
=
cursor
.
getLong
(
cursor
.
getColumnIndex
(
OpenableColumns
.
SIZE
));
String
mimeType
=
context
.
getContentResolver
().
getType
(
uri
);
return
insertRequestRecord
(
uri
,
filename
,
filesize
,
mimeType
);
}
else
if
(
ContentResolver
.
SCHEME_FILE
.
equals
(
uri
.
getScheme
()))
{
String
filename
=
uri
.
getLastPathSegment
();
long
filesize
=
detectFileSizeFor
(
uri
);
String
mimeType
=
MimeTypeMap
.
getSingleton
()
.
getMimeTypeFromExtension
(
MimeTypeMap
.
getFileExtensionFromUrl
(
uri
.
toString
()));
return
insertRequestRecord
(
uri
,
filename
,
filesize
,
mimeType
);
}
}
return
null
;
}
private
String
insertRequestRecord
(
Uri
uri
,
String
filename
,
long
filesize
,
String
mimeType
)
{
final
String
uplId
=
UUID
.
randomUUID
().
toString
();
realmHelper
.
executeTransaction
(
realm
->
realm
.
createOrUpdateObjectFromJson
(
FileUploading
.
class
,
new
JSONObject
()
.
put
(
"uplId"
,
uplId
)
.
put
(
"syncstate"
,
SyncState
.
NOT_SYNCED
)
.
put
(
"repository"
,
FileUploading
.
TO_S3
)
//TODO: should check public-settings.
.
put
(
"uri"
,
uri
.
toString
())
.
put
(
"filename"
,
filename
)
.
put
(
"filesize"
,
filesize
)
.
put
(
"mimeType"
,
mimeType
)
.
put
(
"roomId"
,
roomId
)
.
put
(
"error"
,
JSONObject
.
NULL
)
)
).
continueWith
(
new
LogcatIfError
());
return
uplId
;
}
private
long
detectFileSizeFor
(
Uri
uri
)
{
ParcelFileDescriptor
pfd
=
null
;
try
{
pfd
=
context
.
getContentResolver
().
openFileDescriptor
(
uri
,
"r"
);
return
Math
.
max
(
pfd
.
getStatSize
(),
0
);
}
catch
(
final
FileNotFoundException
exception
)
{
RCLog
.
w
(
exception
);
}
finally
{
if
(
pfd
!=
null
)
{
try
{
pfd
.
close
();
}
catch
(
final
IOException
e
)
{
// Do nothing.
}
}
}
return
-
1
;
}
}
app/src/main/java/chat/rocket/android/layouthelper/chatroom/MessageComposerManager.java
View file @
dd9f79dd
...
...
@@ -8,13 +8,18 @@ import chat.rocket.android.widget.message.MessageComposer;
* handling visibility of FAB-compose and MessageComposer.
*/
public
class
MessageComposerManager
{
public
interface
Callback
{
public
interface
SendMessage
Callback
{
Task
<
Void
>
onSubmit
(
String
messageText
);
}
public
interface
VisibilityChangedListener
{
void
onVisibilityChanged
(
boolean
shown
);
}
private
final
FloatingActionButton
fabCompose
;
private
final
MessageComposer
messageComposer
;
private
Callback
callback
;
private
SendMessageCallback
sendMessageCallback
;
private
VisibilityChangedListener
visibilityChangedListener
;
public
MessageComposerManager
(
FloatingActionButton
fabCompose
,
MessageComposer
messageComposer
)
{
this
.
fabCompose
=
fabCompose
;
...
...
@@ -29,9 +34,9 @@ public class MessageComposerManager {
messageComposer
.
setOnActionListener
(
new
MessageComposer
.
ActionListener
()
{
@Override
public
void
onSubmit
(
String
message
)
{
if
(
c
allback
!=
null
)
{
if
(
sendMessageC
allback
!=
null
)
{
messageComposer
.
setEnabled
(
false
);
c
allback
.
onSubmit
(
message
).
onSuccess
(
task
->
{
sendMessageC
allback
.
onSubmit
(
message
).
onSuccess
(
task
->
{
clearComposingText
();
return
null
;
}).
continueWith
(
task
->
{
...
...
@@ -49,8 +54,12 @@ public class MessageComposerManager {
setMessageComposerVisibility
(
false
);
}
public
void
setCallback
(
Callback
callback
)
{
this
.
callback
=
callback
;
public
void
setSendMessageCallback
(
SendMessageCallback
sendMessageCallback
)
{
this
.
sendMessageCallback
=
sendMessageCallback
;
}
public
void
setVisibilityChangedListener
(
VisibilityChangedListener
listener
)
{
this
.
visibilityChangedListener
=
listener
;
}
public
void
clearComposingText
()
{
...
...
@@ -60,9 +69,18 @@ public class MessageComposerManager {
private
void
setMessageComposerVisibility
(
boolean
show
)
{
if
(
show
)
{
fabCompose
.
hide
();
messageComposer
.
show
(
null
);
messageComposer
.
show
(()
->
{
if
(
visibilityChangedListener
!=
null
)
{
visibilityChangedListener
.
onVisibilityChanged
(
true
);
}
});
}
else
{
messageComposer
.
hide
(
fabCompose:
:
show
);
messageComposer
.
hide
(()
->
{
fabCompose
.
show
();
if
(
visibilityChangedListener
!=
null
)
{
visibilityChangedListener
.
onVisibilityChanged
(
false
);
}
});
}
}
...
...
app/src/main/java/chat/rocket/android/model/ddp/PublicSetting.java
0 → 100644
View file @
dd9f79dd
package
chat
.
rocket
.
android
.
model
.
ddp
;
import
io.realm.RealmObject
;
import
io.realm.annotations.PrimaryKey
;
import
org.json.JSONException
;
import
org.json.JSONObject
;
/**
* public setting model.
*/
@SuppressWarnings
({
"PMD.ShortClassName"
,
"PMD.ShortVariable"
,
"PMD.MethodNamingConventions"
,
"PMD.VariableNamingConventions"
})
public
class
PublicSetting
extends
RealmObject
{
@PrimaryKey
private
String
_id
;
private
String
group
;
private
String
type
;
private
String
value
;
//any type is available...!
private
long
_updatedAt
;
private
String
meta
;
//JSON
public
static
JSONObject
customizeJson
(
JSONObject
settingJson
)
throws
JSONException
{
if
(!
settingJson
.
isNull
(
"_updatedAt"
))
{
long
updatedAt
=
settingJson
.
getJSONObject
(
"_updatedAt"
).
getLong
(
"$date"
);
settingJson
.
remove
(
"_updatedAt"
);
settingJson
.
put
(
"_updatedAt"
,
updatedAt
);
}
return
settingJson
;
}
}
app/src/main/java/chat/rocket/android/model/internal/FileUploading.java
0 → 100644
View file @
dd9f79dd
package
chat
.
rocket
.
android
.
model
.
internal
;
import
io.realm.RealmObject
;
import
io.realm.annotations.PrimaryKey
;
/**
* holding statuses for uploading file.
*/
public
class
FileUploading
extends
RealmObject
{
public
static
final
int
TO_S3
=
1
;
@PrimaryKey
private
String
uplId
;
private
int
syncstate
;
private
int
repository
;
private
String
uri
;
private
String
filename
;
private
long
filesize
;
private
String
mimeType
;
private
String
roomId
;
private
long
uploadedSize
;
private
String
error
;
public
String
getUplId
()
{
return
uplId
;
}
public
void
setUplId
(
String
uplId
)
{
this
.
uplId
=
uplId
;
}
public
int
getSyncstate
()
{
return
syncstate
;
}
public
void
setSyncstate
(
int
syncstate
)
{
this
.
syncstate
=
syncstate
;
}
public
int
getRepository
()
{
return
repository
;
}
public
void
setRepository
(
int
repository
)
{
this
.
repository
=
repository
;
}
public
String
getUri
()
{
return
uri
;
}
public
void
setUri
(
String
uri
)
{
this
.
uri
=
uri
;
}
public
String
getFilename
()
{
return
filename
;
}
public
void
setFilename
(
String
filename
)
{
this
.
filename
=
filename
;
}
public
long
getFilesize
()
{
return
filesize
;
}
public
void
setFilesize
(
long
filesize
)
{
this
.
filesize
=
filesize
;
}
public
String
getMimeType
()
{
return
mimeType
;
}
public
void
setMimeType
(
String
mimeType
)
{
this
.
mimeType
=
mimeType
;
}
public
String
getRoomId
()
{
return
roomId
;
}
public
void
setRoomId
(
String
roomId
)
{
this
.
roomId
=
roomId
;
}
public
long
getUploadedSize
()
{
return
uploadedSize
;
}
public
void
setUploadedSize
(
long
uploadedSize
)
{
this
.
uploadedSize
=
uploadedSize
;
}
public
String
getError
()
{
return
error
;
}
public
void
setError
(
String
error
)
{
this
.
error
=
error
;
}
}
app/src/main/java/chat/rocket/android/renderer/FileUploadingRenderer.java
0 → 100644
View file @
dd9f79dd
package
chat
.
rocket
.
android
.
renderer
;
import
android.content.Context
;
import
android.widget.ProgressBar
;
import
android.widget.TextView
;
import
chat.rocket.android.model.internal.FileUploading
;
/**
* rendering FileUploading status.
*/
public
class
FileUploadingRenderer
extends
AbstractRenderer
<
FileUploading
>
{
public
FileUploadingRenderer
(
Context
context
,
FileUploading
object
)
{
super
(
context
,
object
);
}
public
FileUploadingRenderer
progressInto
(
ProgressBar
progressBar
)
{
if
(!
shouldHandle
(
progressBar
))
{
return
this
;
}
if
(
object
.
getFilesize
()
>=
Integer
.
MAX_VALUE
)
{
int
max
=
1000
;
int
progress
=
(
int
)
(
max
*
object
.
getUploadedSize
()
/
object
.
getFilesize
());
progressBar
.
setProgress
(
progress
);
progressBar
.
setMax
(
max
);
}
else
{
progressBar
.
setProgress
((
int
)
object
.
getUploadedSize
());
progressBar
.
setMax
((
int
)
object
.
getFilesize
());
}
return
this
;
}
public
FileUploadingRenderer
progressTextInto
(
TextView
uploadedSizeText
,
TextView
totalSizeText
)
{
if
(!
shouldHandle
(
uploadedSizeText
)
||
!
shouldHandle
(
totalSizeText
))
{
return
this
;
}
long
uploaded
=
object
.
getUploadedSize
();
long
total
=
object
.
getFilesize
();
if
(
total
<
50
*
1024
)
{
//<50KB
uploadedSizeText
.
setText
(
String
.
format
(
"%,d"
,
uploaded
));
totalSizeText
.
setText
(
String
.
format
(
"%,d"
,
total
));
}
else
if
(
total
<
8
*
1048576
)
{
//<8MB
uploadedSizeText
.
setText
(
String
.
format
(
"%,d"
,
uploaded
/
1024
));
totalSizeText
.
setText
(
String
.
format
(
"%,d KB"
,
total
/
1024
));
}
else
{
uploadedSizeText
.
setText
(
String
.
format
(
"%,d"
,
uploaded
/
1048576
));
totalSizeText
.
setText
(
String
.
format
(
"%,d MB"
,
total
/
1048576
));
}
return
this
;
}
}
app/src/main/java/chat/rocket/android/service/RocketChatWebSocketThread.java
View file @
dd9f79dd
...
...
@@ -18,6 +18,7 @@ import chat.rocket.android.service.ddp.base.ActiveUsersSubscriber;
import
chat.rocket.android.service.ddp.base.LoginServiceConfigurationSubscriber
;
import
chat.rocket.android.service.ddp.base.UserDataSubscriber
;
import
chat.rocket.android.service.observer.CurrentUserObserver
;
import
chat.rocket.android.service.observer.S3FileUploadingObserver
;
import
chat.rocket.android.service.observer.GetUsersOfRoomsProcedureObserver
;
import
chat.rocket.android.service.observer.LoadMessageProcedureObserver
;
import
chat.rocket.android.service.observer.MethodCallObserver
;
...
...
@@ -49,7 +50,8 @@ public class RocketChatWebSocketThread extends HandlerThread {
NewMessageObserver
.
class
,
CurrentUserObserver
.
class
,
ReactiveNotificationManager
.
class
,
NotificationItemObserver
.
class
NotificationItemObserver
.
class
,
S3FileUploadingObserver
.
class
};
private
final
Context
appContext
;
private
final
String
serverConfigId
;
...
...
app/src/main/java/chat/rocket/android/service/observer/S3FileUploadingObserver.java
0 → 100644
View file @
dd9f79dd
package
chat
.
rocket
.
android
.
service
.
observer
;
import
android.content.Context
;
import
android.net.Uri
;
import
bolts.Task
;
import
chat.rocket.android.api.DDPClientWraper
;
import
chat.rocket.android.api.FileUploadingHelper
;
import
chat.rocket.android.helper.LogcatIfError
;
import
chat.rocket.android.helper.OkHttpHelper
;
import
chat.rocket.android.log.RCLog
;
import
chat.rocket.android.model.SyncState
;
import
chat.rocket.android.model.internal.FileUploading
;
import
chat.rocket.android.realm_helper.RealmHelper
;
import
io.realm.Realm
;
import
io.realm.RealmResults
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.util.List
;
import
okhttp3.MediaType
;
import
okhttp3.MultipartBody
;
import
okhttp3.Request
;
import
okhttp3.RequestBody
;
import
okhttp3.Response
;
import
okio.BufferedSink
;
import
okio.Okio
;
import
okio.Source
;
import
org.json.JSONArray
;
import
org.json.JSONObject
;
/**
* execute file uploading and requesting sendMessage with attachment.
*/
public
class
S3FileUploadingObserver
extends
AbstractModelObserver
<
FileUploading
>
{
private
FileUploadingHelper
methodCall
;
public
S3FileUploadingObserver
(
Context
context
,
String
hostname
,
RealmHelper
realmHelper
,
DDPClientWraper
ddpClient
)
{
super
(
context
,
hostname
,
realmHelper
,
ddpClient
);
methodCall
=
new
FileUploadingHelper
(
realmHelper
,
ddpClient
);
realmHelper
.
executeTransaction
(
realm
->
{
// resume pending operations.
RealmResults
<
FileUploading
>
pendingUploadRequests
=
realm
.
where
(
FileUploading
.
class
)
.
equalTo
(
"syncstate"
,
SyncState
.
SYNCING
)
.
equalTo
(
"repository"
,
FileUploading
.
TO_S3
)
.
findAll
();
for
(
FileUploading
req
:
pendingUploadRequests
)
{
req
.
setSyncstate
(
SyncState
.
NOT_SYNCED
);
}
// clean up records.
realm
.
where
(
FileUploading
.
class
)
.
beginGroup
()
.
equalTo
(
"syncstate"
,
SyncState
.
SYNCED
)
.
or
()
.
equalTo
(
"syncstate"
,
SyncState
.
FAILED
)
.
endGroup
()
.
equalTo
(
"repository"
,
FileUploading
.
TO_S3
)
.
findAll
().
deleteAllFromRealm
();
return
null
;
}).
continueWith
(
new
LogcatIfError
());
}
@Override
public
RealmResults
<
FileUploading
>
queryItems
(
Realm
realm
)
{
return
realm
.
where
(
FileUploading
.
class
)
.
equalTo
(
"syncstate"
,
SyncState
.
NOT_SYNCED
)
.
equalTo
(
"repository"
,
FileUploading
.
TO_S3
)
.
findAll
();
}
@Override
public
void
onUpdateResults
(
List
<
FileUploading
>
results
)
{
if
(
results
.
isEmpty
())
{
return
;
}
List
<
FileUploading
>
uploadingList
=
realmHelper
.
executeTransactionForReadResults
(
realm
->
realm
.
where
(
FileUploading
.
class
).
equalTo
(
"syncstate"
,
SyncState
.
SYNCING
).
findAll
());
if
(
uploadingList
.
size
()
>=
3
)
{
// do not upload more than 3 files simultaneously
return
;
}
FileUploading
fileUploading
=
results
.
get
(
0
);
final
String
roomId
=
fileUploading
.
getRoomId
();
final
String
uplId
=
fileUploading
.
getUplId
();
final
String
filename
=
fileUploading
.
getFilename
();
final
long
filesize
=
fileUploading
.
getFilesize
();
final
String
mimeType
=
fileUploading
.
getMimeType
();
final
Uri
fileUri
=
Uri
.
parse
(
fileUploading
.
getUri
());
realmHelper
.
executeTransaction
(
realm
->
realm
.
createOrUpdateObjectFromJson
(
FileUploading
.
class
,
new
JSONObject
()
.
put
(
"uplId"
,
uplId
)
.
put
(
"syncstate"
,
SyncState
.
SYNCING
)
)
).
onSuccessTask
(
_task
->
methodCall
.
uploadRequest
(
filename
,
filesize
,
mimeType
,
roomId
)
).
onSuccessTask
(
task
->
{
final
JSONObject
info
=
task
.
getResult
();
final
String
uploadUrl
=
info
.
getString
(
"upload"
);
final
String
downloadUrl
=
info
.
getString
(
"download"
);
final
JSONArray
postDataList
=
info
.
getJSONArray
(
"postData"
);
MultipartBody
.
Builder
bodyBuilder
=
new
MultipartBody
.
Builder
()
.
setType
(
MultipartBody
.
FORM
);
for
(
int
i
=
0
;
i
<
postDataList
.
length
();
i
++)
{
JSONObject
postData
=
postDataList
.
getJSONObject
(
i
);
bodyBuilder
.
addFormDataPart
(
postData
.
getString
(
"name"
),
postData
.
getString
(
"value"
));
}
bodyBuilder
.
addFormDataPart
(
"file"
,
filename
,
new
RequestBody
()
{
private
long
numBytes
=
0
;
@Override
public
MediaType
contentType
()
{
return
MediaType
.
parse
(
mimeType
);
}
@Override
public
long
contentLength
()
throws
IOException
{
return
filesize
;
}
@Override
public
void
writeTo
(
BufferedSink
sink
)
throws
IOException
{
InputStream
inputStream
=
context
.
getContentResolver
().
openInputStream
(
fileUri
);
try
(
Source
source
=
Okio
.
source
(
inputStream
))
{
long
readBytes
;
while
((
readBytes
=
source
.
read
(
sink
.
buffer
(),
8192
))
>
0
)
{
numBytes
+=
readBytes
;
realmHelper
.
executeTransaction
(
realm
->
realm
.
createOrUpdateObjectFromJson
(
FileUploading
.
class
,
new
JSONObject
()
.
put
(
"uplId"
,
uplId
)
.
put
(
"uploadedSize"
,
numBytes
)))
.
continueWith
(
new
LogcatIfError
());
}
}
}
});
Request
request
=
new
Request
.
Builder
()
.
url
(
uploadUrl
)
.
post
(
bodyBuilder
.
build
())
.
build
();
Response
response
=
OkHttpHelper
.
getClientForUploadFile
().
newCall
(
request
).
execute
();
if
(
response
.
isSuccessful
())
{
return
Task
.
forResult
(
downloadUrl
);
}
else
{
return
Task
.
forError
(
new
Exception
(
response
.
message
()));
}
}).
onSuccessTask
(
task
->
{
String
downloadUrl
=
task
.
getResult
();
return
methodCall
.
sendFileMessage
(
roomId
,
"s3"
,
new
JSONObject
()
.
put
(
"_id"
,
Uri
.
parse
(
downloadUrl
).
getLastPathSegment
())
.
put
(
"type"
,
mimeType
)
.
put
(
"size"
,
filesize
)
.
put
(
"name"
,
filename
)
.
put
(
"url"
,
downloadUrl
)
);
}).
onSuccessTask
(
task
->
realmHelper
.
executeTransaction
(
realm
->
realm
.
createOrUpdateObjectFromJson
(
FileUploading
.
class
,
new
JSONObject
()
.
put
(
"uplId"
,
uplId
)
.
put
(
"syncstate"
,
SyncState
.
SYNCED
)
.
put
(
"error"
,
JSONObject
.
NULL
)
)
)).
continueWithTask
(
task
->
{
if
(
task
.
isFaulted
())
{
RCLog
.
w
(
task
.
getError
());
return
realmHelper
.
executeTransaction
(
realm
->
realm
.
createOrUpdateObjectFromJson
(
FileUploading
.
class
,
new
JSONObject
()
.
put
(
"uplId"
,
uplId
)
.
put
(
"syncstate"
,
SyncState
.
FAILED
)
.
put
(
"error"
,
task
.
getError
().
getMessage
())
));
}
else
{
return
Task
.
forResult
(
null
);
}
});
}
}
app/src/main/java/chat/rocket/android/service/observer/SessionObserver.java
View file @
dd9f79dd
...
...
@@ -2,7 +2,9 @@ package chat.rocket.android.service.observer;
import
android.content.Context
;
import
chat.rocket.android.api.DDPClientWraper
;
import
chat.rocket.android.api.MethodCallHelper
;
import
chat.rocket.android.helper.LogcatIfError
;
import
chat.rocket.android.model.ddp.PublicSetting
;
import
chat.rocket.android.model.internal.GetUsersOfRoomsProcedure
;
import
chat.rocket.android.model.internal.LoadMessageProcedure
;
import
chat.rocket.android.model.internal.MethodCall
;
...
...
@@ -62,6 +64,8 @@ public class SessionObserver extends AbstractModelObserver<Session> {
@DebugLog
private
void
onLogin
()
{
streamNotifyMessage
.
register
();
new
MethodCallHelper
(
realmHelper
,
ddpClient
).
getPublicSettings
()
.
continueWith
(
new
LogcatIfError
());
}
@DebugLog
private
void
onLogout
()
{
...
...
@@ -69,6 +73,7 @@ public class SessionObserver extends AbstractModelObserver<Session> {
realmHelper
.
executeTransaction
(
realm
->
{
// remove all tables. ONLY INTERNAL TABLES!.
realm
.
delete
(
PublicSetting
.
class
);
realm
.
delete
(
MethodCall
.
class
);
realm
.
delete
(
LoadMessageProcedure
.
class
);
realm
.
delete
(
GetUsersOfRoomsProcedure
.
class
);
...
...
app/src/main/res/drawable/ic_insert_photo_white_24dp.xml
0 → 100644
View file @
dd9f79dd
<vector
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:width=
"24dp"
android:height=
"24dp"
android:viewportWidth=
"24.0"
android:viewportHeight=
"24.0"
android:alpha=
"0.78"
>
<path
android:fillColor=
"#FFFFFFFF"
android:pathData=
"M21,19V5c0,-1.1 -0.9,-2 -2,-2H5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2zM8.5,13.5l2.5,3.01L14.5,12l4.5,6H5l3.5,-4.5z"
/>
</vector>
app/src/main/res/drawable/progress_bar.xml
0 → 100644
View file @
dd9f79dd
<?xml version="1.0" encoding="utf-8"?>
<layer-list
xmlns:android=
"http://schemas.android.com/apk/res/android"
>
<item
android:id=
"@android:id/background"
>
<shape>
<corners
android:radius=
"2dp"
/>
<solid
android:color=
"#12000000"
/>
</shape>
</item>
<item
android:id=
"@android:id/secondaryProgress"
>
<clip>
<shape>
<corners
android:radius=
"2dp"
/>
<solid
android:color=
"@color/colorAccent_a40"
/>
</shape>
</clip>
</item>
<item
android:id=
"@android:id/progress"
>
<clip>
<shape>
<corners
android:radius=
"2dp"
/>
<solid
android:color=
"@color/colorAccent"
/>
</shape>
</clip>
</item>
</layer-list>
app/src/main/res/layout/dialog_file_uploading.xml
0 → 100644
View file @
dd9f79dd
<?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:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:paddingStart=
"@dimen/margin_16"
android:paddingEnd=
"@dimen/margin_16"
android:paddingBottom=
"@dimen/margin_16"
android:orientation=
"vertical"
>
<FrameLayout
android:id=
"@+id/room_user_titlebar"
android:layout_width=
"match_parent"
android:layout_height=
"?attr/actionBarSize"
>
<TextView
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_gravity=
"start|center_vertical"
android:text=
"@string/file_uploading_title"
android:textAppearance=
"@style/TextAppearance.AppCompat.Title"
/>
</FrameLayout>
<ProgressBar
android:id=
"@+id/progressBar"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
style=
"@style/AppTheme.ProgressBar.Horizontal"
android:layout_marginTop=
"@dimen/margin_8"
android:layout_marginBottom=
"@dimen/margin_8"
tools:progress=
"12"
tools:max=
"120"
/>
<LinearLayout
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:orientation=
"horizontal"
android:layout_gravity=
"end"
android:paddingEnd=
"2dp"
>
<TextView
android:id=
"@+id/txt_filesize_uploaded"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
tools:text=
"12"
/>
<TextView
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:text=
"/"
android:layout_marginStart=
"2dp"
android:layout_marginEnd=
"2dp"
/>
<TextView
android:id=
"@+id/txt_filesize_total"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
tools:text=
"120"
/>
</LinearLayout>
</LinearLayout>
\ No newline at end of file
app/src/main/res/layout/fragment_room_main.xml
View file @
dd9f79dd
...
...
@@ -20,6 +20,16 @@
android:layout_gravity=
"bottom"
android:background=
"@android:color/white"
/>
<android.support.design.widget.FloatingActionButton
android:id=
"@+id/fab_upload_file"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_gravity=
"start|bottom"
android:layout_margin=
"@dimen/margin_16"
app:fabSize=
"mini"
app:srcCompat=
"@drawable/ic_insert_photo_white_24dp"
/>
<android.support.design.widget.FloatingActionButton
android:id=
"@+id/fab_compose"
android:layout_width=
"wrap_content"
...
...
app/src/main/res/values/strings.xml
View file @
dd9f79dd
...
...
@@ -18,6 +18,8 @@
<string
name=
"resend"
>
Resend
</string>
<string
name=
"discard"
>
Discard
</string>
<string
name=
"file_uploading_title"
>
Uploading...
</string>
<string
name=
"dialog_user_registration_email"
>
Email
</string>
<string
name=
"dialog_user_registration_username"
>
Username
</string>
<string
name=
"dialog_user_registration_password"
>
Password
</string>
...
...
app/src/main/res/values/styles.xml
View file @
dd9f79dd
...
...
@@ -38,4 +38,9 @@
<item
name=
"colorControlActivated"
>
@color/colorAccentDark
</item>
<item
name=
"android:textColorHighlight"
>
@color/colorAccent_a40
</item>
</style>
<style
name=
"AppTheme.ProgressBar.Horizontal"
parent=
"Widget.AppCompat.ProgressBar.Horizontal"
>
<item
name=
"android:minHeight"
>
11dp
</item>
<item
name=
"android:progressDrawable"
>
@drawable/progress_bar
</item>
</style>
</resources>
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