Commit a75ac7a3 authored by Leonardo Aramaki's avatar Leonardo Aramaki

Merge branch 'markdown-support' into actions-delete

parents c0127753 eefea063
......@@ -71,8 +71,8 @@ dependencies {
kapt libraries.roomProcessor
implementation libraries.roomRxjava
implementation libraries.rxjava
implementation libraries.rxandroid
implementation libraries.rxKotlin
implementation libraries.rxAndroid
implementation libraries.moshi
implementation libraries.okhttp
......@@ -80,6 +80,7 @@ dependencies {
implementation libraries.timber
implementation libraries.threeTenABP
implementation libraries.rxBinding
implementation libraries.fresco
api libraries.frescoOkHttp
......@@ -87,12 +88,10 @@ dependencies {
implementation libraries.frescoWebP
implementation libraries.frescoAnimatedWebP
implementation libraries.frescoImageViewer
kapt libraries.kotshiCompiler
implementation libraries.kotshiApi
implementation libraries.floatingSearchView
implementation libraries.frescoImageViewer
implementation libraries.androidSvg
......@@ -104,6 +103,8 @@ dependencies {
implementation libraries.markwonImageLoader
implementation libraries.moshiLazyAdapters
implementation('com.crashlytics.sdk.android:crashlytics:2.6.8@aar') {
transitive = true
}
......
......@@ -19,14 +19,13 @@
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
android:supportsRtl="true">
<activity
android:name=".authentication.ui.AuthenticationActivity"
android:configChanges="orientation"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.SplashScreen"
android:theme="@style/AuthenticationTheme"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
......@@ -41,8 +40,8 @@
android:theme="@style/AppTheme" />
<activity
android:name=".chatrooms.ui.ChatRoomsActivity"
android:theme="@style/ChatListTheme" />
android:name=".main.ui.MainActivity"
android:theme="@style/AppTheme" />
<activity
android:name=".chatroom.ui.ChatRoomActivity"
......
......@@ -25,8 +25,6 @@ import io.fabric.sdk.android.Fabric
import timber.log.Timber
import javax.inject.Inject
class RocketChatApplication : Application(), HasActivityInjector, HasServiceInjector {
@Inject
......
......@@ -7,7 +7,7 @@ import chat.rocket.android.authentication.login.ui.LoginFragment
import chat.rocket.android.authentication.signup.ui.SignupFragment
import chat.rocket.android.authentication.twofactor.ui.TwoFAFragment
import chat.rocket.android.authentication.ui.AuthenticationActivity
import chat.rocket.android.chatrooms.ui.ChatRoomsActivity
import chat.rocket.android.main.ui.MainActivity
import chat.rocket.android.util.addFragmentBackStack
import chat.rocket.android.webview.webViewIntent
......@@ -36,7 +36,7 @@ class AuthenticationNavigator(internal val activity: AuthenticationActivity, int
}
fun toChatList() {
val chatList = Intent(activity, ChatRoomsActivity::class.java).apply {
val chatList = Intent(activity, MainActivity::class.java).apply {
//TODO any parameter to pass
}
activity.startActivity(chatList)
......
......@@ -55,7 +55,7 @@ class TwoFAFragment : Fragment(), TwoFAView {
activity?.apply {
text_two_factor_auth.requestFocus()
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(text_two_factor_auth, InputMethodManager.SHOW_IMPLICIT)
imm.showSoftInput(text_two_factor_auth, InputMethodManager.RESULT_UNCHANGED_SHOWN)
}
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
......
......@@ -2,7 +2,7 @@ package chat.rocket.android.chatrooms.di
import android.content.Context
import chat.rocket.android.chatrooms.presentation.ChatRoomsNavigator
import chat.rocket.android.chatrooms.ui.ChatRoomsActivity
import chat.rocket.android.main.ui.MainActivity
import chat.rocket.android.dagger.scope.PerActivity
import dagger.Module
import dagger.Provides
......@@ -12,5 +12,5 @@ class ChatRoomsModule {
@Provides
@PerActivity
fun provideAuthenticationNavigator(activity: ChatRoomsActivity, context: Context) = ChatRoomsNavigator(activity, context)
fun provideChatRoomsNavigator(activity: MainActivity, context: Context) = ChatRoomsNavigator(activity, context)
}
\ No newline at end of file
......@@ -3,9 +3,9 @@ package chat.rocket.android.chatrooms.presentation
import android.content.Context
import chat.rocket.android.R
import chat.rocket.android.chatroom.ui.chatRoomIntent
import chat.rocket.android.chatrooms.ui.ChatRoomsActivity
import chat.rocket.android.main.ui.MainActivity
class ChatRoomsNavigator(private val activity: ChatRoomsActivity, private val context: Context) {
class ChatRoomsNavigator(private val activity: MainActivity, private val context: Context) {
fun toChatRoom(chatRoomId: String, chatRoomName: String, chatRoomType: String, isChatRoomReadOnly: Boolean) {
activity.startActivity(context.chatRoomIntent(chatRoomId, chatRoomName, chatRoomType, isChatRoomReadOnly))
......
......@@ -14,7 +14,12 @@ interface ChatRoomsView : LoadingView, MessageView {
suspend fun updateChatRooms(newDataSet: List<ChatRoom>)
/**
* User has successfully logged out from the current server.
* Shows no chat rooms to display.
*/
fun showNoChatRoomsToDisplay()
/**
* User has successfully logged out from the current server.
**/
fun onLogout()
}
\ No newline at end of file
package chat.rocket.android.chatrooms.ui
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.util.addFragment
import dagger.android.AndroidInjection
import dagger.android.AndroidInjector
import dagger.android.DispatchingAndroidInjector
import dagger.android.support.HasSupportFragmentInjector
import javax.inject.Inject
class ChatRoomsActivity : AppCompatActivity(), HasSupportFragmentInjector {
@Inject lateinit var fragmentDispatchingAndroidInjector: DispatchingAndroidInjector<Fragment>
override fun onCreate(savedInstanceState: Bundle?) {
AndroidInjection.inject(this)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_chat_rooms)
addFragment("ChatRoomsFragment", R.id.fragment_container) {
ChatRoomsFragment.newInstance()
}
}
override fun onDestroy() {
super.onDestroy()
}
override fun supportFragmentInjector(): AndroidInjector<Fragment> {
return fragmentDispatchingAndroidInjector
}
}
\ No newline at end of file
......@@ -14,21 +14,19 @@ import chat.rocket.android.R
import chat.rocket.android.authentication.ui.AuthenticationActivity
import chat.rocket.android.chatrooms.presentation.ChatRoomsPresenter
import chat.rocket.android.chatrooms.presentation.ChatRoomsView
import chat.rocket.android.util.inflate
import chat.rocket.android.util.setVisible
import chat.rocket.android.widget.DividerItemDecoration
import chat.rocket.core.model.ChatRoom
import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.app_bar.*
import kotlinx.android.synthetic.main.fragment_chat_rooms.*
import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.android.UI
import kotlinx.coroutines.experimental.async
import kotlinx.coroutines.experimental.launch
import timber.log.Timber
import javax.inject.Inject
class ChatRoomsFragment : Fragment(), ChatRoomsView {
@Inject lateinit var presenter: ChatRoomsPresenter
private var searchView: SearchView? = null
......@@ -43,45 +41,27 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
}
override fun onDestroy() {
Timber.d("Called on destroy...")
presenter.disconnect()
super.onDestroy()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = inflater.inflate(R.layout.fragment_chat_rooms, container, false)
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = container?.inflate(R.layout.fragment_chat_rooms)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
(activity as AppCompatActivity).apply {
recycler_view.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
recycler_view.addItemDecoration(DividerItemDecoration(this, 144, 32))
recycler_view.itemAnimator = DefaultItemAnimator()
recycler_view.adapter = ChatRoomsAdapter(this) { chatRoom ->
presenter.loadChatRoom(chatRoom)
}
if (supportActionBar == null) {
setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(false)
supportActionBar?.setDisplayShowHomeEnabled(true)
//TODO: should display the current server "SiteName" setting?
supportActionBar?.setDisplayShowTitleEnabled(true)
supportActionBar?.title = "Rocket.Chat"
}
}
setupToolbar()
setupRecyclerView()
presenter.loadChatRooms()
}
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
inflater?.inflate(R.menu.chatrooms_menu, menu)
val searchItem = menu?.findItem(R.id.action_search)
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
inflater.inflate(R.menu.chatrooms, menu)
val searchItem = menu.findItem(R.id.action_search)
searchView = searchItem?.actionView as SearchView
val sv = searchView
sv?.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
searchView?.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean {
return queryChatRoomsByName(query)
}
......@@ -113,6 +93,8 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
}
}
override fun showNoChatRoomsToDisplay() = text_no_data_to_display.setVisible(true)
override fun showLoading() = view_loading.setVisible(true)
override fun hideLoading() = view_loading.setVisible(false)
......@@ -130,6 +112,21 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
}
}
private fun setupToolbar() {
(activity as AppCompatActivity).supportActionBar?.title = getString(R.string.title_chats)
}
private fun setupRecyclerView() {
activity?.apply {
recycler_view.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
recycler_view.addItemDecoration(DividerItemDecoration(this, 144, 32))
recycler_view.itemAnimator = DefaultItemAnimator()
recycler_view.adapter = ChatRoomsAdapter(this) { chatRoom ->
presenter.loadChatRoom(chatRoom)
}
}
}
private fun queryChatRoomsByName(name: String?): Boolean {
presenter.chatRoomsByName(name ?: "")
return true
......
......@@ -10,8 +10,9 @@ import chat.rocket.android.chatroom.di.ChatRoomFragmentProvider
import chat.rocket.android.chatroom.ui.ChatRoomActivity
import chat.rocket.android.chatrooms.di.ChatRoomsFragmentProvider
import chat.rocket.android.chatrooms.di.ChatRoomsModule
import chat.rocket.android.chatrooms.ui.ChatRoomsActivity
import chat.rocket.android.main.ui.MainActivity
import chat.rocket.android.dagger.scope.PerActivity
import chat.rocket.android.profile.di.ProfileFragmentProvider
import dagger.Module
import dagger.android.ContributesAndroidInjector
......@@ -28,8 +29,8 @@ abstract class ActivityBuilder {
abstract fun bindAuthenticationActivity(): AuthenticationActivity
@PerActivity
@ContributesAndroidInjector(modules = [ChatRoomsModule::class, ChatRoomsFragmentProvider::class])
abstract fun bindMainActivity(): ChatRoomsActivity
@ContributesAndroidInjector(modules = [ChatRoomsModule::class, ChatRoomsFragmentProvider::class, ProfileFragmentProvider::class])
abstract fun bindMainActivity(): MainActivity
@PerActivity
@ContributesAndroidInjector(modules = [ChatRoomFragmentProvider::class])
......
package chat.rocket.android.main.ui
import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v7.app.AppCompatActivity
import android.view.Gravity
import android.view.MenuItem
import chat.rocket.android.R
import chat.rocket.android.chatrooms.ui.ChatRoomsFragment
import chat.rocket.android.profile.ui.ProfileFragment
import chat.rocket.android.util.addFragment
import dagger.android.AndroidInjection
import dagger.android.AndroidInjector
import dagger.android.DispatchingAndroidInjector
import dagger.android.support.HasSupportFragmentInjector
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.app_bar.*
import javax.inject.Inject
class MainActivity : AppCompatActivity(), HasSupportFragmentInjector {
@Inject lateinit var fragmentDispatchingAndroidInjector: DispatchingAndroidInjector<Fragment>
private var isFragmentAdded: Boolean = false
override fun onCreate(savedInstanceState: Bundle?) {
AndroidInjection.inject(this)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setupToolbar()
setupNavigationView()
}
override fun onResume() {
super.onResume()
if (!isFragmentAdded) {
// Adding the first fragment.
addFragment("ChatRoomsFragment")
isFragmentAdded = true
}
}
override fun supportFragmentInjector(): AndroidInjector<Fragment> = fragmentDispatchingAndroidInjector
private fun setupToolbar() {
setSupportActionBar(toolbar)
toolbar.setNavigationIcon(R.drawable.ic_menu_white_24dp)
toolbar.setNavigationOnClickListener {
drawer_layout.openDrawer(Gravity.START)
}
}
private fun setupNavigationView() {
view_navigation.setNavigationItemSelectedListener { menuItem ->
menuItem.isChecked = true
drawer_layout.closeDrawer(Gravity.START)
onNavDrawerItemSelected(menuItem)
true
}
}
private fun onNavDrawerItemSelected(menuItem: MenuItem) {
when (menuItem.itemId) {
R.id.action_chat_rooms -> {
addFragment("ChatRoomsFragment", R.id.fragment_container) {
ChatRoomsFragment.newInstance()
}
}
R.id.action_profile -> {
addFragment("ProfileFragment", R.id.fragment_container) {
ProfileFragment.newInstance()
}
}
}
}
private fun addFragment(tag: String) {
addFragment(tag, R.id.fragment_container) {
ChatRoomsFragment.newInstance()
}
}
}
\ No newline at end of file
package chat.rocket.android.profile.di
import android.arch.lifecycle.LifecycleOwner
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.dagger.scope.PerFragment
import chat.rocket.android.profile.presentation.ProfileView
import chat.rocket.android.profile.ui.ProfileFragment
import dagger.Module
import dagger.Provides
import kotlinx.coroutines.experimental.Job
@Module
@PerFragment
class ProfileFragmentModule {
@Provides
fun profileView(frag: ProfileFragment): ProfileView {
return frag
}
@Provides
fun provideLifecycleOwner(frag: ProfileFragment): LifecycleOwner {
return frag
}
@Provides
fun provideCancelStrategy(owner: LifecycleOwner, jobs: Job): CancelStrategy {
return CancelStrategy(owner, jobs)
}
}
\ No newline at end of file
package chat.rocket.android.profile.di
import chat.rocket.android.profile.ui.ProfileFragment
import dagger.Module
import dagger.android.ContributesAndroidInjector
@Module
abstract class ProfileFragmentProvider {
@ContributesAndroidInjector(modules = [ProfileFragmentModule::class])
abstract fun provideProfileFragment(): ProfileFragment
}
\ No newline at end of file
package chat.rocket.android.profile.presentation
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.helper.UrlHelper
import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.launchUI
import chat.rocket.common.RocketChatException
import chat.rocket.common.util.ifNull
import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.rest.me
import chat.rocket.core.internal.rest.updateProfile
import javax.inject.Inject
class ProfilePresenter @Inject constructor (private val view: ProfileView,
private val strategy: CancelStrategy,
serverInteractor: GetCurrentServerInteractor,
factory: RocketChatClientFactory) {
private val serverUrl = serverInteractor.get()!!
private val client: RocketChatClient = factory.create(serverUrl)
private lateinit var myselfId: String
fun loadUserProfile() {
launchUI(strategy) {
view.showLoading()
try {
val myself = client.me()
myselfId = myself.id
val avatarUrl = UrlHelper.getAvatarUrl(serverUrl, myself.username!!)
view.showProfile(avatarUrl, myself.name!!, myself.username!!, myself.emails?.get(0)?.address!!)
} catch (exception: RocketChatException) {
exception.message?.let {
view.showMessage(it)
}.ifNull {
view.showGenericErrorMessage()
}
} finally {
view.hideLoading()
}
}
}
fun updateUserProfile(email: String, name: String, username: String) {
launchUI(strategy) {
view.showLoading()
try {
val user = client.updateProfile(myselfId, email, name, username)
view.showProfileUpdateSuccessfullyMessage()
loadUserProfile()
} catch (exception: RocketChatException) {
exception.message?.let {
view.showMessage(it)
}.ifNull {
view.showGenericErrorMessage()
}
} finally {
view.hideLoading()
}
}
}
}
\ No newline at end of file
package chat.rocket.android.profile.presentation
import chat.rocket.android.core.behaviours.LoadingView
import chat.rocket.android.core.behaviours.MessageView
import chat.rocket.core.model.Myself
interface ProfileView : LoadingView, MessageView {
/**
* Shows the user profile.
*
* @param avatarUrl The user avatar URL.
* @param name The user display name.
* @param username The user username.
* @param email The user email.
*/
fun showProfile(avatarUrl: String, name: String, username: String, email: String)
/**
* Shows a profile update successfully message
*/
fun showProfileUpdateSuccessfullyMessage()
}
\ No newline at end of file
package chat.rocket.android.profile.ui
import DrawableHelper
import android.os.Build
import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v7.view.ActionMode
import android.view.*
import android.widget.Toast
import chat.rocket.android.R
import chat.rocket.android.main.ui.MainActivity
import chat.rocket.android.profile.presentation.ProfilePresenter
import chat.rocket.android.profile.presentation.ProfileView
import chat.rocket.android.util.getObservable
import chat.rocket.android.util.inflate
import chat.rocket.android.util.setVisible
import chat.rocket.android.util.textContent
import dagger.android.support.AndroidSupportInjection
import io.reactivex.rxkotlin.Observables
import kotlinx.android.synthetic.main.app_bar.*
import kotlinx.android.synthetic.main.avatar_profile.*
import kotlinx.android.synthetic.main.fragment_profile.*
import javax.inject.Inject
class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
@Inject lateinit var presenter: ProfilePresenter
private lateinit var currentName: String
private lateinit var currentUsername: String
private lateinit var currentEmail: String
private var actionMode: ActionMode? = null
companion object {
fun newInstance() = ProfileFragment()
}
override fun onCreate(savedInstanceState: Bundle?) {
AndroidSupportInjection.inject(this)
super.onCreate(savedInstanceState)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = container?.inflate(R.layout.fragment_profile)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupToolbar()
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
tintEditTextDrawableStart()
}
presenter.loadUserProfile()
}
override fun showProfile(avatarUrl: String, name: String, username: String, email: String) {
image_avatar.setImageURI(avatarUrl)
text_name.textContent = name
text_username.textContent = username
text_email.textContent = email
currentName = name
currentUsername = username
currentEmail = email
profile_container.setVisible(true)
listenToChanges()
}
override fun showProfileUpdateSuccessfullyMessage() = showMessage(getString(R.string.msg_profile_update_successfully))
override fun showLoading() {
enableUserInput(false)
view_loading.setVisible(true)
}
override fun hideLoading() {
view_loading.setVisible(false)
enableUserInput(true)
}
override fun showMessage(message: String) = Toast.makeText(activity, message, Toast.LENGTH_SHORT).show()
override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error))
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
mode.menuInflater.inflate(R.menu.profile, menu)
mode.title = getString(R.string.title_update_profile)
return true
}
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean = false
override fun onActionItemClicked(mode: ActionMode, menuItem: MenuItem): Boolean {
return when (menuItem.itemId) {
R.id.action_profile -> {
presenter.updateUserProfile(text_email.textContent, text_name.textContent, text_username.textContent)
mode.finish()
true
}
else -> {
false
}
}
}
override fun onDestroyActionMode(mode: ActionMode) {
actionMode = null
}
private fun setupToolbar() {
(activity as MainActivity).toolbar.title = getString(R.string.title_profile)
}
private fun tintEditTextDrawableStart() {
(activity as MainActivity).apply {
val personDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_person_black_24dp, this)
val atDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_at_black_24dp, this)
val emailDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_email_black_24dp, this)
val drawables = arrayOf(personDrawable, atDrawable, emailDrawable)
DrawableHelper.wrapDrawables(drawables)
DrawableHelper.tintDrawables(drawables, this, R.color.colorDrawableTintGrey)
DrawableHelper.compoundDrawables(arrayOf(text_name, text_username, text_email), drawables)
}
}
private fun listenToChanges() {
Observables.combineLatest(text_name.getObservable(), text_username.getObservable(), text_email.getObservable()).subscribe({ t ->
if (t.first.toString() != currentName || t.second.toString() != currentUsername || t.third.toString() != currentEmail) {
startActionMode()
} else {
finishActionMode()
}
})
}
private fun startActionMode() {
if (actionMode == null) {
actionMode = (activity as MainActivity).startSupportActionMode(this)
}
}
private fun finishActionMode() = actionMode?.finish()
private fun enableUserInput(value: Boolean) {
text_name.isEnabled = value
text_username.isEnabled = value
text_email.isEnabled = value
}
}
\ No newline at end of file
......@@ -20,7 +20,7 @@ import android.text.Spanned
import android.util.Log
import chat.rocket.android.BuildConfig
import chat.rocket.android.R
import chat.rocket.android.chatrooms.ui.ChatRoomsActivity
import chat.rocket.android.main.ui.MainActivity
import org.json.JSONObject
import java.io.Serializable
import java.util.*
......@@ -455,7 +455,7 @@ object PushManager {
}
private fun getContentIntent(context: Context, notificationId: Int, pushMessage: PushMessage, grouped: Boolean = false): PendingIntent {
val notificationIntent = Intent(context, ChatRoomsActivity::class.java)
val notificationIntent = Intent(context, MainActivity::class.java)
.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP)
.putExtra(EXTRA_NOT_ID, notificationId)
.putExtra(EXTRA_HOSTNAME, pushMessage.host)
......
package chat.rocket.android.util
import android.app.Activity
import android.content.Context
import android.support.v4.app.Fragment
import android.support.v7.app.AppCompatActivity
import android.view.inputmethod.InputMethodManager
import chat.rocket.android.R
fun AppCompatActivity.addFragment(tag: String, layoutId: Int, newInstance: () -> Fragment) {
......@@ -19,3 +22,8 @@ fun AppCompatActivity.addFragmentBackStack(tag: String, layoutId: Int, newInstan
.addToBackStack(tag)
.commit()
}
fun Activity.hideKeyboard() {
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(currentFocus.windowToken, InputMethodManager.RESULT_UNCHANGED_SHOWN)
}
\ No newline at end of file
......@@ -4,8 +4,13 @@ import android.support.annotation.LayoutRes
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import android.widget.TextView
import ru.noties.markwon.Markwon
import com.jakewharton.rxbinding2.widget.RxTextView
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import java.util.concurrent.TimeUnit
fun String.ifEmpty(value: String): String {
if (isEmpty()) {
......@@ -54,3 +59,10 @@ var TextView.hintContent: String
set(value) {
hint = value
}
fun EditText.getObservable(): Observable<CharSequence> {
return RxTextView.textChanges(this)
.debounce(100, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(AndroidSchedulers.mainThread())
}
\ No newline at end of file
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M20,2H4c-1.1,0 -2,0.9 -2,2v18l4,-4h14c1.1,0 2,-0.9 2,-2V4c0,-1.1 -0.9,-2 -2,-2z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z" />
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M3,18h18v-2L3,16v2zM3,13h18v-2L3,11v2zM3,6v2h18L21,6L3,6z"/>
</vector>
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<color android:color="@color/colorPrimary"/>
</item>
<!--<item>
<bitmap
android:gravity="center"
android:src="@mipmap/ic_launcher"/>
</item>-->
</layer-list>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke
android:width="1dp"
android:color="@color/colorPrimary" />
<solid
android:color="@android:color/transparent" />
<corners
android:radius="2dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:theme="@style/ChatListTheme"
tools:context=".chatrooms.ui.ChatRoomsActivity">
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout 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/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:theme="@style/AppTheme"
tools:context=".main.ui.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include
android:id="@+id/layout_app_bar"
layout="@layout/app_bar" />
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<android.support.design.widget.NavigationView
android:id="@+id/view_navigation"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:menu="@menu/navigation" />
</android.support.v4.widget.DrawerLayout>
\ No newline at end of file
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:elevation="6dp">
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/image_avatar"
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_centerHorizontal="true"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:roundedCornerRadius="2dp" />
</android.support.constraint.ConstraintLayout>
\ No newline at end of file
......@@ -23,7 +23,7 @@
<EditText
android:id="@+id/text_username_or_email"
style="@style/AuthenticationEditText"
style="@style/EditText.Authentication"
android:layout_marginTop="32dp"
android:drawableStart="@drawable/ic_assignment_ind_black_24dp"
android:hint="@string/msg_username_or_email"
......@@ -35,7 +35,7 @@
<EditText
android:id="@+id/text_password"
style="@style/AuthenticationEditText"
style="@style/EditText.Authentication"
android:layout_marginTop="16dp"
android:drawableStart="@drawable/ic_lock_black_24dp"
android:hint="@string/msg_password"
......
......@@ -24,7 +24,7 @@
<EditText
android:id="@+id/text_server_url"
style="@style/AuthenticationEditText"
style="@style/EditText.Authentication"
android:layout_below="@id/text_headline"
android:layout_marginStart="0dp"
android:layout_marginTop="32dp"
......
......@@ -17,10 +17,10 @@
<EditText
android:id="@+id/text_name"
style="@style/AuthenticationEditText"
style="@style/EditText.Authentication"
android:layout_marginTop="32dp"
android:drawableStart="@drawable/ic_person_black_24dp"
android:hint="@string/msg_name_and_surname"
android:hint="@string/msg_name"
android:imeOptions="actionNext"
android:inputType="textCapWords"
app:layout_constraintLeft_toLeftOf="parent"
......@@ -29,7 +29,7 @@
<EditText
android:id="@+id/text_username"
style="@style/AuthenticationEditText"
style="@style/EditText.Authentication"
android:layout_marginTop="16dp"
android:drawableStart="@drawable/ic_at_black_24dp"
android:hint="@string/msg_username"
......@@ -41,7 +41,7 @@
<EditText
android:id="@+id/text_password"
style="@style/AuthenticationEditText"
style="@style/EditText.Authentication"
android:layout_marginTop="16dp"
android:drawableStart="@drawable/ic_lock_black_24dp"
android:hint="@string/msg_password"
......@@ -53,7 +53,7 @@
<EditText
android:id="@+id/text_email"
style="@style/AuthenticationEditText"
style="@style/EditText.Authentication"
android:layout_marginTop="16dp"
android:drawableStart="@drawable/ic_email_black_24dp"
android:hint="@string/msg_email"
......
......@@ -14,7 +14,7 @@
<EditText
android:id="@+id/text_two_factor_auth"
style="@style/AuthenticationEditText"
style="@style/EditText.Authentication"
android:layout_below="@id/text_headline"
android:layout_marginTop="32dp"
android:drawableStart="@drawable/ic_vpn_key_black_24dp"
......
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
<RelativeLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".chatrooms.ui.ChatRoomsFragment">
<include
android:id="@+id/layout_app_bar"
layout="@layout/app_bar"
android:background="@color/black" />
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:gravity="center_horizontal"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
android:layout_height="match_parent" />
<com.wang.avi.AVLoadingIndicatorView
android:id="@+id/view_loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:visibility="gone"
app:indicatorColor="@color/black"
app:indicatorName="BallPulseIndicator"
app:indicatorName="BallPulseIndicator" />
<TextView
android:id="@+id/text_no_data_to_display"
style="@style/TextAppearance.AppCompat.Subhead"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="@string/msg_no_data_to_display"
android:visibility="gone"
tools:visibility="visible" />
</android.support.design.widget.CoordinatorLayout>
\ No newline at end of file
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/relative_layout"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusableInTouchMode="true"
tools:context=".profile.ui.ProfileFragment">
<LinearLayout
android:id="@+id/profile_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone">
<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/EditText.Profile"
android:layout_marginTop="32dp"
android:drawableStart="@drawable/ic_person_black_24dp"
android:hint="@string/msg_name"
android:inputType="textCapWords" />
<EditText
android:id="@+id/text_username"
style="@style/EditText.Profile"
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/EditText.Profile"
android:layout_marginTop="16dp"
android:drawableStart="@drawable/ic_email_black_24dp"
android:hint="@string/msg_email"
android:inputType="textEmailAddress" />
</LinearLayout>
<com.wang.avi.AVLoadingIndicatorView
android:id="@+id/view_loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
app:indicatorColor="@color/black"
app:indicatorName="BallPulseIndicator" />
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_search"
android:icon="@drawable/ic_search_white_24px"
......@@ -8,7 +9,9 @@
app:actionViewClass="android.support.v7.widget.SearchView"
app:showAsAction="ifRoom|collapseActionView" />
<item android:id="@+id/action_logout"
android:title="@string/action_logout"
app:showAsAction="never"/>
app:showAsAction="never" />
</menu>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:checkableBehavior="single">
<item
android:id="@+id/action_chat_rooms"
android:checked="true"
android:icon="@drawable/ic_chat_bubble_black_24dp"
android:title="@string/title_chats" />
<item
android:id="@+id/action_profile"
android:icon="@drawable/ic_person_black_24dp"
android:title="@string/title_profile" />
</group>
</menu>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/action_profile"
android:icon="@drawable/ic_check_white_24dp"
android:title="@string/action_update" />
</menu>
\ No newline at end of file
......@@ -5,6 +5,9 @@
<string name="title_log_in">Entrar</string>
<string name="title_sign_up">Inscreva-se</string>
<string name="title_legal_terms">Termos Legais</string>
<string name="title_chats">Chats</string>
<string name="title_profile">Perfil</string>
<string name="title_update_profile">Editar perfil</string>
<!-- Actions -->
<string name="action_connect">Conectar</string>
......@@ -12,16 +15,19 @@
<string name="action_terms_of_service">Termos de Serviço</string>
<string name="action_privacy_policy">Política de Privacidade</string>
<string name="action_search">Pesquisar</string>
<string name="action_update">Atualizar</string>
<string name="action_logout">Sair</string>
<!-- Regular information messages -->
<string name="msg_no_internet_connection">Sem conexão à internet</string>
<string name="msg_invalid_server_url">URL de servidor inválida</string>
<string name="msg_generic_error">Desculpe, ocorreu um erro, tente novamente</string>
<string name="msg_no_data_to_display">Nenhum dado para exibir</string>
<string name="msg_profile_update_successfully">Perfil atualizado com sucesso</string>
<string name="msg_username">nome de usuário</string>
<string name="msg_username_or_email">nome de usuário ou email</string>
<string name="msg_password">senha</string>
<string name="msg_name_and_surname">nome e sobrenome</string>
<string name="msg_name">nome</string>
<string name="msg_email">email</string>
<string name="msg_or_continue_using_social_accounts">Ou continue através de contas sociais</string>
<string name="msg_new_user">Novo usuário? %1$s</string>
......
<resources>
<string name="app_name" translatable="false">Rocket Chat</string>
<string name="app_name" translatable="false">Rocket.Chat</string>
<!-- Titles -->
<string name="title_sign_in_your_server">Sign in your server</string>
<string name="title_log_in">Log in</string>
<string name="title_sign_up">Sign up</string>
<string name="title_legal_terms">Legal Terms</string>
<string name="title_chats">Chats</string>
<string name="title_profile">Profile</string>
<string name="title_update_profile">Update profile</string>
<!-- Actions -->
<string name="action_connect">Connect</string>
......@@ -13,16 +16,19 @@
<string name="action_terms_of_service">Terms of Service</string>
<string name="action_privacy_policy">Privacy Policy</string>
<string name="action_search">Search</string>
<string name="action_update">Update</string>
<string name="action_logout">Log Out</string>
<!-- Regular information messages -->
<string name="msg_no_internet_connection">No internet connection</string>
<string name="msg_invalid_server_url">Invalid server URL</string>
<string name="msg_generic_error">Sorry, an error has occurred, please try again</string>
<string name="msg_no_data_to_display">No data to display</string>
<string name="msg_profile_update_successfully">Profile update successfully</string>
<string name="msg_username">username</string>
<string name="msg_username_or_email">username or email</string>
<string name="msg_password">password</string>
<string name="msg_name_and_surname">name and surname</string>
<string name="msg_name">name</string>
<string name="msg_email">email</string>
<string name="msg_or_continue_using_social_accounts">Or continue using social accounts</string>
<string name="msg_new_user">New user? %1$s</string>
......
......@@ -6,11 +6,9 @@
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="android:statusBarColor">@color/colorPrimaryDark</item>
</style>
<style name="AppTheme.SplashScreen" parent="AppTheme" >
<item name="android:windowBackground">@drawable/splash_screen</item>
<item name="android:statusBarColor">@color/colorPrimaryDark</item>
<item name="windowActionModeOverlay">true</item>
</style>
<style name="AuthenticationTheme" parent="Theme.AppCompat.NoActionBar">
......@@ -18,11 +16,6 @@
<item name="android:windowBackground">@color/colorPrimary</item>
</style>
<style name="ChatListTheme" parent="AppTheme">
<item name="android:windowTranslucentStatus">true</item>
<item name="colorControlHighlight">@color/colorPrimary</item> <!-- We need this item because of this FloatingSearchView's issue: https://github.com/arimorty/floatingsearchview/issues/222 -->
</style>
<!-- Widget styles. -->
<style name="HeadlineTextView" parent="TextAppearance.AppCompat.Headline">
<item name="android:layout_width">wrap_content</item>
......@@ -32,7 +25,7 @@
<item name="android:layout_marginEnd">@dimen/screen_edge_left_and_right_margins</item>
</style>
<style name="AuthenticationEditText" parent="Widget.AppCompat.EditText">
<style name="EditText.Authentication" parent="Widget.AppCompat.EditText">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">50dp</item>
<item name="android:layout_marginStart">@dimen/screen_edge_left_and_right_margins</item>
......@@ -43,7 +36,11 @@
<item name="android:drawablePadding">@dimen/edit_text_drawable_padding</item>
<item name="android:drawableTint" tools:ignore="NewApi">@color/colorDrawableTintGrey</item>
<item name="android:fontFamily">sans-serif</item>
<item name="android:background">@drawable/style_edit_text</item>
<item name="android:background">@drawable/style_edit_text_authentication</item>
</style>
<style name="EditText.Profile" parent="EditText.Authentication">
<item name="android:background">@drawable/style_edit_text_profile</item>
</style>
<style name="AuthenticationLabel" parent="TextAppearance.AppCompat.Medium">
......@@ -54,7 +51,7 @@
<item name="android:maxLines">1</item>
<item name="android:drawablePadding">@dimen/edit_text_drawable_padding</item>
<item name="android:fontFamily">sans-serif</item>
<item name="android:background">@drawable/style_edit_text</item>
<item name="android:background">@drawable/style_edit_text_authentication</item>
</style>
<style name="AuthenticationButton" parent="Widget.AppCompat.Button">
......
......@@ -15,20 +15,21 @@ ext {
exoPlayer : '2.6.0',
playServices : '11.8.0',
room : '1.0.0',
rxjava : '2.1.4',
rxandroid : '2.0.1',
rxKotlin : '2.2.0',
rxAndroid : '2.0.1',
moshi : '1.6.0-SNAPSHOT',
okhttp : '3.9.0',
timber : '4.5.1',
threeTenABP : '1.0.5',
rxBinding : '2.0.0',
fresco : '1.7.1',
frescoImageViewer : '0.5.0',
kotshi : '0.3.0',
floatingSearchView : '2.1.1',
frescoImageViewer : '0.5.0',
androidSvg : '1.2.1',
aVLoadingIndicatorView : '2.1.3',
textDrawable : '1.0.2',
markwon : '1.0.3',
textDrawable : '1.0.2', // Remove this library after https://github.com/RocketChat/Rocket.Chat/pull/9492 is merged
moshiLazyAdapters : '2.1', // Even declared on the SDK we need to add this library here because java.lang.NoClassDefFoundError: Failed resolution of: Lcom/serjltt/moshi/adapters/FallbackEnum;
// For testing
junit : '4.12',
......@@ -60,8 +61,8 @@ ext {
roomProcessor : "android.arch.persistence.room:compiler:${versions.room}",
roomRxjava : "android.arch.persistence.room:rxjava2:${versions.room}",
rxjava : "io.reactivex.rxjava2:rxjava:${versions.rxjava}",
rxandroid : "io.reactivex.rxjava2:rxandroid:${versions.rxandroid}",
rxKotlin : "io.reactivex.rxjava2:rxkotlin:${versions.rxKotlin}",
rxAndroid : "io.reactivex.rxjava2:rxandroid:${versions.rxAndroid}",
moshi : "com.squareup.moshi:moshi:${versions.moshi}",
moshiKotlin : "com.squareup.moshi:moshi-kotlin:${versions.moshi}",
......@@ -70,6 +71,7 @@ ext {
timber : "com.jakewharton.timber:timber:${versions.timber}",
threeTenABP : "com.jakewharton.threetenabp:threetenabp:${versions.threeTenABP}",
rxBinding : "com.jakewharton.rxbinding2:rxbinding-kotlin:${versions.rxBinding}",
fresco : "com.facebook.fresco:fresco:${versions.fresco}",
frescoOkHttp : "com.facebook.fresco:imagepipeline-okhttp3:${versions.fresco}",
......@@ -77,12 +79,10 @@ ext {
frescoWebP : "com.facebook.fresco:webpsupport:${versions.fresco}",
frescoAnimatedWebP : "com.facebook.fresco:animated-webp:${versions.fresco}",
frescoImageViewer : "com.github.stfalcon:frescoimageviewer:${versions.frescoImageViewer}",
kotshiApi : "se.ansman.kotshi:api:${versions.kotshi}",
kotshiCompiler : "se.ansman.kotshi:compiler:${versions.kotshi}",
floatingSearchView : "com.github.arimorty:floatingsearchview:${versions.floatingSearchView}",
frescoImageViewer : "com.github.stfalcon:frescoimageviewer:${versions.frescoImageViewer}",
androidSvg : "com.caverock:androidsvg:${versions.androidSvg}",
......@@ -93,6 +93,8 @@ ext {
markwon : "ru.noties:markwon:${versions.markwon}",
markwonImageLoader : "ru.noties:markwon-image-loader:${versions.markwon}",
moshiLazyAdapters : "com.serjltt.moshi:moshi-lazy-adapters:${versions.moshiLazyAdapters}",
// For testing
junit : "junit:junit:$versions.junit",
expressoCore : "com.android.support.test.espresso:espresso-core:${versions.expresso}",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment