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
95a28de4
Unverified
Commit
95a28de4
authored
Apr 17, 2018
by
divyanshu bhargava
Committed by
GitHub
Apr 17, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #7 from RocketChat/develop-2.x
merge
parents
513931f0
eb73cd48
Changes
25
Hide whitespace changes
Inline
Side-by-side
Showing
25 changed files
with
442 additions
and
90 deletions
+442
-90
build.gradle
app/build.gradle
+6
-2
AndroidManifest.xml
app/src/main/AndroidManifest.xml
+15
-1
LoginDeepLinkInfo.kt
.../android/authentication/domain/model/LoginDeepLinkInfo.kt
+38
-0
LoginPresenter.kt
...droid/authentication/login/presentation/LoginPresenter.kt
+48
-6
LoginFragment.kt
...t/rocket/android/authentication/login/ui/LoginFragment.kt
+16
-2
AuthenticationNavigator.kt
...id/authentication/presentation/AuthenticationNavigator.kt
+7
-0
ServerPresenter.kt
...oid/authentication/server/presentation/ServerPresenter.kt
+16
-6
ServerFragment.kt
...rocket/android/authentication/server/ui/ServerFragment.kt
+15
-1
TwoFAFragment.kt
...cket/android/authentication/twofactor/ui/TwoFAFragment.kt
+1
-1
AuthenticationActivity.kt
...ocket/android/authentication/ui/AuthenticationActivity.kt
+8
-5
ChatRoomAdapter.kt
...a/chat/rocket/android/chatroom/adapter/ChatRoomAdapter.kt
+5
-0
ColorAttachmentViewHolder.kt
...ket/android/chatroom/adapter/ColorAttachmentViewHolder.kt
+38
-0
ChatRoomFragment.kt
.../java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
+2
-2
BaseViewModel.kt
...a/chat/rocket/android/chatroom/viewmodel/BaseViewModel.kt
+2
-1
ColorAttachmentViewModel.kt
...et/android/chatroom/viewmodel/ColorAttachmentViewModel.kt
+24
-0
ViewModelMapper.kt
...chat/rocket/android/chatroom/viewmodel/ViewModelMapper.kt
+14
-0
MessageView.kt
...n/java/chat/rocket/android/core/behaviours/MessageView.kt
+9
-0
AppModule.kt
.../main/java/chat/rocket/android/dagger/module/AppModule.kt
+14
-6
ForMessages.kt
.../java/chat/rocket/android/dagger/qualifier/ForMessages.kt
+11
-0
MainPresenter.kt
...va/chat/rocket/android/main/presentation/MainPresenter.kt
+2
-2
RefreshSettingsInteractor.kt
...rocket/android/server/domain/RefreshSettingsInteractor.kt
+4
-1
CheckServerPresenter.kt
...ocket/android/server/presentation/CheckServerPresenter.kt
+47
-14
fragment_profile.xml
app/src/main/res/layout/fragment_profile.xml
+48
-40
item_color_attachment.xml
app/src/main/res/layout/item_color_attachment.xml
+44
-0
backup_config.xml
app/src/main/res/xml/backup_config.xml
+8
-0
No files found.
app/build.gradle
View file @
95a28de4
...
...
@@ -13,8 +13,8 @@ android {
applicationId
"chat.rocket.android"
minSdkVersion
21
targetSdkVersion
versions
.
targetSdk
versionCode
20
09
versionName
"2.0.0
-rc1
"
versionCode
20
10
versionName
"2.0.0"
testInstrumentationRunner
"android.support.test.runner.AndroidJUnitRunner"
multiDexEnabled
true
}
...
...
@@ -124,6 +124,10 @@ kotlin {
}
}
androidExtensions
{
experimental
=
true
}
// FIXME - build and install the sdk into the app/libs directory
// We were having some issues with the kapt generated files from the sdk when importing as a module
task
compileSdk
(
type:
Exec
)
{
...
...
app/src/main/AndroidManifest.xml
View file @
95a28de4
...
...
@@ -17,10 +17,11 @@
<application
android:name=
".app.RocketChatApplication"
android:allowBackup=
"true"
android:fullBackupContent=
"@xml/backup_config"
android:icon=
"@mipmap/ic_launcher"
android:label=
"@string/app_name"
android:roundIcon=
"@mipmap/ic_launcher_round"
android:networkSecurityConfig=
"@xml/network_security_config"
>
android:networkSecurityConfig=
"@xml/network_security_config"
android:supportsRtl=
"true"
>
<activity
...
...
@@ -34,6 +35,19 @@
<category
android:name=
"android.intent.category.DEFAULT"
/>
<category
android:name=
"android.intent.category.LAUNCHER"
/>
</intent-filter>
<intent-filter>
<action
android:name=
"android.intent.action.VIEW"
/>
<category
android:name=
"android.intent.category.BROWSABLE"
/>
<category
android:name=
"android.intent.category.DEFAULT"
/>
<data
android:host=
"auth"
android:scheme=
"rocketchat"
/>
<data
android:host=
"go.rocket.chat"
android:path=
"/auth"
android:scheme=
"https"
/>
</intent-filter>
</activity>
<activity
...
...
app/src/main/java/chat/rocket/android/authentication/domain/model/LoginDeepLinkInfo.kt
0 → 100644
View file @
95a28de4
package
chat.rocket.android.authentication.domain.model
import
android.content.Intent
import
android.net.Uri
import
android.os.Parcelable
import
kotlinx.android.parcel.Parcelize
import
timber.log.Timber
@Parcelize
data class
LoginDeepLinkInfo
(
val
url
:
String
,
val
userId
:
String
,
val
token
:
String
)
:
Parcelable
fun
Intent
.
getLoginDeepLinkInfo
():
LoginDeepLinkInfo
?
{
val
uri
=
data
return
if
(
action
==
Intent
.
ACTION_VIEW
&&
uri
!=
null
&&
uri
.
isAuthenticationDeepLink
())
{
val
host
=
uri
.
getQueryParameter
(
"host"
)
val
url
=
if
(
host
.
startsWith
(
"http"
))
host
else
"https://$host"
val
userId
=
uri
.
getQueryParameter
(
"userId"
)
val
token
=
uri
.
getQueryParameter
(
"token"
)
try
{
LoginDeepLinkInfo
(
url
,
userId
,
token
)
}
catch
(
ex
:
Exception
)
{
Timber
.
d
(
ex
,
"Error parsing login deeplink"
)
null
}
}
else
null
}
private
inline
fun
Uri
.
isAuthenticationDeepLink
():
Boolean
{
if
(
host
==
"auth"
)
return
true
else
if
(
host
==
"go.rocket.chat"
&&
path
==
"/auth"
)
return
true
return
false
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/authentication/login/presentation/LoginPresenter.kt
View file @
95a28de4
package
chat.rocket.android.authentication.login.presentation
import
chat.rocket.android.authentication.domain.model.LoginDeepLinkInfo
import
chat.rocket.android.authentication.presentation.AuthenticationNavigator
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.helper.OauthHelper
...
...
@@ -10,6 +11,7 @@ import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.android.server.presentation.CheckServerPresenter
import
chat.rocket.android.util.extensions.*
import
chat.rocket.android.util.retryIO
import
chat.rocket.common.RocketChatAuthException
import
chat.rocket.common.RocketChatException
import
chat.rocket.common.RocketChatTwoFactorException
import
chat.rocket.common.model.Token
...
...
@@ -24,6 +26,7 @@ import javax.inject.Inject
private
const
val
TYPE_LOGIN_USER_EMAIL
=
0
private
const
val
TYPE_LOGIN_CAS
=
1
private
const
val
TYPE_LOGIN_OAUTH
=
2
private
const
val
TYPE_LOGIN_DEEP_LINK
=
3
private
const
val
SERVICE_NAME_GITHUB
=
"github"
private
const
val
SERVICE_NAME_GOOGLE
=
"google"
private
const
val
SERVICE_NAME_LINKEDIN
=
"linkedin"
...
...
@@ -35,26 +38,31 @@ class LoginPresenter @Inject constructor(private val view: LoginView,
private
val
tokenRepository
:
TokenRepository
,
private
val
localRepository
:
LocalRepository
,
private
val
getAccountsInteractor
:
GetAccountsInteractor
,
settingsInteractor
:
GetSettingsInteractor
,
private
val
settingsInteractor
:
GetSettingsInteractor
,
serverInteractor
:
GetCurrentServerInteractor
,
private
val
saveAccountInteractor
:
SaveAccountInteractor
,
private
val
factory
:
RocketChatClientFactory
)
:
CheckServerPresenter
(
strategy
,
factory
.
create
(
serverInteractor
.
get
()
!!
)
,
view
)
{
:
CheckServerPresenter
(
strategy
,
factory
,
view
)
{
// TODO - we should validate the current server when opening the app, and have a nonnull get()
private
val
currentServer
=
serverInteractor
.
get
()
!!
private
val
client
:
RocketChatClient
=
factory
.
create
(
currentServer
)
private
val
settings
:
PublicSettings
=
settingsInteractor
.
get
(
currentServer
)
private
lateinit
var
client
:
RocketChatClient
private
lateinit
var
settings
:
PublicSettings
//private val client: RocketChatClient = factory.create(currentServer)
//private val settings: PublicSettings = settingsInteractor.get(currentServer)
private
lateinit
var
usernameOrEmail
:
String
private
lateinit
var
password
:
String
private
lateinit
var
credentialToken
:
String
private
lateinit
var
credentialSecret
:
String
private
lateinit
var
deepLinkUserId
:
String
private
lateinit
var
deepLinkToken
:
String
fun
setupView
()
{
setupConnectionInfo
(
currentServer
)
setupLoginView
()
setupUserRegistrationView
()
setupCasView
()
setupOauthServicesView
()
checkServerInfo
()
checkServerInfo
(
currentServer
)
}
fun
authenticateWithUserAndPassword
(
usernameOrEmail
:
String
,
password
:
String
)
{
...
...
@@ -84,6 +92,32 @@ class LoginPresenter @Inject constructor(private val view: LoginView,
doAuthentication
(
TYPE_LOGIN_OAUTH
)
}
fun
authenticadeWithDeepLink
(
deepLinkInfo
:
LoginDeepLinkInfo
)
{
val
serverUrl
=
deepLinkInfo
.
url
setupConnectionInfo
(
serverUrl
)
deepLinkUserId
=
deepLinkInfo
.
userId
deepLinkToken
=
deepLinkInfo
.
token
tokenRepository
.
save
(
serverUrl
,
Token
(
deepLinkUserId
,
deepLinkToken
))
launchUI
(
strategy
)
{
try
{
val
version
=
checkServerVersion
(
serverUrl
).
await
()
when
(
version
)
{
is
Version
.
OutOfDateError
->
{
view
.
blockAndAlertNotRequiredVersion
()
}
else
->
doAuthentication
(
TYPE_LOGIN_DEEP_LINK
)
}
}
catch
(
ex
:
Exception
)
{
Timber
.
d
(
ex
,
"Error performing deep link login"
)
}
}
}
private
fun
setupConnectionInfo
(
serverUrl
:
String
)
{
client
=
factory
.
create
(
serverUrl
)
settings
=
settingsInteractor
.
get
(
serverUrl
)
}
fun
signup
()
=
navigator
.
toSignUp
()
private
fun
setupLoginView
()
{
...
...
@@ -212,8 +246,16 @@ class LoginPresenter @Inject constructor(private val view: LoginView,
TYPE_LOGIN_OAUTH
->
{
client
.
loginWithOauth
(
credentialToken
,
credentialSecret
)
}
TYPE_LOGIN_DEEP_LINK
->
{
val
myself
=
client
.
me
()
// Just checking if the credentials worked.
if
(
myself
.
id
==
deepLinkUserId
)
{
Token
(
deepLinkUserId
,
deepLinkToken
)
}
else
{
throw
RocketChatAuthException
(
"Invalid Authentication Deep Link Credentials..."
)
}
}
else
->
{
throw
IllegalStateException
(
"Expected TYPE_LOGIN_USER_EMAIL, TYPE_LOGIN_CAS
or TYPE_LOGIN_OAUTH
"
)
throw
IllegalStateException
(
"Expected TYPE_LOGIN_USER_EMAIL, TYPE_LOGIN_CAS
, TYPE_LOGIN_OAUTH or TYPE_LOGIN_DEEP_LINK
"
)
}
}
}
...
...
app/src/main/java/chat/rocket/android/authentication/login/ui/LoginFragment.kt
View file @
95a28de4
...
...
@@ -17,6 +17,7 @@ import android.widget.ScrollView
import
androidx.core.view.postDelayed
import
chat.rocket.android.BuildConfig
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
...
...
@@ -27,6 +28,7 @@ import chat.rocket.android.webview.cas.ui.casWebViewIntent
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
dagger.android.support.AndroidSupportInjection
import
kotlinx.android.synthetic.main.fragment_authentication_log_in.*
import
javax.inject.Inject
...
...
@@ -41,14 +43,22 @@ class LoginFragment : Fragment(), LoginView {
areLoginOptionsNeeded
()
}
private
var
isGlobalLayoutListenerSetUp
=
false
private
var
deepLinkInfo
:
LoginDeepLinkInfo
?
=
null
companion
object
{
fun
newInstance
()
=
LoginFragment
()
private
const
val
DEEP_LINK_INFO
=
"DeepLinkInfo"
fun
newInstance
(
deepLinkInfo
:
LoginDeepLinkInfo
?
=
null
)
=
LoginFragment
().
apply
{
arguments
=
Bundle
().
apply
{
putParcelable
(
DEEP_LINK_INFO
,
deepLinkInfo
)
}
}
}
override
fun
onCreate
(
savedInstanceState
:
Bundle
?)
{
super
.
onCreate
(
savedInstanceState
)
AndroidSupportInjection
.
inject
(
this
)
deepLinkInfo
=
arguments
?.
getParcelable
(
DEEP_LINK_INFO
)
}
override
fun
onCreateView
(
inflater
:
LayoutInflater
,
container
:
ViewGroup
?,
savedInstanceState
:
Bundle
?):
View
?
=
...
...
@@ -61,7 +71,11 @@ class LoginFragment : Fragment(), LoginView {
tintEditTextDrawableStart
()
}
presenter
.
setupView
()
deepLinkInfo
?.
let
{
presenter
.
authenticadeWithDeepLink
(
it
)
}.
ifNull
{
presenter
.
setupView
()
}
}
override
fun
onDestroyView
()
{
...
...
app/src/main/java/chat/rocket/android/authentication/presentation/AuthenticationNavigator.kt
View file @
95a28de4
...
...
@@ -2,6 +2,7 @@ package chat.rocket.android.authentication.presentation
import
android.content.Intent
import
chat.rocket.android.R
import
chat.rocket.android.authentication.domain.model.LoginDeepLinkInfo
import
chat.rocket.android.authentication.login.ui.LoginFragment
import
chat.rocket.android.authentication.registerusername.ui.RegisterUsernameFragment
import
chat.rocket.android.authentication.signup.ui.SignupFragment
...
...
@@ -21,6 +22,12 @@ class AuthenticationNavigator(internal val activity: AuthenticationActivity) {
}
}
fun
toLogin
(
deepLinkInfo
:
LoginDeepLinkInfo
)
{
activity
.
addFragmentBackStack
(
"LoginFragment"
,
R
.
id
.
fragment_container
)
{
LoginFragment
.
newInstance
(
deepLinkInfo
)
}
}
fun
toTwoFA
(
username
:
String
,
password
:
String
)
{
activity
.
addFragmentBackStack
(
"TwoFAFragment"
,
R
.
id
.
fragment_container
)
{
TwoFAFragment
.
newInstance
(
username
,
password
)
...
...
app/src/main/java/chat/rocket/android/authentication/server/presentation/ServerPresenter.kt
View file @
95a28de4
package
chat.rocket.android.authentication.server.presentation
import
chat.rocket.android.authentication.domain.model.LoginDeepLinkInfo
import
chat.rocket.android.authentication.presentation.AuthenticationNavigator
import
chat.rocket.android.core.behaviours.showMessage
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.server.domain.GetAccountsInteractor
import
chat.rocket.android.server.domain.RefreshSettingsInteractor
...
...
@@ -18,6 +20,12 @@ class ServerPresenter @Inject constructor(private val view: ServerView,
private
val
getAccountsInteractor
:
GetAccountsInteractor
)
{
fun
connect
(
server
:
String
)
{
connectToServer
(
server
)
{
navigator
.
toLogin
()
}
}
fun
connectToServer
(
server
:
String
,
block
:
()
->
Unit
)
{
if
(!
server
.
isValidUrl
())
{
view
.
showInvalidServerUrlMessage
()
}
else
{
...
...
@@ -33,17 +41,19 @@ class ServerPresenter @Inject constructor(private val view: ServerView,
try
{
refreshSettingsInteractor
.
refresh
(
server
)
serverInteractor
.
save
(
server
)
navigator
.
toLogin
()
block
()
}
catch
(
ex
:
Exception
)
{
ex
.
message
?.
let
{
view
.
showMessage
(
it
)
}.
ifNull
{
view
.
showGenericErrorMessage
()
}
view
.
showMessage
(
ex
)
}
finally
{
view
.
hideLoading
()
}
}
}
}
fun
deepLink
(
deepLinkInfo
:
LoginDeepLinkInfo
)
{
connectToServer
(
deepLinkInfo
.
url
)
{
navigator
.
toLogin
(
deepLinkInfo
)
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/authentication/server/ui/ServerFragment.kt
View file @
95a28de4
...
...
@@ -7,6 +7,7 @@ import android.view.View
import
android.view.ViewGroup
import
android.view.ViewTreeObserver
import
chat.rocket.android.R
import
chat.rocket.android.authentication.domain.model.LoginDeepLinkInfo
import
chat.rocket.android.authentication.server.presentation.ServerPresenter
import
chat.rocket.android.authentication.server.presentation.ServerView
import
chat.rocket.android.helper.KeyboardHelper
...
...
@@ -17,17 +18,26 @@ import javax.inject.Inject
class
ServerFragment
:
Fragment
(),
ServerView
{
@Inject
lateinit
var
presenter
:
ServerPresenter
private
var
deepLinkInfo
:
LoginDeepLinkInfo
?
=
null
private
val
layoutListener
=
ViewTreeObserver
.
OnGlobalLayoutListener
{
text_server_url
.
isCursorVisible
=
KeyboardHelper
.
isSoftKeyboardShown
(
relative_layout
.
rootView
)
}
companion
object
{
fun
newInstance
()
=
ServerFragment
()
private
const
val
DEEP_LINK_INFO
=
"DeepLinkInfo"
fun
newInstance
(
deepLinkInfo
:
LoginDeepLinkInfo
?)
=
ServerFragment
().
apply
{
arguments
=
Bundle
().
apply
{
putParcelable
(
DEEP_LINK_INFO
,
deepLinkInfo
)
}
}
}
override
fun
onCreate
(
savedInstanceState
:
Bundle
?)
{
super
.
onCreate
(
savedInstanceState
)
AndroidSupportInjection
.
inject
(
this
)
deepLinkInfo
=
arguments
?.
getParcelable
(
DEEP_LINK_INFO
)
}
override
fun
onCreateView
(
inflater
:
LayoutInflater
,
container
:
ViewGroup
?,
savedInstanceState
:
Bundle
?):
View
?
=
...
...
@@ -37,6 +47,10 @@ class ServerFragment : Fragment(), ServerView {
super
.
onViewCreated
(
view
,
savedInstanceState
)
relative_layout
.
viewTreeObserver
.
addOnGlobalLayoutListener
(
layoutListener
)
setupOnClickListener
()
deepLinkInfo
?.
let
{
presenter
.
deepLink
(
it
)
}
}
override
fun
onDestroyView
()
{
...
...
app/src/main/java/chat/rocket/android/authentication/twofactor/ui/TwoFAFragment.kt
View file @
95a28de4
...
...
@@ -28,7 +28,7 @@ class TwoFAFragment : Fragment(), TwoFAView {
private
const
val
PASSWORD
=
"password"
fun
newInstance
(
username
:
String
,
password
:
String
)
=
TwoFAFragment
().
apply
{
arguments
=
Bundle
(
1
).
apply
{
arguments
=
Bundle
(
2
).
apply
{
putString
(
USERNAME
,
username
)
putString
(
PASSWORD
,
password
)
}
...
...
app/src/main/java/chat/rocket/android/authentication/ui/AuthenticationActivity.kt
View file @
95a28de4
...
...
@@ -6,10 +6,11 @@ import android.os.Bundle
import
android.support.v4.app.Fragment
import
android.support.v7.app.AppCompatActivity
import
chat.rocket.android.R
import
chat.rocket.android.authentication.domain.model.LoginDeepLinkInfo
import
chat.rocket.android.authentication.domain.model.getLoginDeepLinkInfo
import
chat.rocket.android.authentication.presentation.AuthenticationPresenter
import
chat.rocket.android.authentication.server.ui.ServerFragment
import
chat.rocket.android.util.extensions.addFragment
import
chat.rocket.android.util.extensions.launchUI
import
dagger.android.AndroidInjection
import
dagger.android.AndroidInjector
import
dagger.android.DispatchingAndroidInjector
...
...
@@ -30,11 +31,13 @@ class AuthenticationActivity : AppCompatActivity(), HasSupportFragmentInjector {
setTheme
(
R
.
style
.
AuthenticationTheme
)
super
.
onCreate
(
savedInstanceState
)
val
deepLinkInfo
=
intent
.
getLoginDeepLinkInfo
()
launch
(
UI
+
job
)
{
val
newServer
=
intent
.
getBooleanExtra
(
INTENT_ADD_NEW_SERVER
,
false
)
presenter
.
loadCredentials
(
newServer
)
{
authenticated
->
// if we got authenticadeWithDeepLink information, pass true to newServer also
presenter
.
loadCredentials
(
newServer
||
deepLinkInfo
!=
null
)
{
authenticated
->
if
(!
authenticated
)
{
showServerInput
(
savedInstanceState
)
showServerInput
(
savedInstanceState
,
deepLinkInfo
)
}
}
}
...
...
@@ -49,9 +52,9 @@ class AuthenticationActivity : AppCompatActivity(), HasSupportFragmentInjector {
return
fragmentDispatchingAndroidInjector
}
fun
showServerInput
(
savedInstanceState
:
Bundle
?)
{
fun
showServerInput
(
savedInstanceState
:
Bundle
?
,
deepLinkInfo
:
LoginDeepLinkInfo
?
)
{
addFragment
(
"ServerFragment"
,
R
.
id
.
fragment_container
)
{
ServerFragment
.
newInstance
()
ServerFragment
.
newInstance
(
deepLinkInfo
)
}
}
}
...
...
app/src/main/java/chat/rocket/android/chatroom/adapter/ChatRoomAdapter.kt
View file @
95a28de4
...
...
@@ -57,6 +57,10 @@ class ChatRoomAdapter(
val
view
=
parent
.
inflate
(
R
.
layout
.
item_author_attachment
)
AuthorAttachmentViewHolder
(
view
,
actionsListener
,
reactionListener
)
}
BaseViewModel
.
ViewType
.
COLOR_ATTACHMENT
->
{
val
view
=
parent
.
inflate
(
R
.
layout
.
item_color_attachment
)
ColorAttachmentViewHolder
(
view
,
actionsListener
,
reactionListener
)
}
else
->
{
throw
InvalidParameterException
(
"TODO - implement for ${viewType.toViewType()}"
)
}
...
...
@@ -97,6 +101,7 @@ class ChatRoomAdapter(
is
UrlPreviewViewHolder
->
holder
.
bind
(
dataSet
[
position
]
as
UrlPreviewViewModel
)
is
MessageAttachmentViewHolder
->
holder
.
bind
(
dataSet
[
position
]
as
MessageAttachmentViewModel
)
is
AuthorAttachmentViewHolder
->
holder
.
bind
(
dataSet
[
position
]
as
AuthorAttachmentViewModel
)
is
ColorAttachmentViewHolder
->
holder
.
bind
(
dataSet
[
position
]
as
ColorAttachmentViewModel
)
}
}
...
...
app/src/main/java/chat/rocket/android/chatroom/adapter/ColorAttachmentViewHolder.kt
0 → 100644
View file @
95a28de4
package
chat.rocket.android.chatroom.adapter
import
android.graphics.drawable.Drawable
import
android.support.v4.content.ContextCompat
import
android.text.method.LinkMovementMethod
import
android.view.View
import
chat.rocket.android.R
import
chat.rocket.android.chatroom.viewmodel.ColorAttachmentViewModel
import
chat.rocket.android.widget.emoji.EmojiReactionListener
import
kotlinx.android.synthetic.main.item_color_attachment.view.*
class
ColorAttachmentViewHolder
(
itemView
:
View
,
listener
:
BaseViewHolder
.
ActionsListener
,
reactionListener
:
EmojiReactionListener
?
=
null
)
:
BaseViewHolder
<
ColorAttachmentViewModel
>(
itemView
,
listener
,
reactionListener
)
{
val
drawable
:
Drawable
?
=
ContextCompat
.
getDrawable
(
itemView
.
context
,
R
.
drawable
.
quote_vertical_bar
)
init
{
with
(
itemView
)
{
setupActionMenu
(
attachment_text
)
setupActionMenu
(
color_attachment_container
)
attachment_text
.
movementMethod
=
LinkMovementMethod
()
}
}
override
fun
bindViews
(
data
:
ColorAttachmentViewModel
)
{
with
(
itemView
)
{
drawable
?.
let
{
quote_bar
.
background
=
drawable
.
mutate
().
apply
{
setTint
(
data
.
color
)
}
attachment_text
.
text
=
data
.
text
}
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
View file @
95a28de4
...
...
@@ -233,9 +233,9 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
// if y is positive the keyboard is up else it's down
recycler_view
.
post
{
if
(
y
>
0
||
Math
.
abs
(
verticalScrollOffset
.
get
())
>=
Math
.
abs
(
y
))
{
recycler_view
.
scrollBy
(
0
,
y
)
ui
{
recycler_view
.
scrollBy
(
0
,
y
)
}
}
else
{
recycler_view
.
scrollBy
(
0
,
verticalScrollOffset
.
get
())
ui
{
recycler_view
.
scrollBy
(
0
,
verticalScrollOffset
.
get
())
}
}
}
}
...
...
app/src/main/java/chat/rocket/android/chatroom/viewmodel/BaseViewModel.kt
View file @
95a28de4
...
...
@@ -22,7 +22,8 @@ interface BaseViewModel<out T> {
VIDEO_ATTACHMENT
(
4
),
AUDIO_ATTACHMENT
(
5
),
MESSAGE_ATTACHMENT
(
6
),
AUTHOR_ATTACHMENT
(
7
)
AUTHOR_ATTACHMENT
(
7
),
COLOR_ATTACHMENT
(
8
)
}
}
...
...
app/src/main/java/chat/rocket/android/chatroom/viewmodel/ColorAttachmentViewModel.kt
0 → 100644
View file @
95a28de4
package
chat.rocket.android.chatroom.viewmodel
import
chat.rocket.android.R
import
chat.rocket.core.model.Message
import
chat.rocket.core.model.attachment.ColorAttachment
data class
ColorAttachmentViewModel
(
override
val
attachmentUrl
:
String
,
val
id
:
Long
,
val
color
:
Int
,
val
text
:
CharSequence
,
override
val
message
:
Message
,
override
val
rawData
:
ColorAttachment
,
override
val
messageId
:
String
,
override
var
reactions
:
List
<
ReactionViewModel
>,
override
var
nextDownStreamMessage
:
BaseViewModel
<*>?
=
null
,
override
var
preview
:
Message
?
=
null
,
override
var
isTemporary
:
Boolean
=
false
)
:
BaseAttachmentViewModel
<
ColorAttachment
>
{
override
val
viewType
:
Int
get
()
=
BaseViewModel
.
ViewType
.
COLOR_ATTACHMENT
.
viewType
override
val
layoutId
:
Int
get
()
=
R
.
layout
.
item_color_attachment
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/viewmodel/ViewModelMapper.kt
View file @
95a28de4
...
...
@@ -5,6 +5,7 @@ import android.content.Context
import
android.graphics.Color
import
android.graphics.Typeface
import
android.support.v4.content.ContextCompat
import
android.text.Html
import
android.text.SpannableStringBuilder
import
android.text.style.ForegroundColorSpan
import
android.text.style.StyleSpan
...
...
@@ -106,10 +107,23 @@ class ViewModelMapper @Inject constructor(private val context: Context,
is
FileAttachment
->
mapFileAttachment
(
message
,
attachment
)
is
MessageAttachment
->
mapMessageAttachment
(
message
,
attachment
)
is
AuthorAttachment
->
mapAuthorAttachment
(
message
,
attachment
)
is
ColorAttachment
->
mapColorAttachment
(
message
,
attachment
)
else
->
null
}
}
private
suspend
fun
mapColorAttachment
(
message
:
Message
,
attachment
:
ColorAttachment
):
BaseViewModel
<
*
>?
{
return
with
(
attachment
)
{
val
content
=
stripMessageQuotes
(
message
)
val
id
=
attachmentId
(
message
,
attachment
)
ColorAttachmentViewModel
(
attachmentUrl
=
url
,
id
=
id
,
color
=
color
.
color
,
text
=
text
,
message
=
message
,
rawData
=
attachment
,
messageId
=
message
.
id
,
reactions
=
getReactions
(
message
),
preview
=
message
.
copy
(
message
=
content
.
message
))
}
}
private
suspend
fun
mapAuthorAttachment
(
message
:
Message
,
attachment
:
AuthorAttachment
):
AuthorAttachmentViewModel
{
return
with
(
attachment
)
{
val
content
=
stripMessageQuotes
(
message
)
...
...
app/src/main/java/chat/rocket/android/core/behaviours/MessageView.kt
View file @
95a28de4
package
chat.rocket.android.core.behaviours
import
android.support.annotation.StringRes
import
chat.rocket.common.util.ifNull
interface
MessageView
{
...
...
@@ -14,4 +15,12 @@ interface MessageView {
fun
showMessage
(
message
:
String
)
fun
showGenericErrorMessage
()
}
fun
MessageView
.
showMessage
(
ex
:
Exception
)
{
ex
.
message
?.
let
{
showMessage
(
it
)
}.
ifNull
{
showGenericErrorMessage
()
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/dagger/module/AppModule.kt
View file @
95a28de4
...
...
@@ -16,6 +16,7 @@ import chat.rocket.android.authentication.infraestructure.SharedPreferencesMulti
import
chat.rocket.android.authentication.infraestructure.SharedPreferencesTokenRepository
import
chat.rocket.android.chatroom.service.MessageService
import
chat.rocket.android.dagger.qualifier.ForFresco
import
chat.rocket.android.dagger.qualifier.ForMessages
import
chat.rocket.android.helper.FrescoAuthInterceptor
import
chat.rocket.android.helper.MessageParser
import
chat.rocket.android.infrastructure.LocalRepository
...
...
@@ -73,7 +74,7 @@ class AppModule {
@Provides
@Singleton
fun
provideRocketChatDatabase
(
context
:
Application
):
RocketChatDatabase
{
return
Room
.
databaseBuilder
(
context
,
RocketChatDatabase
::
class
.
java
,
"rocketchat-db"
).
build
()
return
Room
.
databaseBuilder
(
context
.
applicationContext
,
RocketChatDatabase
::
class
.
java
,
"rocketchat-db"
).
build
()
}
@Provides
...
...
@@ -168,9 +169,14 @@ class AppModule {
}
@Provides
fun
provideSharedPreferences
(
context
:
Application
):
SharedPreferences
{
return
context
.
getSharedPreferences
(
"rocket.chat"
,
Context
.
MODE_PRIVATE
)
}
fun
provideSharedPreferences
(
context
:
Application
)
=
context
.
getSharedPreferences
(
"rocket.chat"
,
Context
.
MODE_PRIVATE
)
@Provides
@ForMessages
fun
provideMessagesSharedPreferences
(
context
:
Application
)
=
context
.
getSharedPreferences
(
"messages"
,
Context
.
MODE_PRIVATE
)
@Provides
@Singleton
...
...
@@ -225,8 +231,10 @@ class AppModule {
@Provides
@Singleton
fun
provideMessageRepository
(
context
:
Application
,
moshi
:
Moshi
,
currentServerInteractor
:
GetCurrentServerInteractor
):
MessagesRepository
{
val
preferences
=
context
.
getSharedPreferences
(
"messages"
,
Context
.
MODE_PRIVATE
)
fun
provideMessageRepository
(
context
:
Application
,
@ForMessages
preferences
:
SharedPreferences
,
moshi
:
Moshi
,
currentServerInteractor
:
GetCurrentServerInteractor
):
MessagesRepository
{
return
SharedPreferencesMessagesRepository
(
preferences
,
moshi
,
currentServerInteractor
)
}
...
...
app/src/main/java/chat/rocket/android/dagger/qualifier/ForMessages.kt
0 → 100644
View file @
95a28de4
package
chat.rocket.android.dagger.qualifier
import
javax.inject.Qualifier
/**
* Created by luciofm on 4/14/18.
*/
@Qualifier
@Retention
(
AnnotationRetention
.
RUNTIME
)
annotation
class
ForMessages
\ No newline at end of file
app/src/main/java/chat/rocket/android/main/presentation/MainPresenter.kt
View file @
95a28de4
...
...
@@ -41,7 +41,7 @@ class MainPresenter @Inject constructor(
private
val
factory
:
RocketChatClientFactory
,
getSettingsInteractor
:
GetSettingsInteractor
,
managerFactory
:
ConnectionManagerFactory
)
:
CheckServerPresenter
(
strategy
,
client
=
factory
.
create
(
serverInteractor
.
get
()
!!
)
,
view
=
view
)
{
)
:
CheckServerPresenter
(
strategy
,
factory
,
view
=
view
)
{
private
val
currentServer
=
serverInteractor
.
get
()
!!
private
val
manager
=
managerFactory
.
create
(
currentServer
)
private
val
client
:
RocketChatClient
=
factory
.
create
(
currentServer
)
...
...
@@ -56,7 +56,7 @@ class MainPresenter @Inject constructor(
fun
toSettings
()
=
navigator
.
toSettings
()
fun
loadCurrentInfo
()
{
checkServerInfo
()
checkServerInfo
(
currentServer
)
launchUI
(
strategy
)
{
try
{
val
me
=
retryIO
(
"me"
)
{
...
...
app/src/main/java/chat/rocket/android/server/domain/RefreshSettingsInteractor.kt
View file @
95a28de4
package
chat.rocket.android.server.domain
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.android.util.retryIO
import
chat.rocket.core.internal.rest.settings
import
kotlinx.coroutines.experimental.CommonPool
import
kotlinx.coroutines.experimental.async
...
...
@@ -27,7 +28,9 @@ class RefreshSettingsInteractor @Inject constructor(private val factory: RocketC
suspend
fun
refresh
(
server
:
String
)
{
withContext
(
CommonPool
)
{
factory
.
create
(
server
).
let
{
client
->
val
settings
=
client
.
settings
(*
settingsFilter
)
val
settings
=
retryIO
(
description
=
"settings"
,
times
=
5
)
{
client
.
settings
(*
settingsFilter
)
}
repository
.
save
(
server
,
settings
)
}
}
...
...
app/src/main/java/chat/rocket/android/server/presentation/CheckServerPresenter.kt
View file @
95a28de4
...
...
@@ -3,33 +3,40 @@ package chat.rocket.android.server.presentation
import
chat.rocket.android.BuildConfig
import
chat.rocket.android.authentication.server.presentation.VersionCheckView
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.android.util.VersionInfo
import
chat.rocket.android.util.extensions.launchUI
import
chat.rocket.android.util.retryIO
import
chat.rocket.core.RocketChatClient
import
chat.rocket.core.internal.rest.serverInfo
import
kotlinx.coroutines.experimental.Deferred
import
kotlinx.coroutines.experimental.Job
import
kotlinx.coroutines.experimental.async
import
timber.log.Timber
abstract
class
CheckServerPresenter
constructor
(
private
val
strategy
:
CancelStrategy
,
private
val
client
:
RocketChatClient
,
private
val
factory
:
RocketChatClientFactory
,
private
val
view
:
VersionCheckView
)
{
internal
fun
checkServerInfo
()
{
launchUI
(
strategy
)
{
private
lateinit
var
currentServer
:
String
private
val
client
:
RocketChatClient
by
lazy
{
factory
.
create
(
currentServer
)
}
internal
fun
checkServerInfo
(
serverUrl
:
String
):
Job
{
return
launchUI
(
strategy
)
{
try
{
val
serverInfo
=
retryIO
(
description
=
"serverInfo"
,
times
=
5
)
{
client
.
serverInfo
()
}
val
thisServerVersion
=
serverInfo
.
version
val
isRequiredVersion
=
isRequiredServerVersion
(
thisServerVersion
)
val
isRecommendedVersion
=
isRecommendedServerVersion
(
thisServerVersion
)
if
(
isRequiredVersion
)
{
if
(
isRecommendedVersion
)
{
Timber
.
i
(
"Your version is nice! (Requires: 0.62.0, Yours: $thisServerVersion)"
)
}
else
{
val
version
=
checkServerVersion
(
serverUrl
).
await
()
when
(
version
)
{
is
Version
.
VersionOk
->
{
Timber
.
i
(
"Your version is nice! (Requires: 0.62.0, Yours: ${version.version})"
)
}
is
Version
.
RecommendedVersionWarning
->
{
Timber
.
i
(
"Your server ${version.version} is bellow recommended version ${BuildConfig.RECOMMENDED_SERVER_VERSION}"
)
view
.
alertNotRecommendedVersion
()
}
}
else
{
if
(!
isRecommendedVersion
)
{
is
Version
.
OutOfDateError
->
{
Timber
.
i
(
"Oops. Looks like your server ${version.version} is out-of-date! Minimum server version required ${BuildConfig.REQUIRED_SERVER_VERSION}!"
)
view
.
blockAndAlertNotRequiredVersion
()
Timber
.
i
(
"Oops. Looks like your server is out-of-date! Minimum server version required ${BuildConfig.REQUIRED_SERVER_VERSION}!"
)
}
}
}
catch
(
ex
:
Exception
)
{
...
...
@@ -38,6 +45,26 @@ abstract class CheckServerPresenter constructor(private val strategy: CancelStra
}
}
internal
fun
checkServerVersion
(
serverUrl
:
String
):
Deferred
<
Version
>
{
currentServer
=
serverUrl
return
async
{
val
serverInfo
=
retryIO
(
description
=
"serverInfo"
,
times
=
5
)
{
client
.
serverInfo
()
}
val
thisServerVersion
=
serverInfo
.
version
val
isRequiredVersion
=
isRequiredServerVersion
(
thisServerVersion
)
val
isRecommendedVersion
=
isRecommendedServerVersion
(
thisServerVersion
)
if
(
isRequiredVersion
)
{
if
(
isRecommendedVersion
)
{
Timber
.
i
(
"Your version is nice! (Requires: 0.62.0, Yours: $thisServerVersion)"
)
return
@async
Version
.
VersionOk
(
thisServerVersion
)
}
else
{
return
@async
Version
.
RecommendedVersionWarning
(
thisServerVersion
)
}
}
else
{
return
@async
Version
.
OutOfDateError
(
thisServerVersion
)
}
}
}
private
fun
isRequiredServerVersion
(
version
:
String
):
Boolean
{
return
isMinimumVersion
(
version
,
getVersionDistilled
(
BuildConfig
.
REQUIRED_SERVER_VERSION
))
}
...
...
@@ -92,4 +119,10 @@ abstract class CheckServerPresenter constructor(private val strategy: CancelStra
0
}
}
sealed
class
Version
(
val
version
:
String
)
{
data class
VersionOk
(
private
val
currentVersion
:
String
)
:
Version
(
currentVersion
)
data class
RecommendedVersionWarning
(
private
val
currentVersion
:
String
)
:
Version
(
currentVersion
)
data class
OutOfDateError
(
private
val
currentVersion
:
String
)
:
Version
(
currentVersion
)
}
}
\ No newline at end of file
app/src/main/res/layout/fragment_profile.xml
View file @
95a28de4
...
...
@@ -8,53 +8,61 @@
android:focusableInTouchMode=
"true"
tools:context=
".profile.ui.ProfileFragment"
>
<LinearLayout
android:id=
"@+id/profile_container"
<ScrollView
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:gravity=
"center"
android:orientation=
"vertical"
android:visibility=
"gone"
>
android:layout_height=
"wrap_content"
>
<include
android:id=
"@+id/layout_avatar_profile"
layout=
"@layout/avatar_profile"
android:layout_width=
"wrap_content"
<LinearLayout
android:id=
"@+id/profile_container"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_marginTop=
"32dp"
/>
android:gravity=
"center"
android:orientation=
"vertical"
android:visibility=
"gone"
tools:visibility=
"visible"
>
<include
android:id=
"@+id/layout_avatar_profile"
layout=
"@layout/avatar_profile"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_marginTop=
"32dp"
/>
<EditText
android:id=
"@+id/text_name"
style=
"@style/Profile.EditText"
android:layout_marginTop=
"32dp"
android:drawableStart=
"@drawable/ic_person_black_24dp"
android:hint=
"@string/msg_name"
android:inputType=
"textCapWords"
/>
<EditText
android:id=
"@+id/text_
name"
style=
"@style/Profile.EditText"
android:layout_marginTop=
"32
dp"
android:drawableStart=
"@drawable/ic_person
_black_24dp"
android:hint=
"@string/msg_
name"
android:inputType=
"textCapWords
"
/>
<EditText
android:id=
"@+id/text_user
name"
style=
"@style/Profile.EditText"
android:layout_marginTop=
"16
dp"
android:drawableStart=
"@drawable/ic_at
_black_24dp"
android:hint=
"@string/msg_user
name"
android:inputType=
"text
"
/>
<EditText
android:id=
"@+id/text_username
"
style=
"@style/Profile.EditText"
android:layout_marginTop=
"16dp"
android:drawableStart=
"@drawable/ic_at
_black_24dp"
android:hint=
"@string/msg_username
"
android:inputType=
"text
"
/>
<EditText
android:id=
"@+id/text_email
"
style=
"@style/Profile.EditText"
android:layout_marginTop=
"16dp"
android:drawableStart=
"@drawable/ic_email
_black_24dp"
android:hint=
"@string/msg_email
"
android:inputType=
"textEmailAddress
"
/>
<EditText
android:id=
"@+id/text_email"
style=
"@style/Profile.EditText"
android:layout_marginTop=
"16dp"
android:drawableStart=
"@drawable/ic_email_black_24dp"
android:hint=
"@string/msg_email"
android:inputType=
"textEmailAddress"
/>
<EditText
android:id=
"@+id/text_avatar_url"
style=
"@style/Profile.EditText"
android:layout_marginTop=
"16dp"
android:drawableStart=
"@drawable/ic_link_black_24dp"
android:hint=
"@string/msg_avatar_url"
android:inputType=
"text"
android:layout_marginBottom=
"16dp"
/>
</LinearLayout>
<EditText
android:id=
"@+id/text_avatar_url"
style=
"@style/Profile.EditText"
android:layout_marginTop=
"16dp"
android:drawableStart=
"@drawable/ic_link_black_24dp"
android:hint=
"@string/msg_avatar_url"
android:inputType=
"text"
/>
</LinearLayout>
</ScrollView>
<com.wang.avi.AVLoadingIndicatorView
android:id=
"@+id/view_loading"
...
...
app/src/main/res/layout/item_color_attachment.xml
0 → 100644
View file @
95a28de4
<?xml version="1.0" encoding="utf-8"?>
<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/color_attachment_container"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:background=
"?android:attr/selectableItemBackground"
android:clickable=
"true"
android:focusable=
"true"
android:paddingBottom=
"@dimen/message_item_top_and_bottom_padding"
android:paddingEnd=
"@dimen/screen_edge_left_and_right_padding"
android:paddingStart=
"@dimen/screen_edge_left_and_right_padding"
android:paddingTop=
"@dimen/message_item_top_and_bottom_padding"
>
<View
android:id=
"@+id/quote_bar"
android:layout_width=
"4dp"
android:layout_height=
"0dp"
android:layout_marginStart=
"56dp"
android:background=
"@drawable/quote_vertical_bar"
app:layout_constraintStart_toStartOf=
"parent"
app:layout_constraintTop_toTopOf=
"parent"
app:layout_constraintBottom_toTopOf=
"@id/recycler_view_reactions"
/>
<TextView
android:id=
"@+id/attachment_text"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_marginStart=
"8dp"
android:textAppearance=
"@style/TextAppearance.AppCompat.Body1"
android:autoLink=
"web"
app:layout_constraintStart_toEndOf=
"@id/quote_bar"
app:layout_constraintEnd_toEndOf=
"parent"
tools:text=
"#5571 - User profile from SSO must not have password change option"
/>
<include
layout=
"@layout/layout_reactions"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
app:layout_constraintStart_toStartOf=
"@id/quote_bar"
app:layout_constraintTop_toBottomOf=
"@id/attachment_text"
/>
</android.support.constraint.ConstraintLayout>
\ No newline at end of file
app/src/main/res/xml/backup_config.xml
0 → 100644
View file @
95a28de4
<?xml version="1.0" encoding="utf-8"?>
<full-backup-content
xmlns:tools=
"http://schemas.android.com/tools"
>
<include
domain=
"sharedpref"
path=
"."
/>
<exclude
domain=
"sharedpref"
path=
"messages.xml"
tools:ignore=
"FullBackupContent"
/>
<exclude
domain=
"file"
path=
"instant-run"
tools:ignore=
"FullBackupContent"
/>
</full-backup-content>
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