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
26ead887
Commit
26ead887
authored
Jun 05, 2018
by
Filipe de Lima Brito
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'beta' of github.com:RocketChat/Rocket.Chat.Android into develop
parents
d46037d4
9da37707
Changes
46
Show whitespace changes
Inline
Side-by-side
Showing
46 changed files
with
958 additions
and
608 deletions
+958
-608
build.gradle
app/build.gradle
+12
-4
google-services.json
app/google-services.json
+247
-13
AndroidManifest.xml
app/src/main/AndroidManifest.xml
+5
-23
DateTimeHelper.kt
app/src/main/java/chat/rocket/android/app/DateTimeHelper.kt
+3
-3
LoginPresenter.kt
...droid/authentication/login/presentation/LoginPresenter.kt
+1
-5
LoginView.kt
...et/android/authentication/login/presentation/LoginView.kt
+2
-2
LoginFragment.kt
...t/rocket/android/authentication/login/ui/LoginFragment.kt
+52
-170
SignupPresenter.kt
...oid/authentication/signup/presentation/SignupPresenter.kt
+1
-5
SignupView.kt
.../android/authentication/signup/presentation/SignupView.kt
+2
-2
SignupFragment.kt
...rocket/android/authentication/signup/ui/SignupFragment.kt
+15
-43
ImageAttachmentViewHolder.kt
...ket/android/chatroom/adapter/ImageAttachmentViewHolder.kt
+1
-1
ChatRoomPresenter.kt
...rocket/android/chatroom/presentation/ChatRoomPresenter.kt
+11
-11
MessageService.kt
...va/chat/rocket/android/chatroom/service/MessageService.kt
+1
-1
ChatRoomFragment.kt
.../java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
+15
-10
MessageViewModel.kt
...hat/rocket/android/chatroom/viewmodel/MessageViewModel.kt
+13
-13
ReactionViewModel.kt
...at/rocket/android/chatroom/viewmodel/ReactionViewModel.kt
+5
-5
ViewModelMapper.kt
...chat/rocket/android/chatroom/viewmodel/ViewModelMapper.kt
+102
-41
ChatRoomsPresenter.kt
...cket/android/chatrooms/presentation/ChatRoomsPresenter.kt
+20
-2
ChatRoomsFragment.kt
...ava/chat/rocket/android/chatrooms/ui/ChatRoomsFragment.kt
+30
-5
ServiceBuilder.kt
.../java/chat/rocket/android/dagger/module/ServiceBuilder.kt
+4
-4
FavoriteMessagesPresenter.kt
...avoritemessages/presentation/FavoriteMessagesPresenter.kt
+3
-3
FavoriteMessagesFragment.kt
...t/android/favoritemessages/ui/FavoriteMessagesFragment.kt
+1
-1
FilesFragment.kt
...c/main/java/chat/rocket/android/files/ui/FilesFragment.kt
+2
-6
FileViewModel.kt
...java/chat/rocket/android/files/viewmodel/FileViewModel.kt
+4
-3
ImageHelper.kt
app/src/main/java/chat/rocket/android/helper/ImageHelper.kt
+0
-3
SmartLockHelper.kt
...c/main/java/chat/rocket/android/helper/SmartLockHelper.kt
+146
-0
MainNavigator.kt
...va/chat/rocket/android/main/presentation/MainNavigator.kt
+3
-3
MainPresenter.kt
...va/chat/rocket/android/main/presentation/MainPresenter.kt
+2
-4
MainView.kt
...in/java/chat/rocket/android/main/presentation/MainView.kt
+1
-4
MainActivity.kt
...src/main/java/chat/rocket/android/main/ui/MainActivity.kt
+58
-88
PinnedMessagesPresenter.kt
...id/pinnedmessages/presentation/PinnedMessagesPresenter.kt
+2
-3
PinnedMessagesFragment.kt
...ocket/android/pinnedmessages/ui/PinnedMessagesFragment.kt
+1
-1
ProfilePresenter.kt
...t/rocket/android/profile/presentation/ProfilePresenter.kt
+2
-1
FirebaseMessagingService.kt
...java/chat/rocket/android/push/FirebaseMessagingService.kt
+24
-0
FirebaseTokenService.kt
...ain/java/chat/rocket/android/push/FirebaseTokenService.kt
+7
-12
PushManager.kt
app/src/main/java/chat/rocket/android/push/PushManager.kt
+115
-83
FirebaseMessagingServiceProvider.kt
...ocket/android/push/di/FirebaseMessagingServiceProvider.kt
+3
-3
ConnectionManager.kt
...ocket/android/server/infraestructure/ConnectionManager.kt
+6
-6
ChangeServerNavigator.kt
...cket/android/server/presentation/ChangeServerNavigator.kt
+5
-2
ChangeServerPresenter.kt
...cket/android/server/presentation/ChangeServerPresenter.kt
+2
-2
ChangeServerActivity.kt
...ava/chat/rocket/android/server/ui/ChangeServerActivity.kt
+5
-2
fragment_authentication_log_in.xml
app/src/main/res/layout/fragment_authentication_log_in.xml
+12
-0
fragment_files.xml
app/src/main/res/layout/fragment_files.xml
+1
-0
api_keys.xml
app/src/main/res/values/api_keys.xml
+0
-5
debug.keystore
debug.keystore
+0
-0
dependencies.gradle
dependencies.gradle
+11
-10
No files found.
app/build.gradle
View file @
26ead887
...
...
@@ -13,7 +13,7 @@ android {
applicationId
"chat.rocket.android"
minSdkVersion
21
targetSdkVersion
versions
.
targetSdk
versionCode
202
2
versionCode
202
4
versionName
"2.3.0"
testInstrumentationRunner
"android.support.test.runner.AndroidJUnitRunner"
multiDexEnabled
true
...
...
@@ -26,12 +26,19 @@ android {
keyAlias
System
.
getenv
(
"KEY_ALIAS"
)
keyPassword
System
.
getenv
(
"KEY_PASSWORD"
)
}
debug
{
storeFile
project
.
rootProject
.
file
(
'debug.keystore'
).
getCanonicalFile
()
storePassword
"android"
keyAlias
"androiddebugkey"
keyPassword
"android"
}
}
buildTypes
{
release
{
buildConfigField
"String"
,
"REQUIRED_SERVER_VERSION"
,
'"0.62.0"'
buildConfigField
"String"
,
"RECOMMENDED_SERVER_VERSION"
,
'"0.6
3.0
"'
buildConfigField
"String"
,
"RECOMMENDED_SERVER_VERSION"
,
'"0.6
4.2
"'
signingConfig
signingConfigs
.
release
minifyEnabled
false
proguardFiles
getDefaultProguardFile
(
'proguard-android.txt'
),
'proguard-rules.pro'
...
...
@@ -39,7 +46,8 @@ android {
debug
{
buildConfigField
"String"
,
"REQUIRED_SERVER_VERSION"
,
'"0.62.0"'
buildConfigField
"String"
,
"RECOMMENDED_SERVER_VERSION"
,
'"0.63.0"'
buildConfigField
"String"
,
"RECOMMENDED_SERVER_VERSION"
,
'"0.64.2"'
signingConfig
signingConfigs
.
debug
applicationIdSuffix
".dev"
}
}
...
...
@@ -73,7 +81,7 @@ dependencies {
kapt
libraries
.
daggerProcessor
kapt
libraries
.
daggerAndroidApt
implementation
libraries
.
playServicesG
cm
implementation
libraries
.
f
cm
implementation
libraries
.
playServicesAuth
implementation
libraries
.
room
...
...
app/google-services.json
View file @
26ead887
{
"project_info"
:
{
"project_number"
:
"
1020987621558
"
,
"firebase_url"
:
"https://rocketchat
nativ
e.firebaseio.com"
,
"project_id"
:
"rocketchat
nativ
e"
,
"storage_bucket"
:
"rocketchat
nativ
e.appspot.com"
"project_number"
:
"
673693445664
"
,
"firebase_url"
:
"https://rocketchat
-9e9b
e.firebaseio.com"
,
"project_id"
:
"rocketchat
-9e9b
e"
,
"storage_bucket"
:
"rocketchat
-9e9b
e.appspot.com"
},
"client"
:
[
{
"client_info"
:
{
"mobilesdk_app_id"
:
"1:
1020987621558:android:16da2e50aff9f0c9
"
,
"mobilesdk_app_id"
:
"1:
673693445664:android:6ef4638e500ec958
"
,
"android_client_info"
:
{
"package_name"
:
"
chat.rocket.android
"
"package_name"
:
"
RocketChat
"
}
},
"oauth_client"
:
[
{
"client_id"
:
"1020987621558-trk61fjrahho0ujtjap095p1jmi48pfq.apps.googleusercontent.com"
,
"client_id"
:
"673693445664-97s9t777ful7mn2510vuhb48958qd9tb.apps.googleusercontent.com"
,
"client_type"
:
3
},
{
"client_id"
:
"673693445664-vtcvuvso7k88gpodlpshod55g1ehs03s.apps.googleusercontent.com"
,
"client_type"
:
3
},
{
"client_id"
:
"673693445664-sf7lqf11kk6vplg9ljh7pi491gvb08f3.apps.googleusercontent.com"
,
"client_type"
:
3
},
{
"client_id"
:
"673693445664-fb71j3aqmafmm20jkj8gvpusv04fdnq8.apps.googleusercontent.com"
,
"client_type"
:
3
},
{
"client_id"
:
"673693445664-ejd5lkbsdjoo5onc052dotsjacdh1kcc.apps.googleusercontent.com"
,
"client_type"
:
3
},
{
"client_id"
:
"673693445664-ssfpeb0are3svvg0etbttog789s0n3ua.apps.googleusercontent.com"
,
"client_type"
:
3
},
{
"client_id"
:
"673693445664-97s9t777ful7mn2510vuhb48958qd9tb.apps.googleusercontent.com"
,
"client_type"
:
3
}
],
"api_key"
:
[
{
"current_key"
:
"AIzaSyD
c7VYUdU6kRkoRTToiCn1rh-W0wJvhLWk
"
"current_key"
:
"AIzaSyD
IkZj1TRz8TmhnMswDwVY5OnWuzFK3rxg
"
}
],
"services"
:
{
...
...
@@ -39,20 +63,143 @@
},
{
"client_info"
:
{
"mobilesdk_app_id"
:
"1:1020987621558:android:1551054db195f705"
,
"mobilesdk_app_id"
:
"1:673693445664:android:16da2e50aff9f0c9"
,
"android_client_info"
:
{
"package_name"
:
"chat.rocket.android"
}
},
"oauth_client"
:
[
{
"client_id"
:
"673693445664-k0mvosdjoe5dbvqce3b377ckabb5dgu8.apps.googleusercontent.com"
,
"client_type"
:
1
,
"android_info"
:
{
"package_name"
:
"chat.rocket.android"
,
"certificate_hash"
:
"33fa8582794176014a59054192e261bfad0e5273"
}
},
{
"client_id"
:
"673693445664-hrjftksij02vqtd467ln2cubvu48ft5j.apps.googleusercontent.com"
,
"client_type"
:
1
,
"android_info"
:
{
"package_name"
:
"chat.rocket.android"
,
"certificate_hash"
:
"41cf750df786a6d9da712a98a629d0c8391876d6"
}
},
{
"client_id"
:
"673693445664-97s9t777ful7mn2510vuhb48958qd9tb.apps.googleusercontent.com"
,
"client_type"
:
3
},
{
"client_id"
:
"673693445664-vtcvuvso7k88gpodlpshod55g1ehs03s.apps.googleusercontent.com"
,
"client_type"
:
3
},
{
"client_id"
:
"673693445664-sf7lqf11kk6vplg9ljh7pi491gvb08f3.apps.googleusercontent.com"
,
"client_type"
:
3
},
{
"client_id"
:
"673693445664-fb71j3aqmafmm20jkj8gvpusv04fdnq8.apps.googleusercontent.com"
,
"client_type"
:
3
},
{
"client_id"
:
"673693445664-ejd5lkbsdjoo5onc052dotsjacdh1kcc.apps.googleusercontent.com"
,
"client_type"
:
3
},
{
"client_id"
:
"673693445664-ssfpeb0are3svvg0etbttog789s0n3ua.apps.googleusercontent.com"
,
"client_type"
:
3
},
{
"client_id"
:
"673693445664-97s9t777ful7mn2510vuhb48958qd9tb.apps.googleusercontent.com"
,
"client_type"
:
3
}
],
"api_key"
:
[
{
"current_key"
:
"AIzaSyDIkZj1TRz8TmhnMswDwVY5OnWuzFK3rxg"
}
],
"services"
:
{
"analytics_service"
:
{
"status"
:
1
},
"appinvite_service"
:
{
"status"
:
2
,
"other_platform_oauth_client"
:
[
{
"client_id"
:
"673693445664-pa3k48sg81r89rn65e9rlnu4gpmm5vem.apps.googleusercontent.com"
,
"client_type"
:
2
,
"ios_info"
:
{
"bundle_id"
:
"com.konecty.rocket.chat"
}
},
{
"client_id"
:
"673693445664-97s9t777ful7mn2510vuhb48958qd9tb.apps.googleusercontent.com"
,
"client_type"
:
3
}
]
},
"ads_service"
:
{
"status"
:
2
}
}
},
{
"client_info"
:
{
"mobilesdk_app_id"
:
"1:673693445664:android:1551054db195f705"
,
"android_client_info"
:
{
"package_name"
:
"chat.rocket.android.dev"
}
},
"oauth_client"
:
[
{
"client_id"
:
"1020987621558-trk61fjrahho0ujtjap095p1jmi48pfq.apps.googleusercontent.com"
,
"client_id"
:
"673693445664-t5aeku0oie010npd40a0tgn27c418vk7.apps.googleusercontent.com"
,
"client_type"
:
1
,
"android_info"
:
{
"package_name"
:
"chat.rocket.android.dev"
,
"certificate_hash"
:
"41cf750df786a6d9da712a98a629d0c8391876d6"
}
},
{
"client_id"
:
"673693445664-iml14ln4vccuu7liclrpt2k671fkjs38.apps.googleusercontent.com"
,
"client_type"
:
1
,
"android_info"
:
{
"package_name"
:
"chat.rocket.android.dev"
,
"certificate_hash"
:
"33fa8582794176014a59054192e261bfad0e5273"
}
},
{
"client_id"
:
"673693445664-97s9t777ful7mn2510vuhb48958qd9tb.apps.googleusercontent.com"
,
"client_type"
:
3
},
{
"client_id"
:
"673693445664-vtcvuvso7k88gpodlpshod55g1ehs03s.apps.googleusercontent.com"
,
"client_type"
:
3
},
{
"client_id"
:
"673693445664-sf7lqf11kk6vplg9ljh7pi491gvb08f3.apps.googleusercontent.com"
,
"client_type"
:
3
},
{
"client_id"
:
"673693445664-fb71j3aqmafmm20jkj8gvpusv04fdnq8.apps.googleusercontent.com"
,
"client_type"
:
3
},
{
"client_id"
:
"673693445664-ejd5lkbsdjoo5onc052dotsjacdh1kcc.apps.googleusercontent.com"
,
"client_type"
:
3
},
{
"client_id"
:
"673693445664-ssfpeb0are3svvg0etbttog789s0n3ua.apps.googleusercontent.com"
,
"client_type"
:
3
},
{
"client_id"
:
"673693445664-97s9t777ful7mn2510vuhb48958qd9tb.apps.googleusercontent.com"
,
"client_type"
:
3
}
],
"api_key"
:
[
{
"current_key"
:
"AIzaSyD
c7VYUdU6kRkoRTToiCn1rh-W0wJvhLWk
"
"current_key"
:
"AIzaSyD
IkZj1TRz8TmhnMswDwVY5OnWuzFK3rxg
"
}
],
"services"
:
{
...
...
@@ -60,8 +207,95 @@
"status"
:
1
},
"appinvite_service"
:
{
"status"
:
1
,
"other_platform_oauth_client"
:
[]
"status"
:
2
,
"other_platform_oauth_client"
:
[
{
"client_id"
:
"673693445664-pa3k48sg81r89rn65e9rlnu4gpmm5vem.apps.googleusercontent.com"
,
"client_type"
:
2
,
"ios_info"
:
{
"bundle_id"
:
"com.konecty.rocket.chat"
}
},
{
"client_id"
:
"673693445664-97s9t777ful7mn2510vuhb48958qd9tb.apps.googleusercontent.com"
,
"client_type"
:
3
}
]
},
"ads_service"
:
{
"status"
:
2
}
}
},
{
"client_info"
:
{
"mobilesdk_app_id"
:
"1:673693445664:android:64932c99863e2838"
,
"android_client_info"
:
{
"package_name"
:
"com.konecty.rocket.chat"
}
},
"oauth_client"
:
[
{
"client_id"
:
"673693445664-97s9t777ful7mn2510vuhb48958qd9tb.apps.googleusercontent.com"
,
"client_type"
:
3
},
{
"client_id"
:
"673693445664-vtcvuvso7k88gpodlpshod55g1ehs03s.apps.googleusercontent.com"
,
"client_type"
:
3
},
{
"client_id"
:
"673693445664-sf7lqf11kk6vplg9ljh7pi491gvb08f3.apps.googleusercontent.com"
,
"client_type"
:
3
},
{
"client_id"
:
"673693445664-fb71j3aqmafmm20jkj8gvpusv04fdnq8.apps.googleusercontent.com"
,
"client_type"
:
3
},
{
"client_id"
:
"673693445664-ejd5lkbsdjoo5onc052dotsjacdh1kcc.apps.googleusercontent.com"
,
"client_type"
:
3
},
{
"client_id"
:
"673693445664-3ajben08beuco6eout3kpod2gbbm8fij.apps.googleusercontent.com"
,
"client_type"
:
1
,
"android_info"
:
{
"package_name"
:
"com.konecty.rocket.chat"
,
"certificate_hash"
:
"cd5806ba3f0141d0f2e47acfe64a485f575108ab"
}
},
{
"client_id"
:
"673693445664-ssfpeb0are3svvg0etbttog789s0n3ua.apps.googleusercontent.com"
,
"client_type"
:
3
},
{
"client_id"
:
"673693445664-97s9t777ful7mn2510vuhb48958qd9tb.apps.googleusercontent.com"
,
"client_type"
:
3
}
],
"api_key"
:
[
{
"current_key"
:
"AIzaSyDIkZj1TRz8TmhnMswDwVY5OnWuzFK3rxg"
}
],
"services"
:
{
"analytics_service"
:
{
"status"
:
1
},
"appinvite_service"
:
{
"status"
:
2
,
"other_platform_oauth_client"
:
[
{
"client_id"
:
"673693445664-pa3k48sg81r89rn65e9rlnu4gpmm5vem.apps.googleusercontent.com"
,
"client_type"
:
2
,
"ios_info"
:
{
"bundle_id"
:
"com.konecty.rocket.chat"
}
},
{
"client_id"
:
"673693445664-97s9t777ful7mn2510vuhb48958qd9tb.apps.googleusercontent.com"
,
"client_type"
:
3
}
]
},
"ads_service"
:
{
"status"
:
2
...
...
app/src/main/AndroidManifest.xml
View file @
26ead887
...
...
@@ -3,17 +3,9 @@
package=
"chat.rocket.android"
>
<uses-permission
android:name=
"android.permission.INTERNET"
/>
<uses-permission
android:name=
"android.permission.WAKE_LOCK"
/>
<uses-permission
android:name=
"android.permission.VIBRATE"
/>
<uses-permission
android:name=
"com.google.android.c2dm.permission.RECEIVE"
/>
<uses-permission
android:name=
"android.permission.WRITE_EXTERNAL_STORAGE"
/>
<permission
android:name=
"${applicationId}.permission.C2D_MESSAGE"
android:protectionLevel=
"signature"
/>
<uses-permission
android:name=
"${applicationId}.permission.C2D_MESSAGE"
/>
<application
android:name=
".app.RocketChatApplication"
android:allowBackup=
"true"
...
...
@@ -39,6 +31,7 @@
<intent-filter>
<action
android:name=
"android.intent.action.VIEW"
/>
<category
android:name=
"android.intent.category.BROWSABLE"
/>
<category
android:name=
"android.intent.category.DEFAULT"
/>
...
...
@@ -91,18 +84,6 @@
android:name=
".settings.about.ui.AboutActivity"
android:theme=
"@style/AppTheme"
/>
<receiver
android:name=
"com.google.android.gms.gcm.GcmReceiver"
android:exported=
"true"
android:permission=
"com.google.android.c2dm.permission.SEND"
>
<intent-filter>
<action
android:name=
"com.google.android.c2dm.intent.RECEIVE"
/>
<action
android:name=
"com.google.android.c2dm.intent.REGISTRATION"
/>
<category
android:name=
"${applicationId}"
/>
</intent-filter>
</receiver>
<receiver
android:name=
".push.DirectReplyReceiver"
android:enabled=
"true"
...
...
@@ -121,10 +102,11 @@
</service>
<service
android:name=
".push.GcmListenerService"
android:exported=
"false"
>
android:name=
".push.FirebaseMessagingService"
android:enabled=
"true"
android:exported=
"true"
>
<intent-filter>
<action
android:name=
"com.google.
android.c2dm.intent.RECEIVE
"
/>
<action
android:name=
"com.google.
firebase.MESSAGING_EVENT
"
/>
</intent-filter>
</service>
...
...
app/src/main/java/chat/rocket/android/app/DateTimeHelper.kt
View file @
26ead887
...
...
@@ -14,11 +14,11 @@ object DateTimeHelper {
/**
* Returns a [LocalDateTime] from a [Long].
*
* @param long The [Long]
* @param long The [Long]
to gets a [LocalDateTime].
* @return The [LocalDateTime] from a [Long].
*/
fun
getLocalDateTime
(
long
:
Long
?
):
LocalDateTime
{
return
LocalDateTime
.
ofInstant
(
long
?.
let
{
Instant
.
ofEpochMilli
(
it
)
}
,
ZoneId
.
systemDefault
())
fun
getLocalDateTime
(
long
:
Long
):
LocalDateTime
{
return
LocalDateTime
.
ofInstant
(
Instant
.
ofEpochMilli
(
long
)
,
ZoneId
.
systemDefault
())
}
/**
...
...
app/src/main/java/chat/rocket/android/authentication/login/presentation/LoginPresenter.kt
View file @
26ead887
...
...
@@ -56,7 +56,6 @@ class LoginPresenter @Inject constructor(
private
lateinit
var
credentialSecret
:
String
private
lateinit
var
deepLinkUserId
:
String
private
lateinit
var
deepLinkToken
:
String
private
var
loginCredentials
:
Credential
?
=
null
fun
setupView
()
{
setupConnectionInfo
(
currentServer
)
...
...
@@ -357,10 +356,7 @@ class LoginPresenter @Inject constructor(
saveToken
(
token
)
registerPushToken
()
if
(
loginType
==
TYPE_LOGIN_USER_EMAIL
)
{
loginCredentials
=
Credential
.
Builder
(
usernameOrEmail
)
.
setPassword
(
password
)
.
build
()
view
.
saveSmartLockCredentials
(
loginCredentials
)
view
.
saveSmartLockCredentials
(
usernameOrEmail
,
password
)
}
navigator
.
toChatList
()
}
else
if
(
loginType
==
TYPE_LOGIN_OAUTH
)
{
...
...
app/src/main/java/chat/rocket/android/authentication/login/presentation/LoginView.kt
View file @
26ead887
...
...
@@ -243,7 +243,7 @@ interface LoginView : LoadingView, MessageView {
fun
alertWrongPassword
()
/**
* Save
credentials via google smart lock
* Save
s Google Smart Lock credentials.
*/
fun
saveSmartLockCredentials
(
loginCredential
:
Credential
?
)
fun
saveSmartLockCredentials
(
id
:
String
,
password
:
String
)
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/authentication/login/ui/LoginFragment.kt
View file @
26ead887
...
...
@@ -2,28 +2,27 @@ package chat.rocket.android.authentication.login.ui
import
DrawableHelper
import
android.app.Activity
import
android.app.PendingIntent
import
android.content.Intent
import
android.content.IntentSender
import
android.graphics.PorterDuff
import
android.os.Build
import
android.os.Bundle
import
android.support.v4.app.Fragment
import
android.support.v4.app.FragmentActivity
import
android.text.style.ClickableSpan
import
android.view.LayoutInflater
import
android.view.View
import
android.view.ViewGroup
import
android.view.ViewTreeObserver
import
android.widget.*
import
android.widget.Button
import
android.widget.ImageButton
import
android.widget.LinearLayout
import
android.widget.ScrollView
import
androidx.core.view.isVisible
import
androidx.core.view.postDelayed
import
chat.rocket.android.R
import
chat.rocket.android.authentication.domain.model.LoginDeepLinkInfo
import
chat.rocket.android.authentication.login.presentation.LoginPresenter
import
chat.rocket.android.authentication.login.presentation.LoginView
import
chat.rocket.android.helper.KeyboardHelper
import
chat.rocket.android.helper.TextHelper
import
chat.rocket.android.helper.*
import
chat.rocket.android.util.extensions.*
import
chat.rocket.android.webview.sso.ui.INTENT_SSO_TOKEN
import
chat.rocket.android.webview.sso.ui.ssoWebViewIntent
...
...
@@ -31,37 +30,25 @@ import chat.rocket.android.webview.oauth.ui.INTENT_OAUTH_CREDENTIAL_SECRET
import
chat.rocket.android.webview.oauth.ui.INTENT_OAUTH_CREDENTIAL_TOKEN
import
chat.rocket.android.webview.oauth.ui.oauthWebViewIntent
import
chat.rocket.common.util.ifNull
import
com.google.android.gms.auth.api.Auth
import
com.google.android.gms.auth.api.credentials.*
import
com.google.android.gms.common.api.CommonStatusCodes
import
com.google.android.gms.common.api.GoogleApiClient
import
com.google.android.gms.common.api.ResolvingResultCallbacks
import
com.google.android.gms.common.api.Status
import
dagger.android.support.AndroidSupportInjection
import
kotlinx.android.synthetic.main.fragment_authentication_log_in.*
import
timber.log.Timber
import
javax.inject.Inject
internal
const
val
REQUEST_CODE_FOR_CAS
=
1
internal
const
val
REQUEST_CODE_FOR_SAML
=
2
internal
const
val
REQUEST_CODE_FOR_OAUTH
=
3
internal
const
val
MULTIPLE_CREDENTIALS_READ
=
4
internal
const
val
NO_CREDENTIALS_EXIST
=
5
internal
const
val
SAVE_CREDENTIALS
=
6
internal
const
val
REQUEST_CODE_FOR_CAS
=
4
internal
const
val
REQUEST_CODE_FOR_SAML
=
5
internal
const
val
REQUEST_CODE_FOR_OAUTH
=
6
lateinit
var
googleApiClient
:
GoogleApiClient
class
LoginFragment
:
Fragment
(),
LoginView
,
GoogleApiClient
.
ConnectionCallbacks
{
class
LoginFragment
:
Fragment
(),
LoginView
{
@Inject
lateinit
var
presenter
:
LoginPresenter
private
var
isOauthViewEnable
=
false
private
val
layoutListener
=
ViewTreeObserver
.
OnGlobalLayoutListener
{
areLoginOptionsNeeded
()
}
private
var
isOauthSuccessful
=
false
private
var
isGlobalLayoutListenerSetUp
=
false
private
var
deepLinkInfo
:
LoginDeepLinkInfo
?
=
null
private
va
r
credentialsToBeSaved
:
Credential
?
=
null
private
va
l
credentialsClient
by
lazy
{
Credentials
.
getClient
(
requireActivity
())
}
companion
object
{
private
const
val
DEEP_LINK_INFO
=
"DeepLinkInfo"
...
...
@@ -73,17 +60,9 @@ class LoginFragment : Fragment(), LoginView, GoogleApiClient.ConnectionCallbacks
}
}
override
fun
onConnected
(
bundle
:
Bundle
?)
{
saveSmartLockCredentials
(
credentialsToBeSaved
)
}
override
fun
onConnectionSuspended
(
errorCode
:
Int
)
{
}
override
fun
onCreate
(
savedInstanceState
:
Bundle
?)
{
super
.
onCreate
(
savedInstanceState
)
AndroidSupportInjection
.
inject
(
this
)
buildGoogleApiClient
()
deepLinkInfo
=
arguments
?.
getParcelable
(
DEEP_LINK_INFO
)
}
...
...
@@ -120,156 +99,40 @@ class LoginFragment : Fragment(), LoginView, GoogleApiClient.ConnectionCallbacks
if
(
resultCode
==
Activity
.
RESULT_OK
)
{
if
(
data
!=
null
)
{
when
(
requestCode
)
{
REQUEST_CODE_FOR_CAS
->
data
.
apply
{
presenter
.
authenticateWithCas
(
getStringExtra
(
INTENT_SSO_TOKEN
))
REQUEST_CODE_FOR_MULTIPLE_ACCOUNTS_RESOLUTION
->
{
onCredentialRetrieved
(
data
.
getParcelableExtra
(
Credential
.
EXTRA_KEY
))
}
REQUEST_CODE_FOR_SIGN_IN_REQUIRED
->
{
//use the hints to autofill sign in forms to reduce the info to be filled.
val
credential
:
Credential
=
data
.
getParcelableExtra
(
Credential
.
EXTRA_KEY
)
text_username_or_email
.
setText
(
credential
.
id
)
text_password
.
setText
(
credential
.
password
)
}
REQUEST_CODE_FOR_SAVE_RESOLUTION
->
{
showMessage
(
getString
(
R
.
string
.
message_credentials_saved_successfully
))
}
REQUEST_CODE_FOR_CAS
->
{
presenter
.
authenticateWithCas
(
data
.
getStringExtra
(
INTENT_SSO_TOKEN
))
}
REQUEST_CODE_FOR_SAML
->
data
.
apply
{
presenter
.
authenticateWithSaml
(
getStringExtra
(
INTENT_SSO_TOKEN
))
}
REQUEST_CODE_FOR_OAUTH
->
{
isOauthSuccessful
=
true
data
.
apply
{
presenter
.
authenticateWithOauth
(
getStringExtra
(
INTENT_OAUTH_CREDENTIAL_TOKEN
),
getStringExtra
(
INTENT_OAUTH_CREDENTIAL_SECRET
)
)
}
}
MULTIPLE_CREDENTIALS_READ
->
{
val
loginCredentials
:
Credential
=
data
.
getParcelableExtra
(
Credential
.
EXTRA_KEY
)
handleCredential
(
loginCredentials
)
}
NO_CREDENTIALS_EXIST
->
{
//use the hints to autofill sign in forms to reduce the info to be filled
val
loginCredentials
:
Credential
=
data
.
getParcelableExtra
(
Credential
.
EXTRA_KEY
)
val
email
=
loginCredentials
.
id
val
password
=
loginCredentials
.
password
text_username_or_email
.
setText
(
email
)
text_password
.
setText
(
password
)
}
SAVE_CREDENTIALS
->
Toast
.
makeText
(
context
,
getString
(
R
.
string
.
message_credentials_saved_successfully
),
Toast
.
LENGTH_SHORT
).
show
()
}
}
}
//cancel button pressed by the user in case of reading from smart lock
else
if
(
resultCode
==
Activity
.
RESULT_CANCELED
&&
requestCode
==
REQUEST_CODE_FOR_OAUTH
)
{
Timber
.
d
(
"Returned from oauth"
)
}
}
override
fun
onDestroy
()
{
super
.
onDestroy
()
googleApiClient
.
let
{
activity
?.
let
{
it1
->
it
.
stopAutoManage
(
it1
)
}
it
.
disconnect
()
}
}
private
fun
buildGoogleApiClient
()
{
googleApiClient
=
GoogleApiClient
.
Builder
(
context
!!
)
.
enableAutoManage
(
activity
as
FragmentActivity
,
{
Timber
.
e
(
"ERROR: Connection to client failed"
)
})
.
addConnectionCallbacks
(
this
)
.
addApi
(
Auth
.
CREDENTIALS_API
)
.
build
()
}
override
fun
onStart
()
{
super
.
onStart
()
if
(!
isOauthSuccessful
)
{
requestCredentials
()
}
}
private
fun
requestCredentials
()
{
val
request
:
CredentialRequest
=
CredentialRequest
.
Builder
()
.
setPasswordLoginSupported
(
true
)
.
build
()
Auth
.
CredentialsApi
.
request
(
googleApiClient
,
request
)
.
setResultCallback
{
credentialRequestResult
->
val
status
=
credentialRequestResult
.
status
when
{
status
.
isSuccess
->
handleCredential
(
credentialRequestResult
.
credential
)
(
status
.
statusCode
==
CommonStatusCodes
.
RESOLUTION_REQUIRED
)
->
resolveResult
(
status
,
MULTIPLE_CREDENTIALS_READ
)
(
status
.
statusCode
==
CommonStatusCodes
.
SIGN_IN_REQUIRED
)
->
{
val
hintRequest
:
HintRequest
=
HintRequest
.
Builder
()
.
setHintPickerConfig
(
CredentialPickerConfig
.
Builder
()
.
setShowCancelButton
(
true
)
.
build
()
data
.
getStringExtra
(
INTENT_OAUTH_CREDENTIAL_TOKEN
),
data
.
getStringExtra
(
INTENT_OAUTH_CREDENTIAL_SECRET
)
)
.
setEmailAddressIdentifierSupported
(
true
)
.
setAccountTypes
(
IdentityProviders
.
GOOGLE
)
.
build
()
val
intent
:
PendingIntent
=
Auth
.
CredentialsApi
.
getHintPickerIntent
(
googleApiClient
,
hintRequest
)
try
{
startIntentSenderForResult
(
intent
.
intentSender
,
NO_CREDENTIALS_EXIST
,
null
,
0
,
0
,
0
,
null
)
}
catch
(
e
:
IntentSender
.
SendIntentException
)
{
Timber
.
e
(
"ERROR: Could not start hint picker Intent"
)
}
}
else
->
Timber
.
d
(
"ERROR: nothing happening"
)
}
}
}
private
fun
handleCredential
(
loginCredentials
:
Credential
)
{
if
(
loginCredentials
.
accountType
==
null
)
{
presenter
.
authenticateWithUserAndPassword
(
loginCredentials
.
id
,
loginCredentials
.
password
.
toString
()
)
}
}
private
fun
resolveResult
(
status
:
Status
,
requestCode
:
Int
)
{
try
{
status
.
startResolutionForResult
(
activity
,
requestCode
)
}
catch
(
e
:
IntentSender
.
SendIntentException
)
{
Timber
.
e
(
"Failed to send Credentials intent"
)
}
}
override
fun
saveSmartLockCredentials
(
loginCredential
:
Credential
?)
{
credentialsToBeSaved
=
loginCredential
if
(
credentialsToBeSaved
==
null
)
{
return
}
activity
?.
let
{
Auth
.
CredentialsApi
.
save
(
googleApiClient
,
credentialsToBeSaved
).
setResultCallback
(
object
:
ResolvingResultCallbacks
<
Status
>(
it
,
SAVE_CREDENTIALS
)
{
override
fun
onSuccess
(
status
:
Status
)
{
Timber
.
d
(
"credentials save:SUCCESS:$status"
)
credentialsToBeSaved
=
null
}
override
fun
onUnresolvableFailure
(
status
:
Status
)
{
Timber
.
e
(
"credentials save:FAILURE:$status"
)
credentialsToBeSaved
=
null
}
})
override
fun
onResume
()
{
super
.
onResume
()
image_key
.
setOnClickListener
{
requestStoredCredentials
()
image_key
.
isVisible
=
false
}
}
...
...
@@ -289,6 +152,24 @@ class LoginFragment : Fragment(), LoginView, GoogleApiClient.ConnectionCallbacks
}
}
private
fun
requestStoredCredentials
()
{
activity
?.
let
{
SmartLockHelper
.
requestStoredCredentials
(
credentialsClient
,
it
)
?.
let
{
onCredentialRetrieved
(
it
)
}
}
}
private
fun
onCredentialRetrieved
(
credential
:
Credential
)
{
presenter
.
authenticateWithUserAndPassword
(
credential
.
id
,
credential
.
password
.
toString
())
}
override
fun
saveSmartLockCredentials
(
id
:
String
,
password
:
String
)
{
activity
?.
let
{
SmartLockHelper
.
save
(
credentialsClient
,
it
,
id
,
password
)
}
}
override
fun
showLoading
()
{
ui
{
view_loading
.
isVisible
=
true
...
...
@@ -321,6 +202,7 @@ class LoginFragment : Fragment(), LoginView, GoogleApiClient.ConnectionCallbacks
ui
{
text_username_or_email
.
isVisible
=
true
text_password
.
isVisible
=
true
image_key
.
isVisible
=
true
}
}
...
...
app/src/main/java/chat/rocket/android/authentication/signup/presentation/SignupPresenter.kt
View file @
26ead887
...
...
@@ -15,7 +15,6 @@ import chat.rocket.core.internal.rest.login
import
chat.rocket.core.internal.rest.me
import
chat.rocket.core.internal.rest.signup
import
chat.rocket.core.model.Myself
import
com.google.android.gms.auth.api.credentials.Credential
import
javax.inject.Inject
class
SignupPresenter
@Inject
constructor
(
...
...
@@ -64,10 +63,7 @@ class SignupPresenter @Inject constructor(
localRepository
.
save
(
LocalRepository
.
CURRENT_USERNAME_KEY
,
me
.
username
)
saveAccount
(
me
)
registerPushToken
()
val
loginCredentials
=
Credential
.
Builder
(
email
)
.
setPassword
(
password
)
.
build
()
view
.
saveSmartLockCredentials
(
loginCredentials
)
view
.
saveSmartLockCredentials
(
username
,
password
)
navigator
.
toChatList
()
}
catch
(
exception
:
RocketChatException
)
{
exception
.
message
?.
let
{
...
...
app/src/main/java/chat/rocket/android/authentication/signup/presentation/SignupView.kt
View file @
26ead887
...
...
@@ -27,7 +27,7 @@ interface SignupView : LoadingView, MessageView {
fun
alertBlankEmail
()
/**
* Save
credentials via google smart lock
* Save
s Google Smart Lock credentials.
*/
fun
saveSmartLockCredentials
(
loginCredential
:
Credential
)
fun
saveSmartLockCredentials
(
id
:
String
,
password
:
String
)
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/authentication/signup/ui/SignupFragment.kt
View file @
26ead887
package
chat.rocket.android.authentication.signup.ui
import
DrawableHelper
import
android.app.Activity
.RESULT_OK
import
android.app.Activity
import
android.content.Intent
import
android.os.Build
import
android.os.Bundle
...
...
@@ -11,30 +11,24 @@ import android.view.LayoutInflater
import
android.view.View
import
android.view.ViewGroup
import
android.view.ViewTreeObserver
import
android.widget.Toast
import
chat.rocket.android.R
import
chat.rocket.android.
authentication.login.ui.googleApiClient
import
chat.rocket.android.
R.string.message_credentials_saved_successfully
import
chat.rocket.android.authentication.signup.presentation.SignupPresenter
import
chat.rocket.android.authentication.signup.presentation.SignupView
import
chat.rocket.android.helper.KeyboardHelper
import
chat.rocket.android.helper.SmartLockHelper
import
chat.rocket.android.helper.TextHelper
import
chat.rocket.android.util.extensions.*
import
com.google.android.gms.auth.api.Auth
import
com.google.android.gms.auth.api.credentials.Credential
import
com.google.android.gms.common.api.ResolvingResultCallbacks
import
com.google.android.gms.common.api.Status
import
com.google.android.gms.auth.api.credentials.Credentials
import
dagger.android.support.AndroidSupportInjection
import
kotlinx.android.synthetic.main.fragment_authentication_sign_up.*
import
timber.log.Timber
import
javax.inject.Inject
internal
const
val
SAVE_CREDENTIALS
=
1
class
SignupFragment
:
Fragment
(),
SignupView
{
@Inject
lateinit
var
presenter
:
SignupPresenter
private
lateinit
var
credentialsToBeSaved
:
Credential
private
val
layoutListener
=
ViewTreeObserver
.
OnGlobalLayoutListener
{
if
(
KeyboardHelper
.
isSoftKeyboardShown
(
relative_layout
.
rootView
))
{
bottom_container
.
setVisible
(
false
)
...
...
@@ -120,41 +114,13 @@ class SignupFragment : Fragment(), SignupView {
}
}
override
fun
saveSmartLockCredentials
(
loginCredential
:
Credential
)
{
credentialsToBeSaved
=
loginCredential
googleApiClient
.
let
{
if
(
it
.
isConnected
)
{
saveCredentials
()
}
}
}
override
fun
onActivityResult
(
requestCode
:
Int
,
resultCode
:
Int
,
data
:
Intent
?)
{
if
(
resultCode
==
Activity
.
RESULT_OK
)
{
if
(
data
!=
null
)
{
if
(
requestCode
==
SAVE_CREDENTIALS
)
{
if
(
resultCode
==
RESULT_OK
)
{
Toast
.
makeText
(
context
,
getString
(
R
.
string
.
message_credentials_saved_successfully
),
Toast
.
LENGTH_SHORT
).
show
()
}
else
{
Timber
.
e
(
"ERROR: Cancelled by user"
)
}
}
showMessage
(
getString
(
message_credentials_saved_successfully
))
}
private
fun
saveCredentials
()
{
activity
?.
let
{
Auth
.
CredentialsApi
.
save
(
googleApiClient
,
credentialsToBeSaved
).
setResultCallback
(
object
:
ResolvingResultCallbacks
<
Status
>(
it
,
SAVE_CREDENTIALS
)
{
override
fun
onSuccess
(
status
:
Status
)
{
Timber
.
d
(
"save:SUCCESS:$status"
)
}
override
fun
onUnresolvableFailure
(
status
:
Status
)
{
Timber
.
e
(
"save:FAILURE:$status"
)
}
})
}
}
...
...
@@ -188,6 +154,12 @@ class SignupFragment : Fragment(), SignupView {
showMessage
(
getString
(
R
.
string
.
msg_generic_error
))
}
override
fun
saveSmartLockCredentials
(
id
:
String
,
password
:
String
)
{
activity
?.
let
{
SmartLockHelper
.
save
(
Credentials
.
getClient
(
it
),
it
,
id
,
password
)
}
}
private
fun
tintEditTextDrawableStart
()
{
ui
{
val
personDrawable
=
...
...
app/src/main/java/chat/rocket/android/chatroom/adapter/ImageAttachmentViewHolder.kt
View file @
26ead887
...
...
@@ -30,7 +30,7 @@ class ImageAttachmentViewHolder(
file_name
.
text
=
data
.
attachmentTitle
image_attachment
.
setOnClickListener
{
ImageHelper
.
openImage
(
it
.
context
,
context
,
data
.
attachmentUrl
,
data
.
attachmentTitle
.
toString
()
)
...
...
app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomPresenter.kt
View file @
26ead887
...
...
@@ -181,11 +181,9 @@ class ChatRoomPresenter @Inject constructor(
}
subscribeTypingStatus
()
if
(
offset
==
0L
)
{
subscribeState
()
}
}
}
private
suspend
fun
loadAndShowMessages
(
chatRoomId
:
String
,
chatRoomType
:
String
,
offset
:
Long
=
0
)
{
val
messages
=
...
...
@@ -229,10 +227,9 @@ class ChatRoomPresenter @Inject constructor(
)
try
{
messagesRepository
.
save
(
newMessage
)
val
message
=
client
.
sendMessage
(
id
,
chatRoomId
,
text
)
view
.
showNewMessage
(
mapper
.
map
(
newMessage
,
RoomViewModel
(
roles
=
chatRoles
,
isBroadcast
=
chatIsBroadcast
)))
message
client
.
sendMessage
(
id
,
chatRoomId
,
text
)
}
catch
(
ex
:
Exception
)
{
// Ok, not very beautiful, but the backend sends us a not valid response
// When someone sends a message on a read-only channel, so we just ignore it
...
...
@@ -324,7 +321,7 @@ class ChatRoomPresenter @Inject constructor(
}
}
private
fun
subscribeState
()
{
private
suspend
fun
subscribeState
()
{
Timber
.
d
(
"Subscribing to Status changes"
)
lastState
=
manager
.
state
manager
.
addStatusChannel
(
stateChannel
)
...
...
@@ -790,6 +787,7 @@ class ChatRoomPresenter @Inject constructor(
}
private
suspend
fun
subscribeTypingStatus
()
{
launch
(
CommonPool
+
strategy
.
jobs
)
{
client
.
subscribeTypingStatus
(
chatRoomId
.
toString
())
{
_
,
id
->
typingStatusSubscriptionId
=
id
}
...
...
@@ -798,6 +796,7 @@ class ChatRoomPresenter @Inject constructor(
processTypingStatus
(
typingStatus
)
}
}
}
private
fun
processTypingStatus
(
typingStatus
:
Pair
<
String
,
Boolean
>)
{
if
(!
typingStatusList
.
any
{
username
->
username
==
typingStatus
.
first
})
{
...
...
@@ -837,6 +836,7 @@ class ChatRoomPresenter @Inject constructor(
launchUI
(
strategy
)
{
val
viewModelStreamedMessage
=
mapper
.
map
(
streamedMessage
,
RoomViewModel
(
roles
=
chatRoles
,
isBroadcast
=
chatIsBroadcast
))
val
roomMessages
=
messagesRepository
.
getByRoomId
(
streamedMessage
.
roomId
)
val
index
=
roomMessages
.
indexOfFirst
{
msg
->
msg
.
id
==
streamedMessage
.
id
}
if
(
index
>
-
1
)
{
...
...
app/src/main/java/chat/rocket/android/chatroom/service/MessageService.kt
View file @
26ead887
...
...
@@ -64,7 +64,7 @@ class MessageService : JobService() {
Timber
.
e
(
ex
)
// TODO - remove the generic message when we implement :userId:/message subscription
if
(
ex
is
IllegalStateException
)
{
Timber
.
d
(
ex
,
"Probably a read-only problem..."
)
Timber
.
e
(
ex
,
"Probably a read-only problem..."
)
// TODO: For now we are only going to reschedule when api is fixed.
messageRepository
.
removeById
(
message
.
id
)
jobFinished
(
params
,
false
)
...
...
app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
View file @
26ead887
...
...
@@ -31,6 +31,8 @@ import chat.rocket.android.helper.KeyboardHelper
import
chat.rocket.android.helper.MessageParser
import
chat.rocket.android.util.extensions.*
import
chat.rocket.android.widget.emoji.*
import
chat.rocket.common.model.RoomType
import
chat.rocket.common.model.roomTypeOf
import
chat.rocket.core.internal.realtime.socket.model.State
import
chat.rocket.core.model.ChatRoom
import
dagger.android.support.AndroidSupportInjection
...
...
@@ -243,7 +245,9 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
if
(
recycler_view
.
adapter
==
null
)
{
adapter
=
ChatRoomAdapter
(
chatRoomType
,
chatRoomName
,
presenter
,
chatRoomType
,
chatRoomName
,
presenter
,
reactionListener
=
this
@ChatRoomFragment
)
recycler_view
.
adapter
=
adapter
...
...
@@ -272,10 +276,12 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
)
{
// TODO: We should rely solely on the user being able to post, but we cannot guarantee
// that the "(channels|groups).roles" endpoint is supported by the server in use.
ui
{
setupMessageComposer
(
userCanPost
)
isBroadcastChannel
=
channelIsBroadcast
if
(
isBroadcastChannel
&&
!
userCanMod
)
activity
?.
invalidateOptionsMenu
()
}
}
override
fun
openDirectMessage
(
chatRoom
:
ChatRoom
,
permalink
:
String
)
{
...
...
@@ -647,12 +653,11 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
if
(
isChatRoomReadOnly
&&
!
canPost
)
{
text_room_is_read_only
.
setVisible
(
true
)
input_container
.
setVisible
(
false
)
}
else
if
(!
isSubscribed
)
{
}
else
if
(!
isSubscribed
&&
roomTypeOf
(
chatRoomType
)
!=
RoomType
.
DIRECT_MESSAGE
)
{
input_container
.
setVisible
(
false
)
button_join_chat
.
setVisible
(
true
)
button_join_chat
.
setOnClickListener
{
presenter
.
joinChat
(
chatRoomId
)
}
}
else
{
button_send
.
alpha
=
0f
button_send
.
setVisible
(
false
)
button_show_attachment_options
.
alpha
=
1f
button_show_attachment_options
.
setVisible
(
true
)
...
...
@@ -788,14 +793,14 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
private
fun
setupComposeButtons
(
charSequence
:
CharSequence
)
{
if
(
charSequence
.
isNotEmpty
()
&&
playComposeMessageButtonsAnimation
)
{
button_show_attachment_options
.
fadeOut
(
1F
,
0F
,
120
)
button_send
.
fadeIn
(
0F
,
1F
,
120
)
button_show_attachment_options
.
setVisible
(
false
)
button_send
.
setVisible
(
true
)
playComposeMessageButtonsAnimation
=
false
}
if
(
charSequence
.
isEmpty
())
{
button_send
.
fadeOut
(
1F
,
0F
,
120
)
button_show_attachment_options
.
fadeIn
(
0F
,
1F
,
120
)
button_send
.
setVisible
(
false
)
button_show_attachment_options
.
setVisible
(
true
)
playComposeMessageButtonsAnimation
=
true
}
}
...
...
app/src/main/java/chat/rocket/android/chatroom/viewmodel/MessageViewModel.kt
View file @
26ead887
app/src/main/java/chat/rocket/android/chatroom/viewmodel/ReactionViewModel.kt
View file @
26ead887
app/src/main/java/chat/rocket/android/chatroom/viewmodel/ViewModelMapper.kt
View file @
26ead887
...
...
@@ -65,24 +65,35 @@ class ViewModelMapper @Inject constructor(
private
val
currentUsername
:
String
?
=
localRepository
.
get
(
LocalRepository
.
CURRENT_USERNAME_KEY
)
private
val
secondaryTextColor
=
ContextCompat
.
getColor
(
context
,
R
.
color
.
colorSecondaryText
)
suspend
fun
map
(
message
:
Message
,
roomViewModel
:
RoomViewModel
=
RoomViewModel
(
roles
=
emptyList
(),
isBroadcast
=
true
)):
List
<
BaseViewModel
<*
>>
{
suspend
fun
map
(
message
:
Message
,
roomViewModel
:
RoomViewModel
=
RoomViewModel
(
roles
=
emptyList
(),
isBroadcast
=
true
)
):
List
<
BaseViewModel
<*
>>
{
return
translate
(
message
,
roomViewModel
)
}
suspend
fun
map
(
messages
:
List
<
Message
>,
roomViewModel
:
RoomViewModel
=
RoomViewModel
(
roles
=
emptyList
(),
isBroadcast
=
true
)):
List
<
BaseViewModel
<*
>>
=
withContext
(
CommonPool
)
{
suspend
fun
map
(
messages
:
List
<
Message
>,
roomViewModel
:
RoomViewModel
=
RoomViewModel
(
roles
=
emptyList
(),
isBroadcast
=
true
),
asNotReversed
:
Boolean
=
false
):
List
<
BaseViewModel
<*
>>
=
withContext
(
CommonPool
)
{
val
list
=
ArrayList
<
BaseViewModel
<*>>(
messages
.
size
)
messages
.
forEach
{
list
.
addAll
(
translate
(
it
,
roomViewModel
))
list
.
addAll
(
if
(
asNotReversed
)
translateAsNotReversed
(
it
,
roomViewModel
)
else
translate
(
it
,
roomViewModel
)
)
}
return
@withContext
list
}
private
suspend
fun
translate
(
message
:
Message
,
roomViewModel
:
RoomViewModel
)
:
List
<
BaseViewModel
<*
>>
=
withContext
(
CommonPool
)
{
private
suspend
fun
translate
(
message
:
Message
,
roomViewModel
:
RoomViewModel
):
List
<
BaseViewModel
<*
>>
=
withContext
(
CommonPool
)
{
val
list
=
ArrayList
<
BaseViewModel
<*>>()
message
.
urls
?.
forEach
{
...
...
@@ -118,6 +129,56 @@ class ViewModelMapper @Inject constructor(
return
@withContext
list
}
private
suspend
fun
translateAsNotReversed
(
message
:
Message
,
roomViewModel
:
RoomViewModel
):
List
<
BaseViewModel
<*
>>
=
withContext
(
CommonPool
)
{
val
list
=
ArrayList
<
BaseViewModel
<*>>()
mapMessage
(
message
).
let
{
if
(
list
.
isNotEmpty
())
{
it
.
preview
=
list
.
first
().
preview
}
list
.
add
(
it
)
}
message
.
attachments
?.
forEach
{
val
attachment
=
mapAttachment
(
message
,
it
)
attachment
?.
let
{
list
.
add
(
attachment
)
}
}
message
.
urls
?.
forEach
{
val
url
=
mapUrl
(
message
,
it
)
url
?.
let
{
list
.
add
(
url
)
}
}
for
(
i
in
list
.
size
-
1
downTo
0
)
{
val
next
=
if
(
i
-
1
<
0
)
null
else
list
[
i
-
1
]
list
[
i
].
nextDownStreamMessage
=
next
}
if
(
isBroadcastReplyAvailable
(
roomViewModel
,
message
))
{
roomsInteractor
.
getById
(
currentServer
,
message
.
roomId
)
?.
let
{
chatRoom
->
val
replyViewModel
=
mapMessageReply
(
message
,
chatRoom
)
list
.
first
().
nextDownStreamMessage
=
replyViewModel
list
.
add
(
0
,
replyViewModel
)
}
}
list
.
dropLast
(
1
).
forEach
{
it
.
reactions
=
emptyList
()
}
list
.
last
().
reactions
=
getReactions
(
message
)
list
.
last
().
nextDownStreamMessage
=
null
return
@withContext
list
}
private
fun
isBroadcastReplyAvailable
(
roomViewModel
:
RoomViewModel
,
message
:
Message
):
Boolean
{
val
senderUsername
=
message
.
sender
?.
username
return
roomViewModel
.
isRoom
&&
roomViewModel
.
isBroadcast
&&
...
...
@@ -127,8 +188,8 @@ class ViewModelMapper @Inject constructor(
private
fun
mapMessageReply
(
message
:
Message
,
chatRoom
:
ChatRoom
):
MessageReplyViewModel
{
val
name
=
message
.
sender
?.
name
val
roomName
=
if
(
settings
.
useRealName
()
&&
name
!=
null
)
name
else
message
.
sender
?.
username
?:
""
val
roomName
=
if
(
settings
.
useRealName
()
&&
name
!=
null
)
name
else
message
.
sender
?.
username
?:
""
val
permalink
=
messageHelper
.
createPermalink
(
message
,
chatRoom
)
return
MessageReplyViewModel
(
messageId
=
message
.
id
,
...
...
app/src/main/java/chat/rocket/android/chatrooms/presentation/ChatRoomsPresenter.kt
View file @
26ead887
...
...
@@ -34,6 +34,7 @@ import chat.rocket.common.model.SimpleUser
import
chat.rocket.common.model.User
import
chat.rocket.common.util.ifNull
import
chat.rocket.core.internal.model.Subscription
import
chat.rocket.core.internal.realtime.createDirectMessage
import
chat.rocket.core.internal.realtime.socket.model.State
import
chat.rocket.core.internal.realtime.socket.model.StreamMessage
import
chat.rocket.core.internal.realtime.socket.model.Type
...
...
@@ -124,8 +125,19 @@ class ChatRoomsPresenter @Inject constructor(
if
(
myself
?.
username
==
null
)
{
view
.
showMessage
(
R
.
string
.
msg_generic_error
)
}
else
{
val
id
=
if
(
isDirectMessage
&&
!
chatRoom
.
open
)
{
retryIO
(
"createDirectMessage(${chatRoom.name})"
)
{
client
.
createDirectMessage
(
chatRoom
.
name
)
}
val
fromTo
=
mutableListOf
(
myself
.
id
,
chatRoom
.
id
).
apply
{
sort
()
}
fromTo
.
joinToString
(
""
)
}
else
{
chatRoom
.
id
}
val
isChatRoomOwner
=
chatRoom
.
user
?.
username
==
myself
.
username
||
isDirectMessage
navigator
.
toChatRoom
(
chatRoom
.
id
,
roomName
,
navigator
.
toChatRoom
(
id
,
roomName
,
chatRoom
.
type
.
toString
(),
chatRoom
.
readonly
?:
false
,
chatRoom
.
lastSeen
?:
-
1
,
chatRoom
.
open
,
isChatRoomOwner
)
...
...
@@ -210,7 +222,7 @@ class ChatRoomsPresenter @Inject constructor(
}
else
{
null
},
name
=
it
.
name
?:
""
,
name
=
it
.
username
?:
it
.
name
?:
""
,
fullName
=
it
.
name
,
readonly
=
false
,
updatedAt
=
null
,
...
...
@@ -640,4 +652,10 @@ class ChatRoomsPresenter @Inject constructor(
manager
.
removeRoomsAndSubscriptionsChannel
(
subscriptionsChannel
)
manager
.
removeActiveUserChannel
(
activeUserChannel
)
}
fun
goToChatRoomWithId
(
chatRoomId
:
String
)
{
launchUI
(
strategy
)
{
chatRoomsInteractor
.
getById
(
currentServer
,
chatRoomId
)
?.
let
{
loadChatRoom
(
it
)
}
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatrooms/ui/ChatRoomsFragment.kt
View file @
26ead887
package
chat.rocket.android.chatrooms.ui
import
android.app.AlertDialog
import
android.content.Context
import
android.content.SharedPreferences
import
android.os.Bundle
import
android.os.Handler
import
android.support.v4.app.Fragment
...
...
@@ -11,7 +9,12 @@ import android.support.v7.util.DiffUtil
import
android.support.v7.widget.DefaultItemAnimator
import
android.support.v7.widget.LinearLayoutManager
import
android.support.v7.widget.SearchView
import
android.view.*
import
android.view.LayoutInflater
import
android.view.Menu
import
android.view.MenuInflater
import
android.view.MenuItem
import
android.view.View
import
android.view.ViewGroup
import
android.widget.CheckBox
import
android.widget.RadioGroup
import
androidx.core.view.isVisible
...
...
@@ -24,7 +27,12 @@ import chat.rocket.android.helper.SharedPreferenceHelper
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.server.domain.GetCurrentServerInteractor
import
chat.rocket.android.server.domain.SettingsRepository
import
chat.rocket.android.util.extensions.*
import
chat.rocket.android.util.extensions.fadeIn
import
chat.rocket.android.util.extensions.fadeOut
import
chat.rocket.android.util.extensions.inflate
import
chat.rocket.android.util.extensions.setVisible
import
chat.rocket.android.util.extensions.showToast
import
chat.rocket.android.util.extensions.ui
import
chat.rocket.android.widget.DividerItemDecoration
import
chat.rocket.common.model.RoomType
import
chat.rocket.core.internal.realtime.socket.model.State
...
...
@@ -36,6 +44,8 @@ import kotlinx.coroutines.experimental.NonCancellable.isActive
import
timber.log.Timber
import
javax.inject.Inject
private
const
val
BUNDLE_CHAT_ROOM_ID
=
"BUNDLE_CHAT_ROOM_ID"
class
ChatRoomsFragment
:
Fragment
(),
ChatRoomsView
{
@Inject
lateinit
var
presenter
:
ChatRoomsPresenter
...
...
@@ -50,15 +60,30 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
private
var
listJob
:
Job
?
=
null
private
var
sectionedAdapter
:
SimpleSectionedRecyclerViewAdapter
?
=
null
private
var
chatRoomId
:
String
?
=
null
companion
object
{
fun
newInstance
()
=
ChatRoomsFragment
()
fun
newInstance
(
chatRoomId
:
String
?
=
null
):
ChatRoomsFragment
{
return
ChatRoomsFragment
().
apply
{
arguments
=
Bundle
(
1
).
apply
{
putString
(
BUNDLE_CHAT_ROOM_ID
,
chatRoomId
)
}
}
}
}
override
fun
onCreate
(
savedInstanceState
:
Bundle
?)
{
super
.
onCreate
(
savedInstanceState
)
AndroidSupportInjection
.
inject
(
this
)
setHasOptionsMenu
(
true
)
val
bundle
=
arguments
if
(
bundle
!=
null
)
{
chatRoomId
=
bundle
.
getString
(
BUNDLE_CHAT_ROOM_ID
)
chatRoomId
?.
let
{
presenter
.
goToChatRoomWithId
(
it
)
chatRoomId
=
null
}
}
}
override
fun
onDestroy
()
{
...
...
app/src/main/java/chat/rocket/android/dagger/module/ServiceBuilder.kt
View file @
26ead887
...
...
@@ -2,10 +2,10 @@ package chat.rocket.android.dagger.module
import
chat.rocket.android.chatroom.di.MessageServiceProvider
import
chat.rocket.android.chatroom.service.MessageService
import
chat.rocket.android.push.FirebaseMessagingService
import
chat.rocket.android.push.FirebaseTokenService
import
chat.rocket.android.push.
GcmListenerService
import
chat.rocket.android.push.
di.FirebaseMessagingServiceProvider
import
chat.rocket.android.push.di.FirebaseTokenServiceProvider
import
chat.rocket.android.push.di.GcmListenerServiceProvider
import
dagger.Module
import
dagger.android.ContributesAndroidInjector
...
...
@@ -14,8 +14,8 @@ import dagger.android.ContributesAndroidInjector
@ContributesAndroidInjector
(
modules
=
[
FirebaseTokenServiceProvider
::
class
])
abstract
fun
bindFirebaseTokenService
():
FirebaseTokenService
@ContributesAndroidInjector
(
modules
=
[
GcmListener
ServiceProvider
::
class
])
abstract
fun
bindGcmListenerService
():
GcmListener
Service
@ContributesAndroidInjector
(
modules
=
[
FirebaseMessaging
ServiceProvider
::
class
])
abstract
fun
bindGcmListenerService
():
FirebaseMessaging
Service
@ContributesAndroidInjector
(
modules
=
[
MessageServiceProvider
::
class
])
abstract
fun
bindMessageService
():
MessageService
...
...
app/src/main/java/chat/rocket/android/favoritemessages/presentation/FavoriteMessagesPresenter.kt
View file @
26ead887
...
...
@@ -25,9 +25,9 @@ class FavoriteMessagesPresenter @Inject constructor(
private
var
offset
:
Int
=
0
/**
* Loads all favorite messages for
room.
the given room id.
* Loads all favorite messages for the given room id.
*
* @param roomId The id of the room to get
its favorite messages
.
* @param roomId The id of the room to get
favorite messages from
.
*/
fun
loadFavoriteMessages
(
roomId
:
String
)
{
launchUI
(
strategy
)
{
...
...
@@ -35,7 +35,7 @@ class FavoriteMessagesPresenter @Inject constructor(
view
.
showLoading
()
roomsInteractor
.
getById
(
serverUrl
,
roomId
)
?.
let
{
val
favoriteMessages
=
client
.
getFavoriteMessages
(
roomId
,
it
.
type
,
offset
)
val
messageList
=
mapper
.
map
(
favoriteMessages
.
result
)
val
messageList
=
mapper
.
map
(
favoriteMessages
.
result
,
asNotReversed
=
true
)
view
.
showFavoriteMessages
(
messageList
)
offset
+=
1
*
30
}.
ifNull
{
...
...
app/src/main/java/chat/rocket/android/favoritemessages/ui/FavoriteMessagesFragment.kt
View file @
26ead887
...
...
@@ -72,7 +72,7 @@ class FavoriteMessagesFragment : Fragment(), FavoriteMessagesView {
LinearLayoutManager
(
context
,
LinearLayoutManager
.
VERTICAL
,
false
)
recycler_view
.
layoutManager
=
linearLayoutManager
recycler_view
.
itemAnimator
=
DefaultItemAnimator
()
if
(
favoriteMessages
.
size
>
1
0
)
{
if
(
favoriteMessages
.
size
>
=
3
0
)
{
recycler_view
.
addOnScrollListener
(
object
:
EndlessRecyclerViewScrollListener
(
linearLayoutManager
)
{
override
fun
onLoadMore
(
...
...
app/src/main/java/chat/rocket/android/files/ui/FilesFragment.kt
View file @
26ead887
...
...
@@ -94,17 +94,13 @@ class FilesFragment : Fragment(), FilesView {
override
fun
playMedia
(
url
:
String
)
{
ui
{
activity
?.
let
{
PlayerActivity
.
play
(
it
,
url
)
}
}
}
override
fun
openImage
(
url
:
String
,
name
:
String
)
{
ui
{
activity
?.
let
{
ImageHelper
.
openImage
(
it
,
url
,
name
)
}
ImageHelper
.
openImage
(
root_layout
.
context
,
url
,
name
)
}
}
...
...
app/src/main/java/chat/rocket/android/files/viewmodel/FileViewModel.kt
View file @
26ead887
...
...
@@ -41,9 +41,10 @@ class FileViewModel(
}
private
fun
getFileUploadDate
():
String
{
return
DateTimeHelper
.
getDateTime
(
DateTimeHelper
.
getLocalDateTime
(
genericAttachment
.
uploadedAt
)
)
genericAttachment
.
uploadedAt
?.
let
{
return
DateTimeHelper
.
getDateTime
(
DateTimeHelper
.
getLocalDateTime
(
it
))
}
return
""
}
private
fun
getFileUrl
():
String
?
{
...
...
app/src/main/java/chat/rocket/android/helper/ImageHelper.kt
View file @
26ead887
...
...
@@ -53,7 +53,6 @@ object ImageHelper {
)
val
toolbar
=
Toolbar
(
context
).
also
{
it
.
inflateMenu
(
R
.
menu
.
image_actions
)
it
.
overflowIcon
?.
setTint
(
Color
.
WHITE
)
it
.
setOnMenuItemClickListener
{
return
@setOnMenuItemClickListener
when
(
it
.
itemId
)
{
R
.
id
.
action_save_image
->
saveImage
(
context
)
...
...
@@ -109,7 +108,6 @@ object ImageHelper {
.
hideStatusBar
(
false
)
.
setCustomDraweeControllerBuilder
(
builder
)
.
show
()
}
private
fun
saveImage
(
context
:
Context
):
Boolean
{
...
...
@@ -166,5 +164,4 @@ object ImageHelper {
)
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/helper/SmartLockHelper.kt
0 → 100644
View file @
26ead887
package
chat.rocket.android.helper
import
android.app.Activity
import
android.content.IntentSender
import
android.support.v4.app.FragmentActivity
import
com.google.android.gms.auth.api.credentials.*
import
com.google.android.gms.common.api.CommonStatusCodes
import
com.google.android.gms.common.api.ResolvableApiException
import
timber.log.Timber
const
val
REQUEST_CODE_FOR_SIGN_IN_REQUIRED
=
1
const
val
REQUEST_CODE_FOR_MULTIPLE_ACCOUNTS_RESOLUTION
=
2
const
val
REQUEST_CODE_FOR_SAVE_RESOLUTION
=
3
/**
* This class handles some cases of Google Smart Lock for passwords like the request to retrieve
* credentials, to retrieve sign-in hints and to store the credentials.
*
* See https://developers.google.com/identity/smartlock-passwords/android/overview for futher
* information.
*/
object
SmartLockHelper
{
/**
* Requests for stored Google Smart Lock credentials.
* Note that in case of exception it will try to start a sign in
* ([REQUEST_CODE_FOR_SIGN_IN_REQUIRED]) or "multiple account"
* ([REQUEST_CODE_FOR_MULTIPLE_ACCOUNTS_RESOLUTION]) resolution.
*
* @param credentialsClient The credential client.
* @param activity The activity.
* @return null or the [Credential] result.
*/
fun
requestStoredCredentials
(
credentialsClient
:
CredentialsClient
,
activity
:
Activity
):
Credential
?
{
var
credential
:
Credential
?
=
null
val
credentialRequest
=
CredentialRequest
.
Builder
()
.
setPasswordLoginSupported
(
true
)
.
build
()
credentialsClient
.
request
(
credentialRequest
)
.
addOnCompleteListener
{
when
{
it
.
isSuccessful
->
{
credential
=
it
.
result
.
credential
}
it
.
exception
is
ResolvableApiException
->
{
val
resolvableApiException
=
(
it
.
exception
as
ResolvableApiException
)
if
(
resolvableApiException
.
statusCode
==
CommonStatusCodes
.
SIGN_IN_REQUIRED
)
{
provideSignInHint
(
credentialsClient
,
activity
)
}
else
{
// This is most likely the case where the user has multiple saved
// credentials and needs to pick one. This requires showing UI to
// resolve the read request.
resolveResult
(
resolvableApiException
,
REQUEST_CODE_FOR_MULTIPLE_ACCOUNTS_RESOLUTION
,
activity
)
}
}
}
}
return
credential
}
/**
* Saves a user credential to Google Smart Lock.
* Note that in case of exception it will try to start a save resolution,
* so the activity/fragment should expected for a request code
* ([REQUEST_CODE_FOR_SAVE_RESOLUTION]) on onActivityResult call.
*
* @param credentialsClient The credential client.
* @param activity The activity.
* @param id The user id credential.
* @param password The user password credential.
*/
fun
save
(
credentialsClient
:
CredentialsClient
,
activity
:
FragmentActivity
,
id
:
String
,
password
:
String
)
{
val
credential
=
Credential
.
Builder
(
id
)
.
setPassword
(
password
)
.
build
()
credentialsClient
.
save
(
credential
)
.
addOnCompleteListener
{
val
exception
=
it
.
exception
if
(
exception
is
ResolvableApiException
)
{
// Try to resolve the save request. This will prompt the user if
// the credential is new.
try
{
exception
.
startResolutionForResult
(
activity
,
REQUEST_CODE_FOR_SAVE_RESOLUTION
)
}
catch
(
e
:
IntentSender
.
SendIntentException
)
{
Timber
.
e
(
"Failed to send resolution. Exception is: $e"
)
}
}
}
}
private
fun
provideSignInHint
(
credentialsClient
:
CredentialsClient
,
activity
:
Activity
)
{
val
hintRequest
=
HintRequest
.
Builder
()
.
setHintPickerConfig
(
CredentialPickerConfig
.
Builder
()
.
setShowCancelButton
(
true
)
.
build
()
)
.
setEmailAddressIdentifierSupported
(
true
)
.
build
()
try
{
val
intent
=
credentialsClient
.
getHintPickerIntent
(
hintRequest
)
activity
.
startIntentSenderForResult
(
intent
.
intentSender
,
REQUEST_CODE_FOR_SIGN_IN_REQUIRED
,
null
,
0
,
0
,
0
,
null
)
}
catch
(
e
:
IntentSender
.
SendIntentException
)
{
Timber
.
e
(
"Could not start hint picker Intent. Exception is: $e"
)
}
}
private
fun
resolveResult
(
exception
:
ResolvableApiException
,
requestCode
:
Int
,
activity
:
Activity
)
{
try
{
exception
.
startResolutionForResult
(
activity
,
requestCode
)
}
catch
(
e
:
IntentSender
.
SendIntentException
)
{
Timber
.
e
(
"Failed to send resolution. Exception is: $e"
)
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/main/presentation/MainNavigator.kt
View file @
26ead887
...
...
@@ -12,9 +12,9 @@ import chat.rocket.android.util.extensions.addFragment
class
MainNavigator
(
internal
val
activity
:
MainActivity
)
{
fun
toChatList
()
{
fun
toChatList
(
chatRoomId
:
String
?
=
null
)
{
activity
.
addFragment
(
"ChatRoomsFragment"
,
R
.
id
.
fragment_container
)
{
ChatRoomsFragment
.
newInstance
()
ChatRoomsFragment
.
newInstance
(
chatRoomId
)
}
}
...
...
@@ -43,7 +43,7 @@ class MainNavigator(internal val activity: MainActivity) {
}
fun
toNewServer
(
serverUrl
:
String
?
=
null
)
{
activity
.
startActivity
(
activity
.
changeServerIntent
(
serverUrl
))
activity
.
startActivity
(
activity
.
changeServerIntent
(
serverUrl
=
serverUrl
))
activity
.
finish
()
}
...
...
app/src/main/java/chat/rocket/android/main/presentation/MainPresenter.kt
View file @
26ead887
...
...
@@ -49,7 +49,7 @@ class MainPresenter @Inject constructor(
private
val
userDataChannel
=
Channel
<
Myself
>()
fun
toChatList
(
)
=
navigator
.
toChatList
(
)
fun
toChatList
(
chatRoomId
:
String
?
=
null
)
=
navigator
.
toChatList
(
chatRoomId
)
fun
toUserProfile
()
=
navigator
.
toUserProfile
()
...
...
@@ -105,13 +105,10 @@ class MainPresenter @Inject constructor(
disconnect
()
removeAccountInteractor
.
remove
(
currentServer
)
tokenRepository
.
remove
(
currentServer
)
view
.
disableAutoSignIn
()
navigator
.
toNewServer
()
}
catch
(
ex
:
Exception
)
{
Timber
.
d
(
ex
,
"Error cleaning up the session..."
)
}
view
.
disableAutoSignIn
()
navigator
.
toNewServer
()
}
}
...
...
@@ -178,6 +175,7 @@ class MainPresenter @Inject constructor(
if
(
pushToken
!=
null
)
{
try
{
retryIO
(
"unregisterPushToken"
)
{
client
.
unregisterPushToken
(
pushToken
)
}
view
.
invalidateToken
(
pushToken
)
}
catch
(
ex
:
Exception
)
{
Timber
.
d
(
ex
,
"Error unregistering push token"
)
}
...
...
app/src/main/java/chat/rocket/android/main/presentation/MainView.kt
View file @
26ead887
...
...
@@ -25,8 +25,5 @@ interface MainView : MessageView, VersionCheckView {
fun
closeServerSelection
()
/**
* callback to disable auto sign in for google smart lock when the user logs out
*/
fun
disableAutoSignIn
()
fun
invalidateToken
(
token
:
String
)
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/main/ui/MainActivity.kt
View file @
26ead887
...
...
@@ -18,15 +18,15 @@ import chat.rocket.android.main.presentation.MainPresenter
import
chat.rocket.android.main.presentation.MainView
import
chat.rocket.android.main.viewmodel.NavHeaderViewModel
import
chat.rocket.android.server.domain.model.Account
import
chat.rocket.android.server.ui.INTENT_CHAT_ROOM_ID
import
chat.rocket.android.util.extensions.fadeIn
import
chat.rocket.android.util.extensions.fadeOut
import
chat.rocket.android.util.extensions.rotateBy
import
chat.rocket.android.util.extensions.showToast
import
chat.rocket.common.model.UserStatus
import
com.google.android.gms.auth.api.Auth
import
com.google.firebase.iid.FirebaseInstanceId
import
com.google.firebase.messaging.FirebaseMessaging
import
com.google.android.gms.common.api.GoogleApiClient
import
com.google.android.gms.gcm.GoogleCloudMessaging
import
com.google.android.gms.iid.InstanceID
import
dagger.android.AndroidInjection
import
dagger.android.AndroidInjector
import
dagger.android.DispatchingAndroidInjector
...
...
@@ -40,8 +40,10 @@ import kotlinx.coroutines.experimental.launch
import
timber.log.Timber
import
javax.inject.Inject
class
MainActivity
:
AppCompatActivity
(),
MainView
,
HasActivityInjector
,
HasSupportFragmentInjector
,
GoogleApiClient
.
ConnectionCallbacks
{
private
const
val
CURRENT_STATE
=
"current_state"
class
MainActivity
:
AppCompatActivity
(),
MainView
,
HasActivityInjector
,
HasSupportFragmentInjector
{
@Inject
lateinit
var
activityDispatchingAndroidInjector
:
DispatchingAndroidInjector
<
Activity
>
@Inject
...
...
@@ -50,73 +52,46 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, HasSupp
lateinit
var
presenter
:
MainPresenter
private
var
isFragmentAdded
:
Boolean
=
false
private
var
expanded
=
false
private
lateinit
var
googleApiClient
:
GoogleApiClient
private
val
headerLayout
by
lazy
{
view_navigation
.
getHeaderView
(
0
)
}
private
va
l
CURRENT_STATE
=
"current_state"
private
va
r
chatRoomId
:
String
?
=
null
override
fun
onCreate
(
savedInstanceState
:
Bundle
?)
{
AndroidInjection
.
inject
(
this
)
super
.
onCreate
(
savedInstanceState
)
setContentView
(
R
.
layout
.
activity_main
)
buildGoogleApiClient
()
launch
(
CommonPool
)
{
try
{
val
token
=
InstanceID
.
getInstance
(
this
@MainActivity
).
getToken
(
getString
(
R
.
string
.
gcm_sender_id
),
GoogleCloudMessaging
.
INSTANCE_ID_SCOPE
,
null
)
Timber
.
d
(
"GCM token: $token"
)
val
token
=
FirebaseInstanceId
.
getInstance
().
token
Timber
.
d
(
"FCM token: $token"
)
presenter
.
refreshToken
(
token
)
}
catch
(
ex
:
Exception
)
{
Timber
.
d
(
ex
,
"Missing play services..."
)
}
}
chatRoomId
=
intent
.
getStringExtra
(
INTENT_CHAT_ROOM_ID
)
presenter
.
connect
()
presenter
.
loadCurrentInfo
()
setupToolbar
()
setupNavigationView
()
}
override
fun
onConnected
(
bundle
:
Bundle
?)
{
}
override
fun
onConnectionSuspended
(
errorCode
:
Int
)
{
}
private
fun
buildGoogleApiClient
()
{
googleApiClient
=
GoogleApiClient
.
Builder
(
this
)
.
enableAutoManage
(
this
,
{
Timber
.
d
(
"ERROR: connection to client failed"
)
})
.
addConnectionCallbacks
(
this
)
.
addApi
(
Auth
.
CREDENTIALS_API
)
.
build
()
}
override
fun
onStart
()
{
super
.
onStart
()
googleApiClient
.
let
{
if
(
it
.
isConnected
)
{
Timber
.
d
(
"Google api client connected successfully"
)
}
}
override
fun
onSaveInstanceState
(
outState
:
Bundle
?)
{
super
.
onSaveInstanceState
(
outState
)
outState
?.
putBoolean
(
CURRENT_STATE
,
isFragmentAdded
)
}
override
fun
disableAutoSignIn
()
{
googleApiClient
.
let
{
if
(
it
.
isConnected
)
{
Auth
.
CredentialsApi
.
disableAutoSignIn
(
googleApiClient
)
}
}
override
fun
onRestoreInstanceState
(
savedInstanceState
:
Bundle
?)
{
super
.
onRestoreInstanceState
(
savedInstanceState
)
isFragmentAdded
=
savedInstanceState
?.
getBoolean
(
CURRENT_STATE
)
?:
false
}
override
fun
onResume
()
{
super
.
onResume
()
if
(!
isFragmentAdded
)
{
presenter
.
toChatList
()
presenter
.
toChatList
(
chatRoomId
)
isFragmentAdded
=
true
}
}
...
...
@@ -128,6 +103,12 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, HasSupp
}
}
override
fun
activityInjector
():
AndroidInjector
<
Activity
>
=
activityDispatchingAndroidInjector
override
fun
supportFragmentInjector
():
AndroidInjector
<
Fragment
>
=
fragmentDispatchingAndroidInjector
override
fun
showUserStatus
(
userStatus
:
UserStatus
)
{
headerLayout
.
apply
{
image_user_status
.
setImageDrawable
(
...
...
@@ -191,38 +172,8 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, HasSupp
.
show
()
}
private
fun
setupAccountsList
(
header
:
View
,
accounts
:
List
<
Account
>)
{
accounts_list
.
layoutManager
=
LinearLayoutManager
(
this
)
accounts_list
.
adapter
=
AccountsAdapter
(
accounts
,
object
:
Selector
{
override
fun
onStatusSelected
(
userStatus
:
UserStatus
)
{
presenter
.
changeDefaultStatus
(
userStatus
)
}
override
fun
onAccountSelected
(
serverUrl
:
String
)
{
presenter
.
changeServer
(
serverUrl
)
}
override
fun
onAddedAccountSelected
()
{
presenter
.
addNewServer
()
}
})
header
.
account_container
.
setOnClickListener
{
header
.
image_account_expand
.
rotateBy
(
180f
)
if
(
expanded
)
{
accounts_list
.
fadeOut
()
}
else
{
accounts_list
.
fadeIn
()
}
expanded
=
!
expanded
}
header
.
image_avatar
.
setOnClickListener
{
view_navigation
.
menu
.
findItem
(
R
.
id
.
action_profile
).
isChecked
=
true
presenter
.
toUserProfile
()
drawer_layout
.
closeDrawer
(
Gravity
.
START
)
}
override
fun
invalidateToken
(
token
:
String
)
{
FirebaseInstanceId
.
getInstance
().
deleteToken
(
token
,
FirebaseMessaging
.
INSTANCE_ID_SCOPE
)
}
override
fun
showMessage
(
resId
:
Int
)
=
showToast
(
resId
)
...
...
@@ -231,11 +182,6 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, HasSupp
override
fun
showGenericErrorMessage
()
=
showMessage
(
getString
(
R
.
string
.
msg_generic_error
))
override
fun
activityInjector
():
AndroidInjector
<
Activity
>
=
activityDispatchingAndroidInjector
override
fun
supportFragmentInjector
():
AndroidInjector
<
Fragment
>
=
fragmentDispatchingAndroidInjector
private
fun
setupToolbar
()
{
setSupportActionBar
(
toolbar
)
toolbar
.
setNavigationIcon
(
R
.
drawable
.
ic_menu_white_24dp
)
...
...
@@ -270,13 +216,37 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, HasSupp
}
}
override
fun
onSaveInstanceState
(
outState
:
Bundle
?)
{
super
.
onSaveInstanceState
(
outState
)
outState
?.
putBoolean
(
CURRENT_STATE
,
isFragmentAdded
)
private
fun
setupAccountsList
(
header
:
View
,
accounts
:
List
<
Account
>)
{
accounts_list
.
layoutManager
=
LinearLayoutManager
(
this
)
accounts_list
.
adapter
=
AccountsAdapter
(
accounts
,
object
:
Selector
{
override
fun
onStatusSelected
(
userStatus
:
UserStatus
)
{
presenter
.
changeDefaultStatus
(
userStatus
)
}
override
fun
onRestoreInstanceState
(
savedInstanceState
:
Bundle
?)
{
super
.
onRestoreInstanceState
(
savedInstanceState
)
isFragmentAdded
=
savedInstanceState
?.
getBoolean
(
CURRENT_STATE
)
?:
false
override
fun
onAccountSelected
(
serverUrl
:
String
)
{
presenter
.
changeServer
(
serverUrl
)
}
override
fun
onAddedAccountSelected
()
{
presenter
.
addNewServer
()
}
})
header
.
account_container
.
setOnClickListener
{
header
.
image_account_expand
.
rotateBy
(
180f
)
if
(
expanded
)
{
accounts_list
.
fadeOut
()
}
else
{
accounts_list
.
fadeIn
()
}
expanded
=
!
expanded
}
header
.
image_avatar
.
setOnClickListener
{
view_navigation
.
menu
.
findItem
(
R
.
id
.
action_profile
).
isChecked
=
true
presenter
.
toUserProfile
()
drawer_layout
.
closeDrawer
(
Gravity
.
START
)
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/pinnedmessages/presentation/PinnedMessagesPresenter.kt
View file @
26ead887
...
...
@@ -26,7 +26,7 @@ class PinnedMessagesPresenter @Inject constructor(
private
var
offset
:
Int
=
0
/**
* Load all pinned messages for the given room id.
* Load
s
all pinned messages for the given room id.
*
* @param roomId The id of the room to get pinned messages from.
*/
...
...
@@ -36,8 +36,7 @@ class PinnedMessagesPresenter @Inject constructor(
view
.
showLoading
()
roomsInteractor
.
getById
(
serverUrl
,
roomId
)
?.
let
{
val
pinnedMessages
=
client
.
getPinnedMessages
(
roomId
,
it
.
type
,
offset
)
val
messageList
=
mapper
.
map
(
pinnedMessages
.
result
.
filterNot
{
it
.
isSystemMessage
()
})
val
messageList
=
mapper
.
map
(
pinnedMessages
.
result
,
asNotReversed
=
true
)
view
.
showPinnedMessages
(
messageList
)
offset
+=
1
*
30
}.
ifNull
{
...
...
app/src/main/java/chat/rocket/android/pinnedmessages/ui/PinnedMessagesFragment.kt
View file @
26ead887
...
...
@@ -74,7 +74,7 @@ class PinnedMessagesFragment : Fragment(), PinnedMessagesView {
LinearLayoutManager
(
context
,
LinearLayoutManager
.
VERTICAL
,
false
)
recycler_view_pinned
.
layoutManager
=
linearLayoutManager
recycler_view_pinned
.
itemAnimator
=
DefaultItemAnimator
()
if
(
pinnedMessages
.
size
>
1
0
)
{
if
(
pinnedMessages
.
size
>
=
3
0
)
{
recycler_view_pinned
.
addOnScrollListener
(
object
:
EndlessRecyclerViewScrollListener
(
linearLayoutManager
)
{
override
fun
onLoadMore
(
...
...
app/src/main/java/chat/rocket/android/profile/presentation/ProfilePresenter.kt
View file @
26ead887
...
...
@@ -58,7 +58,8 @@ class ProfilePresenter @Inject constructor(private val view: ProfileView,
if
(
avatarUrl
!=
""
)
{
retryIO
{
client
.
setAvatar
(
avatarUrl
)
}
}
val
user
=
retryIO
{
client
.
updateProfile
(
myselfId
,
email
,
name
,
username
)
}
val
user
=
retryIO
{
client
.
updateProfile
(
userId
=
myselfId
,
email
=
email
,
name
=
name
,
username
=
username
)
}
view
.
showProfileUpdateSuccessfullyMessage
()
loadUserProfile
()
}
catch
(
exception
:
RocketChatException
)
{
...
...
app/src/main/java/chat/rocket/android/push/
GcmListener
Service.kt
→
app/src/main/java/chat/rocket/android/push/
FirebaseMessaging
Service.kt
View file @
26ead887
package
chat.rocket.android.push
import
android.os.Bundle
import
com.google.android.gms.gcm.GcmListenerService
import
androidx.core.os.bundleOf
import
com.google.firebase.messaging.FirebaseMessagingService
import
com.google.firebase.messaging.RemoteMessage
import
dagger.android.AndroidInjection
import
javax.inject.Inject
class
GcmListenerService
:
GcmListener
Service
()
{
class
FirebaseMessagingService
:
FirebaseMessaging
Service
()
{
@Inject
lateinit
var
pushManager
:
PushManager
...
...
@@ -15,9 +16,9 @@ class GcmListenerService : GcmListenerService() {
AndroidInjection
.
inject
(
this
)
}
override
fun
onMessageReceived
(
from
:
String
?,
data
:
Bundle
?
)
{
data
?.
let
{
pushManager
.
handle
(
data
)
override
fun
onMessageReceived
(
message
:
RemoteMessage
)
{
message
.
data
?.
let
{
pushManager
.
handle
(
bundleOf
(*(
it
.
map
{
Pair
(
it
.
key
,
it
.
value
)
}).
toTypedArray
())
)
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/push/FirebaseTokenService.kt
View file @
26ead887
package
chat.rocket.android.push
import
chat.rocket.android.R
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.server.domain.GetCurrentServerInteractor
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.android.util.retryIO
import
chat.rocket.common.RocketChatException
import
chat.rocket.core.internal.rest.registerPushToken
import
com.google.android.gms.gcm.GoogleCloudMessaging
import
com.google.android.gms.iid.InstanceID
import
com.google.firebase.iid.FirebaseInstanceId
import
com.google.firebase.iid.FirebaseInstanceIdService
import
dagger.android.AndroidInjection
import
kotlinx.coroutines.experimental.launch
...
...
@@ -31,21 +29,18 @@ class FirebaseTokenService : FirebaseInstanceIdService() {
}
override
fun
onTokenRefresh
()
{
//TODO: We need to use the Cordova Project gcm_sender_id since it's the one configured on RC
// default push gateway. We should register this project's own project sender id into it.
try
{
val
gcmToken
=
InstanceID
.
getInstance
(
this
)
.
getToken
(
getString
(
R
.
string
.
gcm_sender_id
),
GoogleCloudMessaging
.
INSTANCE_ID_SCOPE
,
null
)
val
fcmToken
=
FirebaseInstanceId
.
getInstance
().
token
val
currentServer
=
getCurrentServerInteractor
.
get
()
val
client
=
currentServer
?.
let
{
factory
.
create
(
currentServer
)
}
g
cmToken
?.
let
{
localRepository
.
save
(
LocalRepository
.
KEY_PUSH_TOKEN
,
g
cmToken
)
f
cmToken
?.
let
{
localRepository
.
save
(
LocalRepository
.
KEY_PUSH_TOKEN
,
f
cmToken
)
client
?.
let
{
launch
{
try
{
Timber
.
d
(
"Registering push token: $
g
cmToken for ${client.url}"
)
retryIO
(
"register push token"
)
{
client
.
registerPushToken
(
gcmToken
)
}
Timber
.
d
(
"Registering push token: $
f
cmToken for ${client.url}"
)
retryIO
(
"register push token"
)
{
client
.
registerPushToken
(
fcmToken
)
}
}
catch
(
ex
:
RocketChatException
)
{
Timber
.
e
(
ex
,
"Error registering push token"
)
}
...
...
@@ -53,7 +48,7 @@ class FirebaseTokenService : FirebaseInstanceIdService() {
}
}
}
catch
(
ex
:
Exception
)
{
Timber
.
d
(
ex
,
"Error refreshing Firebase TOKEN"
)
Timber
.
e
(
ex
,
"Error refreshing Firebase TOKEN"
)
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/push/PushManager.kt
View file @
26ead887
...
...
@@ -48,7 +48,8 @@ class PushManager @Inject constructor(
private
val
getSettingsInteractor
:
GetSettingsInteractor
,
private
val
context
:
Context
)
{
private
val
randomizer
=
Random
()
private
val
random
=
Random
()
/**
* Handles a receiving push by creating and displaying an appropriate notification based
...
...
@@ -59,7 +60,7 @@ class PushManager @Inject constructor(
val
message
=
data
[
"message"
]
as
String
?
val
ejson
=
data
[
"ejson"
]
as
String
?
val
title
=
data
[
"title"
]
as
String
?
val
notId
=
data
[
"notId"
]
as
String
?
?:
random
izer
.
nextInt
().
toString
()
val
notId
=
data
[
"notId"
]
as
String
?
?:
random
.
nextInt
().
toString
()
val
image
=
data
[
"image"
]
as
String
?
val
style
=
data
[
"style"
]
as
String
?
val
summaryText
=
data
[
"summaryText"
]
as
String
?
...
...
@@ -67,9 +68,13 @@ class PushManager @Inject constructor(
try
{
val
adapter
=
moshi
.
adapter
<
PushInfo
>(
PushInfo
::
class
.
java
)
val
info
=
adapter
.
fromJson
(
ejson
)
val
pushMessage
=
PushMessage
(
title
!!
,
message
!!
,
info
!!
,
image
,
count
,
notId
,
summaryText
,
style
)
val
pushMessage
=
if
(
ejson
!=
null
)
{
val
info
=
adapter
.
fromJson
(
ejson
)
PushMessage
(
title
!!
,
message
!!
,
info
!!
,
image
,
count
,
notId
,
summaryText
,
style
)
}
else
{
PushMessage
(
title
!!
,
message
!!
,
PushInfo
.
EMPTY
,
image
,
count
,
notId
,
summaryText
,
style
)
}
Timber
.
d
(
"Received push message: $pushMessage"
)
...
...
@@ -82,13 +87,17 @@ class PushManager @Inject constructor(
@SuppressLint
(
"NewApi"
)
suspend
fun
showNotification
(
pushMessage
:
PushMessage
)
{
if
(!
hasAccount
(
pushMessage
.
info
.
host
))
{
Timber
.
d
(
"ignoring push message: $pushMessage"
)
val
notId
=
pushMessage
.
notificationId
.
toInt
()
val
host
=
pushMessage
.
info
.
host
if
(!
hasAccount
(
host
))
{
createSingleNotification
(
pushMessage
)
?.
let
{
NotificationManagerCompat
.
from
(
context
).
notify
(
notId
,
it
)
}
Timber
.
d
(
"ignoring push message: $pushMessage (maybe a test notification?)"
)
return
}
val
notId
=
pushMessage
.
notificationId
.
toInt
()
val
host
=
pushMessage
.
info
.
host
val
groupTuple
=
getGroupForHost
(
host
)
groupTuple
.
second
.
incrementAndGet
()
...
...
@@ -103,7 +112,7 @@ class PushManager @Inject constructor(
val
pushMessageList
=
groupedPushes
.
hostToPushMessageList
[
host
]
notification
?.
let
{
manager
.
notify
(
notId
,
notification
)
manager
.
notify
(
notId
,
it
)
}
pushMessageList
?.
let
{
...
...
@@ -182,7 +191,7 @@ class PushManager @Inject constructor(
if
(
style
==
null
||
"inbox"
==
style
)
{
val
pushMessageList
=
groupedPushes
.
hostToPushMessageList
.
get
(
host
)
pushMessageList
?.
let
{
if
(
pushMessageList
!=
null
)
{
val
userMessages
=
pushMessageList
.
filter
{
it
.
notificationId
==
pushMessage
.
notificationId
}
...
...
@@ -206,6 +215,12 @@ class PushManager @Inject constructor(
.
bigText
(
message
.
fromHtml
())
builder
.
setStyle
(
bigTextStyle
)
}
}
else
{
// We don't know which kind of push is this - maybe a test push, so just show it
val
bigTextStyle
=
NotificationCompat
.
BigTextStyle
()
.
bigText
(
message
.
fromHtml
())
builder
.
setStyle
(
bigTextStyle
)
return
builder
.
build
()
}
}
else
{
val
bigTextStyle
=
NotificationCompat
.
BigTextStyle
()
...
...
@@ -213,8 +228,7 @@ class PushManager @Inject constructor(
builder
.
setStyle
(
bigTextStyle
)
}
return
builder
.
addReplyAction
(
pushMessage
)
.
build
()
return
builder
.
addReplyAction
(
pushMessage
).
build
()
}
}
...
...
@@ -235,13 +249,27 @@ class PushManager @Inject constructor(
.
setContentIntent
(
contentIntent
)
.
setMessageNotification
()
if
(
host
.
isEmpty
())
{
builder
.
setContentIntent
(
deleteIntent
)
}
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
O
)
{
val
channel
=
NotificationChannel
(
host
,
host
,
NotificationManager
.
IMPORTANCE_HIGH
)
val
channelId
:
String
val
channelName
:
String
if
(
host
.
isEmpty
())
{
channelName
=
"Test Notification"
channelId
=
"test-channel"
}
else
{
channelName
=
host
channelId
=
host
}
val
channel
=
NotificationChannel
(
channelId
,
channelName
,
NotificationManager
.
IMPORTANCE_HIGH
)
channel
.
lockscreenVisibility
=
Notification
.
VISIBILITY_PUBLIC
channel
.
enableLights
(
false
)
channel
.
enableVibration
(
true
)
channel
.
setShowBadge
(
true
)
manager
.
createNotificationChannel
(
channel
)
builder
.
setChannelId
(
channelId
)
}
//TODO: Get Site_Name PublicSetting from cache
...
...
@@ -271,12 +299,12 @@ class PushManager @Inject constructor(
}
private
fun
getContentIntent
(
context
:
Context
,
notificationId
:
Int
,
pushMessage
:
PushMessage
,
grouped
:
Boolean
=
false
):
PendingIntent
{
val
notificationIntent
=
context
.
changeServerIntent
(
pushMessage
.
info
.
host
)
val
notificationIntent
=
context
.
changeServerIntent
(
pushMessage
.
info
.
host
,
chatRoomId
=
pushMessage
.
info
.
roomId
)
// TODO - add support to go directly to the chatroom
/*if (!grouped) {
notificationIntent.putExtra(EXTRA_ROOM_ID, pushMessage.info.roomId)
}*/
return
PendingIntent
.
getActivity
(
context
,
random
izer
.
nextInt
(),
notificationIntent
,
PendingIntent
.
FLAG_UPDATE_CURRENT
)
return
PendingIntent
.
getActivity
(
context
,
random
.
nextInt
(),
notificationIntent
,
PendingIntent
.
FLAG_UPDATE_CURRENT
)
}
// CharSequence extensions
...
...
@@ -318,14 +346,14 @@ class PushManager @Inject constructor(
return
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
N
)
{
PendingIntent
.
getBroadcast
(
context
,
randomizer
.
nextInt
(),
random
.
nextInt
(),
replyIntent
,
PendingIntent
.
FLAG_UPDATE_CURRENT
)
}
else
{
PendingIntent
.
getActivity
(
context
,
randomizer
.
nextInt
(),
random
.
nextInt
(),
replyIntent
,
PendingIntent
.
FLAG_UPDATE_CURRENT
)
...
...
@@ -359,6 +387,7 @@ data class PushMessage(
val
summaryText
:
String
?
=
null
,
val
style
:
String
?
=
null
)
:
Parcelable
{
constructor
(
parcel
:
Parcel
)
:
this
(
parcel
.
readString
(),
parcel
.
readString
(),
...
...
@@ -438,6 +467,9 @@ data class PushInfo @KotshiConstructor constructor(
}
companion
object
CREATOR
:
Parcelable
.
Creator
<
PushInfo
>
{
val
EMPTY
=
PushInfo
(
hostname
=
""
,
roomId
=
""
,
type
=
RoomType
.
CHANNEL
,
name
=
""
,
sender
=
null
)
override
fun
createFromParcel
(
parcel
:
Parcel
):
PushInfo
{
return
PushInfo
(
parcel
)
}
...
...
app/src/main/java/chat/rocket/android/push/di/
GcmListener
ServiceProvider.kt
→
app/src/main/java/chat/rocket/android/push/di/
FirebaseMessaging
ServiceProvider.kt
View file @
26ead887
package
chat.rocket.android.push.di
import
chat.rocket.android.dagger.module.AppModule
import
chat.rocket.android.push.
GcmListener
Service
import
chat.rocket.android.push.
FirebaseMessaging
Service
import
dagger.Module
import
dagger.android.ContributesAndroidInjector
@Module
abstract
class
GcmListener
ServiceProvider
{
@Module
abstract
class
FirebaseMessaging
ServiceProvider
{
@ContributesAndroidInjector
(
modules
=
[
AppModule
::
class
])
abstract
fun
provide
GcmListenerService
():
GcmListener
Service
abstract
fun
provide
FirebaseMessagingService
():
FirebaseMessaging
Service
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/server/infraestructure/ConnectionManager.kt
View file @
26ead887
...
...
@@ -3,16 +3,16 @@ package chat.rocket.android.server.infraestructure
import
chat.rocket.common.model.BaseRoom
import
chat.rocket.common.model.User
import
chat.rocket.core.RocketChatClient
import
chat.rocket.core.internal.realtime.subscribeSubscriptions
import
chat.rocket.core.internal.realtime.subscribeRooms
import
chat.rocket.core.internal.realtime.subscribeUserData
import
chat.rocket.core.internal.realtime.subscribeActiveUsers
import
chat.rocket.core.internal.realtime.subscribeRoomMessages
import
chat.rocket.core.internal.realtime.unsubscribe
import
chat.rocket.core.internal.realtime.socket.connect
import
chat.rocket.core.internal.realtime.socket.disconnect
import
chat.rocket.core.internal.realtime.socket.model.State
import
chat.rocket.core.internal.realtime.socket.model.StreamMessage
import
chat.rocket.core.internal.realtime.subscribeActiveUsers
import
chat.rocket.core.internal.realtime.subscribeRoomMessages
import
chat.rocket.core.internal.realtime.subscribeRooms
import
chat.rocket.core.internal.realtime.subscribeSubscriptions
import
chat.rocket.core.internal.realtime.subscribeUserData
import
chat.rocket.core.internal.realtime.unsubscribe
import
chat.rocket.core.internal.rest.chatRooms
import
chat.rocket.core.model.Message
import
chat.rocket.core.model.Myself
...
...
app/src/main/java/chat/rocket/android/server/presentation/ChangeServerNavigator.kt
View file @
26ead887
...
...
@@ -4,6 +4,7 @@ import android.content.Intent
import
chat.rocket.android.authentication.ui.newServerIntent
import
chat.rocket.android.main.ui.MainActivity
import
chat.rocket.android.server.ui.ChangeServerActivity
import
chat.rocket.android.server.ui.INTENT_CHAT_ROOM_ID
class
ChangeServerNavigator
(
internal
val
activity
:
ChangeServerActivity
)
{
fun
toServerScreen
()
{
...
...
@@ -11,8 +12,10 @@ class ChangeServerNavigator (internal val activity: ChangeServerActivity) {
activity
.
finish
()
}
fun
toChatRooms
()
{
activity
.
startActivity
(
Intent
(
activity
,
MainActivity
::
class
.
java
))
fun
toChatRooms
(
chatRoomId
:
String
?
=
null
)
{
activity
.
startActivity
(
Intent
(
activity
,
MainActivity
::
class
.
java
).
also
{
it
.
putExtra
(
INTENT_CHAT_ROOM_ID
,
chatRoomId
)
})
activity
.
finish
()
}
...
...
app/src/main/java/chat/rocket/android/server/presentation/ChangeServerPresenter.kt
View file @
26ead887
...
...
@@ -21,7 +21,7 @@ class ChangeServerPresenter @Inject constructor(
private
val
localRepository
:
LocalRepository
,
private
val
connectionManager
:
ConnectionManagerFactory
)
{
fun
loadServer
(
newUrl
:
String
?)
{
fun
loadServer
(
newUrl
:
String
?
,
chatRoomId
:
String
?
=
null
)
{
launchUI
(
strategy
)
{
view
.
showProgress
()
var
url
=
newUrl
...
...
@@ -56,7 +56,7 @@ class ChangeServerPresenter @Inject constructor(
saveCurrentServerInteractor
.
save
(
serverUrl
)
view
.
hideProgress
()
navigator
.
toChatRooms
()
navigator
.
toChatRooms
(
chatRoomId
)
}.
ifNull
{
view
.
hideProgress
()
navigator
.
toServerScreen
()
...
...
app/src/main/java/chat/rocket/android/server/ui/ChangeServerActivity.kt
View file @
26ead887
...
...
@@ -21,7 +21,8 @@ class ChangeServerActivity : AppCompatActivity(), ChangeServerView {
super
.
onCreate
(
savedInstanceState
)
val
serverUrl
:
String
?
=
intent
.
getStringExtra
(
INTENT_SERVER_URL
)
presenter
.
loadServer
(
serverUrl
)
val
chatRoomId
:
String
?
=
intent
.
getStringExtra
(
INTENT_CHAT_ROOM_ID
)
presenter
.
loadServer
(
serverUrl
,
chatRoomId
)
}
override
fun
showInvalidCredentials
()
{
...
...
@@ -40,11 +41,13 @@ class ChangeServerActivity : AppCompatActivity(), ChangeServerView {
private
const
val
INTENT_SERVER_URL
=
"INTENT_SERVER_URL"
private
const
val
INTENT_CHAT_ROOM_NAME
=
"INTENT_CHAT_ROOM_NAME"
private
const
val
INTENT_CHAT_ROOM_TYPE
=
"INTENT_CHAT_ROOM_TYPE"
const
val
INTENT_CHAT_ROOM_ID
=
"INTENT_CHAT_ROOM_ID"
fun
Context
.
changeServerIntent
(
serverUrl
:
String
?
=
null
):
Intent
{
fun
Context
.
changeServerIntent
(
serverUrl
:
String
?
=
null
,
chatRoomId
:
String
?
=
""
):
Intent
{
return
Intent
(
this
,
ChangeServerActivity
::
class
.
java
).
apply
{
serverUrl
?.
let
{
url
->
putExtra
(
INTENT_SERVER_URL
,
url
)
putExtra
(
INTENT_CHAT_ROOM_ID
,
chatRoomId
)
}
flags
=
Intent
.
FLAG_ACTIVITY_CLEAR_TOP
or
Intent
.
FLAG_ACTIVITY_CLEAR_TASK
}
...
...
app/src/main/res/layout/fragment_authentication_log_in.xml
View file @
26ead887
...
...
@@ -32,6 +32,18 @@
app:layout_constraintRight_toRightOf=
"parent"
app:layout_constraintTop_toBottomOf=
"@+id/text_headline"
/>
<ImageView
android:id=
"@+id/image_key"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_marginEnd=
"10dp"
android:src=
"@drawable/ic_vpn_key_black_24dp"
android:tint=
"@color/colorDrawableTintGrey"
android:visibility=
"gone"
app:layout_constraintBottom_toBottomOf=
"@+id/text_username_or_email"
app:layout_constraintEnd_toEndOf=
"@+id/text_username_or_email"
app:layout_constraintTop_toTopOf=
"@+id/text_username_or_email"
/>
<EditText
android:id=
"@+id/text_password"
style=
"@style/Authentication.EditText"
...
...
app/src/main/res/layout/fragment_files.xml
View file @
26ead887
...
...
@@ -2,6 +2,7 @@
<android.support.constraint.ConstraintLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:app=
"http://schemas.android.com/apk/res-auto"
xmlns:tools=
"http://schemas.android.com/tools"
android:id=
"@+id/root_layout"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
tools:context=
".files.ui.FilesFragment"
>
...
...
app/src/main/res/values/api_keys.xml
deleted
100644 → 0
View file @
d46037d4
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- This is the Cordova GCM sender id-->
<string
name=
"gcm_sender_id"
translatable=
"false"
>
673693445664
</string>
</resources>
\ No newline at end of file
debug.keystore
0 → 100644
View file @
26ead887
File added
dependencies.gradle
View file @
26ead887
...
...
@@ -14,7 +14,8 @@ ext {
androidKtx
:
'0.3'
,
dagger
:
'2.14.1'
,
exoPlayer
:
'2.6.0'
,
playServices
:
'11.8.0'
,
playServices
:
'15.0.0'
,
firebase
:
'15.0.0'
,
room
:
'1.0.0'
,
lifecycle
:
'1.1.1'
,
rxKotlin
:
'2.2.0'
,
...
...
@@ -63,7 +64,7 @@ ext {
daggerSupport
:
"com.google.dagger:dagger-android-support:${versions.dagger}"
,
daggerProcessor
:
"com.google.dagger:dagger-compiler:${versions.dagger}"
,
daggerAndroidApt
:
"com.google.dagger:dagger-android-processor:${versions.dagger}"
,
playServicesGcm
:
"com.google.android.gms:play-services-gcm:${versions.playServices
}"
,
fcm
:
"com.google.firebase:firebase-messaging:${versions.firebase
}"
,
playServicesAuth
:
"com.google.android.gms:play-services-auth:${versions.playServices}"
,
exoPlayer
:
"com.google.android.exoplayer:exoplayer:${versions.exoPlayer}"
,
...
...
@@ -102,19 +103,19 @@ ext {
aVLoadingIndicatorView:
"com.wang.avi:library:${versions.aVLoadingIndicatorView}"
,
// For testing
junit
:
"junit:junit:$versions.junit"
,
espressoCore
:
"com.android.support.test.espresso:espresso-core:${versions.espresso}"
,
espressoIntents
:
"com.android.support.test.espresso:espresso-intents:${versions.espresso}"
,
roomTest
:
"android.arch.persistence.room:testing:${versions.room}"
,
truth
:
"com.google.truth:truth:$versions.truth"
,
//For the wear app
wearable
:
"com.google.android.support:wearable:${versions.wear}"
,
playServicesWearable
:
"com.google.android.gms:play-services-wearable:${versions.playServicesWearable}"
,
percentLayout
:
"com.android.support:percent:${versions.supportWearable}"
,
supportWearable
:
"com.android.support:support-v4:${versions.supportWearable}"
,
wearableRecyclerView
:
"com.android.support:recyclerview-v7:${versions.supportWearable}"
,
wearSupport
:
"com.android.support:wear:${versions.supportWearable}"
wearSupport
:
"com.android.support:wear:${versions.supportWearable}"
,
// For testing
junit
:
"junit:junit:$versions.junit"
,
espressoCore
:
"com.android.support.test.espresso:espresso-core:${versions.espresso}"
,
espressoIntents
:
"com.android.support.test.espresso:espresso-intents:${versions.espresso}"
,
roomTest
:
"android.arch.persistence.room:testing:${versions.room}"
,
truth
:
"com.google.truth:truth:$versions.truth"
]
}
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