Commit d0cc012d authored by Filipe de Lima Brito's avatar Filipe de Lima Brito

Add create channel feature.

parent 1a137f9a
...@@ -73,12 +73,9 @@ ...@@ -73,12 +73,9 @@
android:name=".chatroom.ui.ChatRoomActivity" android:name=".chatroom.ui.ChatRoomActivity"
android:theme="@style/AppTheme" android:theme="@style/AppTheme"
android:windowSoftInputMode="adjustResize|stateAlwaysHidden" /> android:windowSoftInputMode="adjustResize|stateAlwaysHidden" />
<activity
android:name=".createChannel.ui.CreateNewChannelActivity"
android:theme="@style/AppTheme"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity android:name=".createChannel.addMembers.ui.AddMembersActivity" <activity
android:name=".createchannel.addmembers.ui.AddMembersActivity"
android:theme="@style/AppTheme" android:theme="@style/AppTheme"
android:windowSoftInputMode="stateAlwaysHidden" /> android:windowSoftInputMode="stateAlwaysHidden" />
......
...@@ -613,8 +613,14 @@ class ChatRoomPresenter @Inject constructor( ...@@ -613,8 +613,14 @@ class ChatRoomPresenter @Inject constructor(
val name = it.name ?: "" val name = it.name ?: ""
val searchList = mutableListOf(username, name) val searchList = mutableListOf(username, name)
it.emails?.forEach { email -> searchList.add(email.address) } it.emails?.forEach { email -> searchList.add(email.address) }
PeopleSuggestionViewModel(currentServer.avatarUrl(username), PeopleSuggestionViewModel(
username, username, name, it.status, false, searchList) currentServer.avatarUrl(username),
username,
username,
name,
it.status,
false,
searchList)
}.filterNot { filterSelfOut && self != null && self == it.text }) }.filterNot { filterSelfOut && self != null && self == it.text })
} }
ROOMS -> { ROOMS -> {
......
package chat.rocket.android.chatrooms.ui package chat.rocket.android.chatrooms.ui
import android.content.Intent
import android.app.AlertDialog import android.app.AlertDialog
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
...@@ -22,7 +21,6 @@ import androidx.core.view.isVisible ...@@ -22,7 +21,6 @@ import androidx.core.view.isVisible
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.chatrooms.presentation.ChatRoomsPresenter import chat.rocket.android.chatrooms.presentation.ChatRoomsPresenter
import chat.rocket.android.chatrooms.presentation.ChatRoomsView import chat.rocket.android.chatrooms.presentation.ChatRoomsView
import chat.rocket.android.createChannel.ui.CreateNewChannelActivity
import chat.rocket.android.helper.ChatRoomsSortOrder import chat.rocket.android.helper.ChatRoomsSortOrder
import chat.rocket.android.helper.Constants import chat.rocket.android.helper.Constants
import chat.rocket.android.helper.SharedPreferenceHelper import chat.rocket.android.helper.SharedPreferenceHelper
...@@ -105,7 +103,6 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView { ...@@ -105,7 +103,6 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
setupToolbar() setupToolbar()
setupRecyclerView() setupRecyclerView()
setupFab()
presenter.loadChatRooms() presenter.loadChatRooms()
} }
...@@ -193,7 +190,7 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView { ...@@ -193,7 +190,7 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
/*val diff = async(CommonPool) { /*val diff = async(CommonPool) {
DiffUtil.calculateDiff(RoomsDiffCallback(adapter.baseAdapter.dataSet, newDataSet)) DiffUtil.calculateDiff(RoomsDiffCallback(adapter.baseAdapter.dataSet, newDataSet))
}.await()*/ }.await()*/
text_no_search.isVisible = newDataSet.isEmpty() text_no_result_found.isVisible = newDataSet.isEmpty()
if (isActive) { if (isActive) {
adapter.baseAdapter.updateRooms(newDataSet) adapter.baseAdapter.updateRooms(newDataSet)
// TODO - fix crash to re-enable diff.dispatchUpdatesTo(adapter) // TODO - fix crash to re-enable diff.dispatchUpdatesTo(adapter)
...@@ -314,13 +311,6 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView { ...@@ -314,13 +311,6 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
sectionedAdapter?.setSections(sections.toArray(dummy)) sectionedAdapter?.setSections(sections.toArray(dummy))
} }
private fun setupFab() {
create_new_channel_fab.setOnClickListener {
val intent = Intent(activity, CreateNewChannelActivity::class.java)
startActivity(intent)
}
}
private fun queryChatRoomsByName(name: String?): Boolean { private fun queryChatRoomsByName(name: String?): Boolean {
presenter.chatRoomsByName(name ?: "") presenter.chatRoomsByName(name ?: "")
return true return true
......
package chat.rocket.android.createChannel.di
import android.arch.lifecycle.LifecycleOwner
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.createChannel.presentation.CreateNewChannelView
import chat.rocket.android.createChannel.ui.CreateNewChannelActivity
import chat.rocket.android.dagger.scope.PerActivity
import dagger.Module
import dagger.Provides
import kotlinx.coroutines.experimental.Job
@Module
class CreateNewChannelModule {
@Provides
fun provideLifecycleOwner(activity: CreateNewChannelActivity): LifecycleOwner {
return activity
}
@Provides
@PerActivity
fun createChannelView(activity: CreateNewChannelActivity): CreateNewChannelView {
return activity
}
@Provides
fun provideCancelStrategy(owner: LifecycleOwner, jobs: Job): CancelStrategy {
return CancelStrategy(owner, jobs)
}
}
\ No newline at end of file
package chat.rocket.android.createChannel.di
import chat.rocket.android.createChannel.ui.CreateNewChannelActivity
import dagger.Module
import dagger.android.ContributesAndroidInjector
@Module
abstract class CreateNewChannelProvider {
@ContributesAndroidInjector(modules = [CreateNewChannelModule::class])
abstract fun provideNewChannelActivity(): CreateNewChannelActivity
}
\ No newline at end of file
package chat.rocket.android.createChannel.presentation
import chat.rocket.android.core.behaviours.LoadingView
interface CreateNewChannelView : LoadingView {
/**
* Show a message that a channel was successfully created
*/
fun showChannelCreatedSuccessfullyMessage()
/**
* Show message and clear text in edit text
*
* @param resId Resource id of the message to be shown
*/
fun showMessageAndClearText(resId: Int)
/**
* Show message and clear text in edit text
*
* @param message Toast message to be shown
*/
fun showMessageAndClearText(message: String)
/**
* Show error message
*/
fun showErrorMessage()
}
\ No newline at end of file
package chat.rocket.android.createChannel.ui
import android.app.Activity
import android.content.Intent
import android.graphics.drawable.GradientDrawable
import android.os.Bundle
import android.support.design.chip.Chip
import android.support.v7.app.AppCompatActivity
import android.view.MenuItem
import androidx.core.view.isVisible
import chat.rocket.android.R
import chat.rocket.android.createChannel.addMembers.ui.AddMembersActivity
import chat.rocket.android.createChannel.presentation.CreateNewChannelPresenter
import chat.rocket.android.createChannel.presentation.CreateNewChannelView
import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.textContent
import chat.rocket.common.model.RoomType
import dagger.android.AndroidInjection
import kotlinx.android.synthetic.main.activity_create_new_channel.*
import kotlinx.android.synthetic.main.layout_toolbar.*
import javax.inject.Inject
internal const val ADD_MEMBERS_ACTIVITY_REQUEST_CODE = 1
class CreateNewChannelActivity : AppCompatActivity(), CreateNewChannelView {
@Inject
lateinit var presenter: CreateNewChannelPresenter
private var channelType: RoomType = RoomType.CHANNEL
private var listOfUsers: ArrayList<String> = ArrayList()
override fun onCreate(savedInstanceState: Bundle?) {
AndroidInjection.inject(this)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_create_new_channel)
setUpToolBar()
setUpOnClickListeners()
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when (item?.itemId) {
android.R.id.home -> {
finish()
return true
}
}
return super.onOptionsItemSelected(item)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK) {
if (requestCode == ADD_MEMBERS_ACTIVITY_REQUEST_CODE && data != null) {
listOfUsers = data.getStringArrayListExtra("members")
selected_members_chips.removeAllViews()
refreshMembersChips()
}
}
}
override fun showLoading() {
view_loading.isVisible = true
layout_container.alpha = 0.5f
layout_container.isEnabled = false
}
override fun hideLoading() {
view_loading.isVisible = false
layout_container.alpha = 1.0f
layout_container.isEnabled = true
}
override fun showChannelCreatedSuccessfullyMessage() {
showToast(getString(R.string.msg_channel_created_successfully))
finish()
}
override fun showMessageAndClearText(resId: Int) {
channel_name_edit_text.setText("")
showToast(getString(resId))
}
override fun showMessageAndClearText(message: String) {
channel_name_edit_text.setText("")
showToast(message)
}
override fun showErrorMessage() {
showMessageAndClearText(getString(R.string.msg_generic_error))
}
private fun refreshMembersChips() {
for (element in listOfUsers) {
val memberChip = Chip(this)
memberChip.chipText = element
memberChip.isCloseIconEnabled = false
memberChip.isLongClickable = false
memberChip.setChipBackgroundColorResource(R.color.icon_grey)
selected_members_chips.addView(memberChip)
}
}
private fun setUpToolBar() {
setSupportActionBar(toolbar)
toolbar_title.text = getString(R.string.title_create_new_channel)
toolbar_action_text.text = getString(R.string.action_create_new_channel)
toolbar_action_text.alpha = 1.0f
toolbar_action_text.isEnabled = true
supportActionBar?.setDisplayHomeAsUpEnabled(true)
}
private fun setUpOnClickListeners() {
public_channel.setOnClickListener {
channelType = RoomType.CHANNEL
channel_type.text = getString(R.string.public_channel_type)
channel_description.text = getString(R.string.public_channel_description)
placeholder.setImageDrawable(getDrawable(R.drawable.ic_hashtag_black_12dp))
(getDrawable(R.drawable.button_border) as GradientDrawable).setColor(
resources.getColor(
R.color.default_background
)
)
(getDrawable(R.drawable.button_solid) as GradientDrawable).setColor(resources.getColor(R.color.colorRed))
private_channel.background = getDrawable(R.drawable.button_border)
public_channel.background = getDrawable(R.drawable.button_solid)
private_channel.setTextColor(resources.getColor(R.color.colorRed))
public_channel.setTextColor(resources.getColor(R.color.default_background))
}
private_channel.setOnClickListener {
channelType = RoomType.PRIVATE_GROUP
channel_type.text = getString(R.string.private_channel_type)
channel_description.text = getString(R.string.private_channel_type_description)
placeholder.setImageDrawable(getDrawable(R.drawable.ic_lock_black_12_dp))
(getDrawable(R.drawable.button_border) as GradientDrawable).setColor(
resources.getColor(R.color.colorRed)
)
(getDrawable(R.drawable.button_solid) as GradientDrawable).setColor(
resources.getColor(R.color.default_background)
)
(getDrawable(R.drawable.button_solid) as GradientDrawable).setStroke(
1,
resources.getColor(R.color.colorRed)
)
private_channel.background = getDrawable(R.drawable.button_border)
public_channel.background = getDrawable(R.drawable.button_solid)
private_channel.setTextColor(resources.getColor(R.color.default_background))
public_channel.setTextColor(resources.getColor(R.color.colorRed))
}
toolbar_action_text.setOnClickListener {
if (channel_name_edit_text.textContent.isNotEmpty()) {
presenter.createNewChannel(
channelType,
channel_name_edit_text.text.toString(),
listOfUsers,
false
)
} else{
showToast(getString(R.string.msg_channel_name_required))
}
}
add_members_view.setOnClickListener {
val intent = Intent(this, AddMembersActivity::class.java)
intent.putExtra("chips", listOfUsers)
startActivityForResult(intent, ADD_MEMBERS_ACTIVITY_REQUEST_CODE)
}
}
}
\ No newline at end of file
package chat.rocket.android.createChannel.addMembers.di package chat.rocket.android.createchannel.addmembers.di
import android.arch.lifecycle.LifecycleOwner import android.arch.lifecycle.LifecycleOwner
import chat.rocket.android.core.lifecycle.CancelStrategy import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.createChannel.addMembers.presentation.AddMembersView import chat.rocket.android.createchannel.addmembers.presentation.AddMembersView
import chat.rocket.android.createChannel.addMembers.ui.AddMembersActivity import chat.rocket.android.createchannel.addmembers.ui.AddMembersActivity
import chat.rocket.android.dagger.scope.PerActivity import chat.rocket.android.dagger.scope.PerActivity
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
...@@ -11,6 +11,7 @@ import kotlinx.coroutines.experimental.Job ...@@ -11,6 +11,7 @@ import kotlinx.coroutines.experimental.Job
@Module @Module
class AddMembersModule { class AddMembersModule {
@Provides @Provides
fun provideLifecycleOwner(activity: AddMembersActivity): LifecycleOwner { fun provideLifecycleOwner(activity: AddMembersActivity): LifecycleOwner {
return activity return activity
......
package chat.rocket.android.createChannel.addMembers.di package chat.rocket.android.createchannel.addmembers.di
import chat.rocket.android.createChannel.addMembers.ui.AddMembersActivity import chat.rocket.android.createchannel.addmembers.ui.AddMembersActivity
import dagger.Module import dagger.Module
import dagger.android.ContributesAndroidInjector import dagger.android.ContributesAndroidInjector
......
package chat.rocket.android.createChannel.addMembers.presentation package chat.rocket.android.createchannel.addmembers.presentation
import chat.rocket.android.core.lifecycle.CancelStrategy import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.members.viewmodel.MemberViewModelMapper import chat.rocket.android.members.viewmodel.MemberViewModelMapper
import chat.rocket.android.server.domain.GetCurrentServerInteractor import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.extensions.launchUI import chat.rocket.android.util.extensions.launchUI
import chat.rocket.android.util.retryIO
import chat.rocket.common.RocketChatException import chat.rocket.common.RocketChatException
import chat.rocket.common.util.ifNull import chat.rocket.common.util.ifNull
import chat.rocket.core.internal.rest.queryUsers import chat.rocket.core.internal.rest.searchUser
import javax.inject.Inject import javax.inject.Inject
class AddMembersPresenter @Inject constructor( class AddMembersPresenter @Inject constructor(
private val view: AddMembersView, private val view: AddMembersView,
private val strategy: CancelStrategy, private val strategy: CancelStrategy,
private val serverInteractor: GetCurrentServerInteractor,
private val mapper: MemberViewModelMapper, private val mapper: MemberViewModelMapper,
factory: RocketChatClientFactory val serverInteractor: GetCurrentServerInteractor,
val factory: RocketChatClientFactory
) { ) {
private val client = factory.create(serverInteractor.get()!!) private val client = factory.create(serverInteractor.get()!!)
private var offset: Long = 0
fun queryUsersFromRegex(queryParam: String, offset: Long = 0) { fun searchUser(query: String) {
view.showLoading()
launchUI(strategy) { launchUI(strategy) {
try { try {
val allMembers = retryIO("queryUsers($queryParam)") { view.showLoading()
client.queryUsers(queryParam, 60, offset) val users = client.searchUser(query, offset)
} val memberViewModelMapper = mapper.mapToViewModelList(users.result)
val memberViewModelMapper = mapper.mapToViewModelList(allMembers.result) view.showUsers(memberViewModelMapper, users.total)
view.showMembers(memberViewModelMapper, allMembers.total) offset += 1 * 30L
} catch (ex: RocketChatException) { } catch (ex: RocketChatException) {
ex.message?.let { ex.message?.let {
view.showMessage(it) view.showMessage(it)
......
package chat.rocket.android.createChannel.addMembers.presentation package chat.rocket.android.createchannel.addmembers.presentation
import chat.rocket.android.core.behaviours.LoadingView import chat.rocket.android.core.behaviours.LoadingView
import chat.rocket.android.core.behaviours.MessageView import chat.rocket.android.core.behaviours.MessageView
import chat.rocket.android.members.viewmodel.MemberViewModel import chat.rocket.android.members.viewmodel.MemberViewModel
interface AddMembersView : LoadingView, MessageView { interface AddMembersView : LoadingView, MessageView {
/** /**
* Show members on the basis of query * Show the users of the server on the basis of query.
* *
* @param dataSet The list of members * @param dataSet The list of users to show.
* @param total The number of members returned * @param total The number of users returned.
*/ */
fun showMembers(dataSet: List<MemberViewModel>, total: Long) fun showUsers(dataSet: List<MemberViewModel>, total: Long)
} }
\ No newline at end of file
package chat.rocket.android.createChannel.addMembers.ui package chat.rocket.android.createchannel.addmembers.ui
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
...@@ -8,67 +8,61 @@ import android.support.v7.app.AppCompatActivity ...@@ -8,67 +8,61 @@ import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.LinearLayoutManager import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView import android.support.v7.widget.RecyclerView
import android.view.MenuItem import android.view.MenuItem
import android.widget.EditText
import androidx.core.view.isVisible import androidx.core.view.isVisible
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.createChannel.addMembers.presentation.AddMembersPresenter import chat.rocket.android.createchannel.addmembers.presentation.AddMembersPresenter
import chat.rocket.android.createChannel.addMembers.presentation.AddMembersView import chat.rocket.android.createchannel.addmembers.presentation.AddMembersView
import chat.rocket.android.helper.EndlessRecyclerViewScrollListener import chat.rocket.android.helper.EndlessRecyclerViewScrollListener
import chat.rocket.android.members.adapter.MembersAdapter import chat.rocket.android.members.adapter.MembersAdapter
import chat.rocket.android.members.viewmodel.MemberViewModel import chat.rocket.android.members.viewmodel.MemberViewModel
import chat.rocket.android.util.extensions.asObservable
import chat.rocket.android.util.extensions.showToast import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.textContent import chat.rocket.android.util.extensions.textContent
import chat.rocket.android.widget.DividerItemDecoration import chat.rocket.android.widget.DividerItemDecoration
import com.jakewharton.rxbinding2.widget.RxTextView
import dagger.android.AndroidInjection import dagger.android.AndroidInjection
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable import io.reactivex.disposables.Disposable
import io.reactivex.subjects.BehaviorSubject
import kotlinx.android.synthetic.main.activity_add_members.* import kotlinx.android.synthetic.main.activity_add_members.*
import kotlinx.android.synthetic.main.layout_toolbar.* import kotlinx.android.synthetic.main.layout_toolbar.*
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject
class AddMembersActivity : AppCompatActivity(), AddMembersView { class AddMembersActivity : AppCompatActivity(), AddMembersView {
@Inject @Inject
lateinit var presenter: AddMembersPresenter lateinit var presenter: AddMembersPresenter
private lateinit var queryParam: String private var query: String = ""
private var membersToAdd: ArrayList<String> = ArrayList() private var membersToAdd = arrayListOf<String>()
private val adapter: MembersAdapter = MembersAdapter { memberViewModel -> private val linearLayoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
if (!membersToAdd.contains(memberViewModel.username)) { private lateinit var editTextDisposable: Disposable
addNewChip(memberViewModel) private val adapter: MembersAdapter = MembersAdapter {
it.username?.let {
if (!membersToAdd.contains(it)) {
buildChip(it)
membersToAdd.add(it)
updateToolBar() updateToolBar()
search_view.setText("")
} else { } else {
showMessage(getString(R.string.msg_member_already_added)) showMessage(getString(R.string.msg_member_already_added))
} }
} }
private lateinit var observableForSearchView: Disposable }
private lateinit var observableForToolbarAction: Disposable
private val linearLayoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
AndroidInjection.inject(this) AndroidInjection.inject(this)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_add_members) setContentView(R.layout.activity_add_members)
setUpToolBar() setupToolBar()
setUpRecyclerView() setupRecyclerView()
setOnClickListeners() setupInitialChips()
setInitialChips() setListeners()
} }
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
setUpObservableForSearchView() subscribeEditText()
} }
override fun onStop() { override fun onStop() {
super.onStop() super.onStop()
//dispose off the rx disposables unsubscribeEditText()
observableForToolbarAction.dispose()
observableForSearchView.dispose()
} }
override fun onOptionsItemSelected(item: MenuItem?): Boolean { override fun onOptionsItemSelected(item: MenuItem?): Boolean {
...@@ -82,27 +76,6 @@ class AddMembersActivity : AppCompatActivity(), AddMembersView { ...@@ -82,27 +76,6 @@ class AddMembersActivity : AppCompatActivity(), AddMembersView {
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)
} }
override fun showMembers(dataSet: List<MemberViewModel>, total: Long) {
if (adapter.itemCount == 0) {
adapter.prependData(dataSet)
if (dataSet.size >= 59) {
search_results.addOnScrollListener(object :
EndlessRecyclerViewScrollListener(linearLayoutManager) {
override fun onLoadMore(
page: Int,
totalItemsCount: Int,
recyclerView: RecyclerView?
) {
presenter.queryUsersFromRegex(queryParam, page * 60L)
}
})
}
} else {
adapter.appendData(dataSet)
}
}
override fun showLoading() { override fun showLoading() {
view_loading.isVisible = true view_loading.isVisible = true
} }
...@@ -123,74 +96,50 @@ class AddMembersActivity : AppCompatActivity(), AddMembersView { ...@@ -123,74 +96,50 @@ class AddMembersActivity : AppCompatActivity(), AddMembersView {
showMessage(getString(R.string.msg_generic_error)) showMessage(getString(R.string.msg_generic_error))
} }
private fun setInitialChips() { override fun showUsers(dataSet: List<MemberViewModel>, total: Long) {
membersToAdd = intent.getStringArrayListExtra("chips") if (adapter.itemCount == 0) {
for (element in membersToAdd) { adapter.prependData(dataSet)
buildNewChip(element) if (dataSet.size >= 30) {
} recycler_view.addOnScrollListener(object :
updateToolBar() EndlessRecyclerViewScrollListener(linearLayoutManager) {
} override fun onLoadMore(
page: Int,
private fun setUpObservableForSearchView() { totalItemsCount: Int,
observableForSearchView = observableFromSearchView(search_view) recyclerView: RecyclerView?
.debounce(300, TimeUnit.MILLISECONDS) ) {
.filter { item -> item.isNotEmpty() } presenter.searchUser(query)
.observeOn(AndroidSchedulers.mainThread())
.subscribe { query ->
queryParam = query
run {
adapter.reAllocateArrayList()
presenter.queryUsersFromRegex(query)
}
}
}
private fun addNewChip(memberViewModel: MemberViewModel) {
buildNewChip(memberViewModel.displayName)
membersToAdd.add(memberViewModel.displayName)
}
private fun buildNewChip(chipText: String) {
val memberChip = Chip(this)
memberChip.chipText = chipText
memberChip.isCloseIconEnabled = true
memberChip.setChipBackgroundColorResource(R.color.icon_grey)
memberChip.setOnCloseIconClickListener { view ->
members_chips.removeView(view)
membersToAdd.remove((view as Chip).chipText.toString())
updateToolBar()
} }
members_chips.addView(memberChip) })
} }
private fun updateToolBar() {
toolbar_action_text.isEnabled = membersToAdd.isNotEmpty()
if (membersToAdd.size == 0) {
toolbar_action_text.alpha = 0.8f
} else { } else {
toolbar_action_text.alpha = 1.0f adapter.appendData(dataSet)
} }
toolbar_title.textContent =
getString(R.string.title_add_members, membersToAdd.size.toString())
} }
private fun setUpToolBar() { private fun setupToolBar() {
setSupportActionBar(toolbar) setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
toolbar_title.text = getString(R.string.title_add_members, "0") toolbar_title.text = getString(R.string.title_add_members, "0")
toolbar_action_text.text = getString(R.string.action_select_members) toolbar_action_text.text = getString(R.string.action_select_members)
supportActionBar?.setDisplayHomeAsUpEnabled(true) }
private fun setupRecyclerView() {
recycler_view.layoutManager = linearLayoutManager
recycler_view.adapter = adapter
recycler_view.addItemDecoration(DividerItemDecoration(this))
} }
private fun setUpRecyclerView() { private fun setupInitialChips() {
search_results.layoutManager = linearLayoutManager membersToAdd = intent.getStringArrayListExtra("chips")
search_results.adapter = adapter for (element in membersToAdd) {
search_results.addItemDecoration(DividerItemDecoration(this)) buildChip(element)
}
updateToolBar()
} }
private fun setOnClickListeners() { private fun setListeners() {
toolbar_action_text.setOnClickListener { view -> toolbar_action_text.setOnClickListener {
if (view.isEnabled) { if (it.isEnabled) {
val intent = Intent() val intent = Intent()
intent.putExtra("members", membersToAdd) intent.putExtra("members", membersToAdd)
setResult(Activity.RESULT_OK, intent) setResult(Activity.RESULT_OK, intent)
...@@ -199,13 +148,45 @@ class AddMembersActivity : AppCompatActivity(), AddMembersView { ...@@ -199,13 +148,45 @@ class AddMembersActivity : AppCompatActivity(), AddMembersView {
} }
} }
private fun observableFromSearchView(searchView: EditText): Observable<String> { private fun subscribeEditText() {
val observableSubject: BehaviorSubject<String> = BehaviorSubject.create() editTextDisposable = text_search_member.asObservable()
observableForToolbarAction = RxTextView.textChanges(searchView).subscribe { text -> .debounce(500, TimeUnit.MILLISECONDS)
if (text.isNotBlank()) { .filter { t -> t.isNotEmpty() && t != query }
observableSubject.onNext(text.toString()) .subscribe {
adapter.clearData()
query = it.toString()
presenter.searchUser(query)
}
}
private fun unsubscribeEditText() {
editTextDisposable.dispose()
}
private fun buildChip(chipText: String) {
val chip = Chip(this)
chip.chipText = chipText
chip.isCloseIconEnabled = true
chip.setChipBackgroundColorResource(R.color.icon_grey)
chip.setOnCloseIconClickListener {
members_chips.removeView(it)
membersToAdd.remove((it as Chip).chipText.toString())
updateToolBar()
} }
members_chips.addView(chip)
}
private fun updateToolBar() {
if (membersToAdd.isEmpty()) {
toolbar_action_text.alpha = 0.8F
toolbar_action_text.isEnabled = false
members_chips.isVisible = false
} else {
toolbar_action_text.alpha = 1.0F
toolbar_action_text.isEnabled = true
members_chips.isVisible = true
} }
return observableSubject toolbar_title.textContent =
getString(R.string.title_add_members, membersToAdd.size.toString())
} }
} }
\ No newline at end of file
package chat.rocket.android.createchannel.di
import android.arch.lifecycle.LifecycleOwner
import chat.rocket.android.createchannel.presentation.CreateChannelView
import chat.rocket.android.createchannel.ui.CreateChannelFragment
import chat.rocket.android.dagger.scope.PerFragment
import dagger.Module
import dagger.Provides
@Module
@PerFragment
class CreateChannelModule {
@Provides
fun createChannelView(fragment: CreateChannelFragment): CreateChannelView {
return fragment
}
@Provides
fun provideLifecycleOwner(fragment: CreateChannelFragment): LifecycleOwner {
return fragment
}
}
\ No newline at end of file
package chat.rocket.android.createchannel.di
import chat.rocket.android.createchannel.ui.CreateChannelFragment
import dagger.Module
import dagger.android.ContributesAndroidInjector
@Module
abstract class CreateChannelProvider {
@ContributesAndroidInjector(modules = [CreateChannelModule::class])
abstract fun provideCreateChannelFragment(): CreateChannelFragment
}
\ No newline at end of file
package chat.rocket.android.createChannel.presentation package chat.rocket.android.createchannel.presentation
import chat.rocket.android.core.lifecycle.CancelStrategy import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.main.presentation.MainNavigator
import chat.rocket.android.members.viewmodel.MemberViewModelMapper
import chat.rocket.android.server.domain.GetCurrentServerInteractor import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.extensions.launchUI import chat.rocket.android.util.extensions.launchUI
...@@ -9,17 +11,20 @@ import chat.rocket.common.model.RoomType ...@@ -9,17 +11,20 @@ import chat.rocket.common.model.RoomType
import chat.rocket.common.util.ifNull import chat.rocket.common.util.ifNull
import chat.rocket.core.RocketChatClient import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.rest.createChannel import chat.rocket.core.internal.rest.createChannel
import chat.rocket.core.internal.rest.searchUser
import javax.inject.Inject import javax.inject.Inject
class CreateNewChannelPresenter @Inject constructor( class CreateChannelPresenter @Inject constructor(
private val view: CreateNewChannelView, private val view: CreateChannelView,
private val strategy: CancelStrategy, private val strategy: CancelStrategy,
private val serverInteractor: GetCurrentServerInteractor, private val mapper: MemberViewModelMapper,
factory: RocketChatClientFactory private val navigator: MainNavigator,
val serverInteractor: GetCurrentServerInteractor,
val factory: RocketChatClientFactory
) { ) {
private val client: RocketChatClient = factory.create(serverInteractor.get()!!) private val client: RocketChatClient = factory.create(serverInteractor.get()!!)
fun createNewChannel( fun createChannel(
roomType: RoomType, roomType: RoomType,
channelName: String, channelName: String,
usersList: List<String>, usersList: List<String>,
...@@ -27,18 +32,40 @@ class CreateNewChannelPresenter @Inject constructor( ...@@ -27,18 +32,40 @@ class CreateNewChannelPresenter @Inject constructor(
) { ) {
launchUI(strategy) { launchUI(strategy) {
view.showLoading() view.showLoading()
view.disableUserInput()
try { try {
client.createChannel(roomType, channelName, usersList, readOnly) client.createChannel(roomType, channelName, usersList, readOnly)
view.prepareToShowChatList()
view.showChannelCreatedSuccessfullyMessage() view.showChannelCreatedSuccessfullyMessage()
toChatList()
} catch (exception: RocketChatException) { } catch (exception: RocketChatException) {
exception.message?.let { exception.message?.let {
view.showMessageAndClearText(it) view.showMessage(it)
}.ifNull { }.ifNull {
view.showErrorMessage() view.showGenericErrorMessage()
} }
} finally { } finally {
view.hideLoading() view.hideLoading()
view.enableUserInput()
} }
} }
} }
fun searchUser(query: String) {
launchUI(strategy) {
try {
val users = client.searchUser(query, count = 5)
val memberViewModelMapper = mapper.mapToViewModelList(users.result)
view.showUserSuggestion(memberViewModelMapper)
} catch (ex: RocketChatException) {
ex.message?.let {
view.showMessage(it)
}.ifNull {
view.showGenericErrorMessage()
}
}
}
}
fun toChatList() = navigator.toChatList()
} }
\ No newline at end of file
package chat.rocket.android.createchannel.presentation
import chat.rocket.android.core.behaviours.LoadingView
import chat.rocket.android.core.behaviours.MessageView
import chat.rocket.android.members.viewmodel.MemberViewModel
interface CreateChannelView : LoadingView, MessageView {
/**
* Shows the server's users suggestion (on the basis of the user typing - the query).
*
* @param dataSet The list of server's users to show.
*/
fun showUserSuggestion(dataSet: List<MemberViewModel>)
/**
* Shows the navigation drawer with the chat item checked before showing the chat list.
* This function is invoked after successfully created the channel.
*/
fun prepareToShowChatList()
/**
* Shows a message that a channel was successfully created.
*/
fun showChannelCreatedSuccessfullyMessage()
/**
* Enables the user input.
*/
fun enableUserInput()
/**
* Disables the user input.
*/
fun disableUserInput()
}
\ No newline at end of file
package chat.rocket.android.createchannel.ui
import android.os.Bundle
import android.support.design.chip.Chip
import android.support.v4.app.Fragment
import android.support.v7.app.AppCompatActivity
import android.support.v7.view.ActionMode
import android.support.v7.widget.LinearLayoutManager
import android.view.*
import androidx.core.view.isVisible
import androidx.core.view.postDelayed
import chat.rocket.android.R
import chat.rocket.android.createchannel.presentation.CreateChannelPresenter
import chat.rocket.android.createchannel.presentation.CreateChannelView
import chat.rocket.android.main.ui.MainActivity
import chat.rocket.android.members.adapter.MembersAdapter
import chat.rocket.android.members.viewmodel.MemberViewModel
import chat.rocket.android.util.extensions.asObservable
import chat.rocket.android.util.extensions.inflate
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 dagger.android.support.AndroidSupportInjection
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.fragment_create_channel.*
import java.util.concurrent.TimeUnit
import javax.inject.Inject
class CreateChannelFragment : Fragment(), CreateChannelView, ActionMode.Callback {
@Inject
lateinit var createChannelPresenter: CreateChannelPresenter
private var actionMode: ActionMode? = null
private val adapter: MembersAdapter = MembersAdapter {
if (it.username != null) {
processSelectedMember(it.username)
}
}
private val compositeDisposable = CompositeDisposable()
private var channelType: RoomType = RoomType.CHANNEL
private var isChannelReadOnly: Boolean = false
private var memberList = arrayListOf<String>()
companion object {
fun newInstance() = CreateChannelFragment()
}
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_create_channel)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupToolBar()
setupViewListeners()
setupRecyclerView()
subscribeEditTexts()
}
override fun onDestroyView() {
super.onDestroyView()
unsubscribeEditTexts()
}
override fun showLoading() {
ui {
view_loading.isVisible = true
}
}
override fun hideLoading() {
ui {
view_loading.isVisible = false
}
}
override fun showMessage(resId: Int) {
ui {
showToast(resId)
}
}
override fun showMessage(message: String) {
ui {
showToast(message)
}
}
override fun showGenericErrorMessage() {
showMessage(getString(R.string.msg_generic_error))
}
override fun showUserSuggestion(dataSet: List<MemberViewModel>) {
// Hiding the progress because we are showing it already.
hideSuggestionViewInProgress()
if (dataSet.isEmpty()) {
showNoSuggestionView()
} else {
showSuggestionViewResults(dataSet)
}
}
override fun prepareToShowChatList() {
with(activity as MainActivity) {
setCheckedNavDrawerItem(R.id.action_chat_rooms)
openDrawer()
getDrawerLayout().postDelayed(600) {
closeDrawer()
createChannelPresenter.toChatList()
}
}
}
override fun showChannelCreatedSuccessfullyMessage() {
showMessage(getString(R.string.msg_channel_created_successfully))
}
override fun enableUserInput() {
text_channel_name.isEnabled = true
text_invite_members.isEnabled = true
}
override fun disableUserInput() {
text_channel_name.isEnabled = false
text_invite_members.isEnabled = false
}
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
mode.menuInflater.inflate(R.menu.create_channel, menu)
mode.title = getString(R.string.title_create_channel)
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_create_channel -> {
createChannelPresenter.createChannel(
channelType,
text_channel_name.text.toString(),
memberList,
isChannelReadOnly
)
mode.finish()
true
}
else -> {
false
}
}
}
override fun onDestroyActionMode(mode: ActionMode) {
actionMode = null
}
private fun setupToolBar() {
(activity as AppCompatActivity?)?.supportActionBar?.title =
getString(R.string.title_create_channel)
}
private fun setupViewListeners() {
switch_channel_type.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
text_channel_type.text = getString(R.string.msg_private_channel)
text_channel_type_description.text =
getString(R.string.msg_private_channel_description)
image_channel_icon.setImageDrawable(
context?.getDrawable(R.drawable.ic_lock_black_12_dp)
)
channelType = RoomType.PRIVATE_GROUP
} else {
text_channel_type.text = getString(R.string.msg_public_channel)
text_channel_type_description.text =
getString(R.string.msg_public_channel_description)
image_channel_icon.setImageDrawable(
context?.getDrawable(R.drawable.ic_hashtag_black_12dp)
)
channelType = RoomType.CHANNEL
}
}
switch_read_only.setOnCheckedChangeListener { _, isChecked ->
isChannelReadOnly = isChecked
}
}
private fun setupRecyclerView() {
ui {
recycler_view.layoutManager =
LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
recycler_view.addItemDecoration(DividerItemDecoration(it))
recycler_view.adapter = adapter
}
}
private fun subscribeEditTexts() {
val channelNameDisposable = text_channel_name.asObservable()
.subscribe {
if (it.isNotBlank()) {
startActionMode()
} else {
finishActionMode()
}
}
val inviteMembersDisposable = text_invite_members.asObservable()
.debounce(500, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
.subscribe {
if (it.length >= 3) {
showSuggestionViewInProgress()
createChannelPresenter.searchUser(it.toString())
} else {
hideSuggestionView()
}
}
compositeDisposable.addAll(channelNameDisposable, inviteMembersDisposable)
}
private fun unsubscribeEditTexts() {
compositeDisposable.dispose()
}
private fun startActionMode() {
if (actionMode == null) {
actionMode = (activity as MainActivity).startSupportActionMode(this)
}
}
private fun finishActionMode() {
actionMode?.finish()
}
private fun processSelectedMember(username: String) {
if (memberList.contains(username)) {
showMessage(getString(R.string.msg_member_already_added))
} else {
hideSuggestionView()
text_invite_members.setText("")
addMember(username)
addChip(username)
chip_group_member.isVisible = true
}
}
private fun addMember(username: String) {
memberList.add(username)
}
private fun removeMember(username: String) {
memberList.remove(username)
}
private fun addChip(chipText: String) {
val chip = Chip(context)
chip.chipText = chipText
chip.isCloseIconEnabled = true
chip.setChipBackgroundColorResource(R.color.icon_grey)
setupChipOnCloseIconClickListener(chip)
chip_group_member.addView(chip)
}
private fun setupChipOnCloseIconClickListener(chip: Chip) {
chip.setOnCloseIconClickListener {
removeChip(it)
removeMember((it as Chip).chipText.toString())
// whenever we remove a chip we should process the chip group visibility.
processChipGroupVisibility()
}
}
private fun removeChip(chip: View) {
chip_group_member.removeView(chip)
}
private fun processChipGroupVisibility() {
chip_group_member.isVisible = memberList.isNotEmpty()
}
private fun showSuggestionView() {
view_member_suggestion.isVisible = true
}
private fun hideSuggestionView() {
view_member_suggestion.isVisible = false
}
private fun showSuggestionViewInProgress() {
recycler_view.isVisible = false
text_member_not_found.isVisible = false
view_member_suggestion_loading.isVisible = true
showSuggestionView()
}
private fun hideSuggestionViewInProgress() {
view_member_suggestion_loading.isVisible = false
}
private fun showSuggestionViewResults(dataSet: List<MemberViewModel>) {
adapter.clearData()
adapter.prependData(dataSet)
text_member_not_found.isVisible = false
recycler_view.isVisible = true
showSuggestionView()
}
private fun showNoSuggestionView() {
recycler_view.isVisible = false
text_member_not_found.isVisible = true
showSuggestionView()
}
}
\ No newline at end of file
...@@ -13,11 +13,9 @@ import chat.rocket.android.chatroom.di.ChatRoomModule ...@@ -13,11 +13,9 @@ import chat.rocket.android.chatroom.di.ChatRoomModule
import chat.rocket.android.chatroom.di.FavoriteMessagesFragmentProvider import chat.rocket.android.chatroom.di.FavoriteMessagesFragmentProvider
import chat.rocket.android.chatroom.ui.ChatRoomActivity import chat.rocket.android.chatroom.ui.ChatRoomActivity
import chat.rocket.android.chatrooms.di.ChatRoomsFragmentProvider import chat.rocket.android.chatrooms.di.ChatRoomsFragmentProvider
import chat.rocket.android.createChannel.addMembers.di.AddMembersModule import chat.rocket.android.createchannel.addmembers.di.AddMembersModule
import chat.rocket.android.createChannel.addMembers.ui.AddMembersActivity import chat.rocket.android.createchannel.addmembers.ui.AddMembersActivity
import chat.rocket.android.createChannel.di.CreateNewChannelModule import chat.rocket.android.createchannel.di.CreateChannelProvider
import chat.rocket.android.createChannel.di.CreateNewChannelProvider
import chat.rocket.android.createChannel.ui.CreateNewChannelActivity
import chat.rocket.android.dagger.scope.PerActivity import chat.rocket.android.dagger.scope.PerActivity
import chat.rocket.android.files.di.FilesFragmentProvider import chat.rocket.android.files.di.FilesFragmentProvider
import chat.rocket.android.main.di.MainModule import chat.rocket.android.main.di.MainModule
...@@ -27,6 +25,7 @@ import chat.rocket.android.pinnedmessages.di.PinnedMessagesFragmentProvider ...@@ -27,6 +25,7 @@ import chat.rocket.android.pinnedmessages.di.PinnedMessagesFragmentProvider
import chat.rocket.android.profile.di.ProfileFragmentProvider import chat.rocket.android.profile.di.ProfileFragmentProvider
import chat.rocket.android.server.di.ChangeServerModule import chat.rocket.android.server.di.ChangeServerModule
import chat.rocket.android.server.ui.ChangeServerActivity import chat.rocket.android.server.ui.ChangeServerActivity
import chat.rocket.android.settings.di.SettingsFragmentProvider
import chat.rocket.android.settings.password.di.PasswordFragmentProvider import chat.rocket.android.settings.password.di.PasswordFragmentProvider
import chat.rocket.android.settings.password.ui.PasswordActivity import chat.rocket.android.settings.password.ui.PasswordActivity
import dagger.Module import dagger.Module
...@@ -52,7 +51,9 @@ abstract class ActivityBuilder { ...@@ -52,7 +51,9 @@ abstract class ActivityBuilder {
@ContributesAndroidInjector( @ContributesAndroidInjector(
modules = [MainModule::class, modules = [MainModule::class,
ChatRoomsFragmentProvider::class, ChatRoomsFragmentProvider::class,
ProfileFragmentProvider::class CreateChannelProvider::class,
ProfileFragmentProvider::class,
SettingsFragmentProvider::class
] ]
) )
abstract fun bindMainActivity(): MainActivity abstract fun bindMainActivity(): MainActivity
...@@ -78,10 +79,6 @@ abstract class ActivityBuilder { ...@@ -78,10 +79,6 @@ abstract class ActivityBuilder {
@ContributesAndroidInjector(modules = [ChangeServerModule::class]) @ContributesAndroidInjector(modules = [ChangeServerModule::class])
abstract fun bindChangeServerActivity(): ChangeServerActivity abstract fun bindChangeServerActivity(): ChangeServerActivity
@PerActivity
@ContributesAndroidInjector(modules = [CreateNewChannelModule::class])
abstract fun bindCreateNewChannelActivity(): CreateNewChannelActivity
@PerActivity @PerActivity
@ContributesAndroidInjector(modules = [AddMembersModule::class]) @ContributesAndroidInjector(modules = [AddMembersModule::class])
abstract fun bindAddMembersActivity(): AddMembersActivity abstract fun bindAddMembersActivity(): AddMembersActivity
......
...@@ -4,6 +4,7 @@ import chat.rocket.android.R ...@@ -4,6 +4,7 @@ import chat.rocket.android.R
import chat.rocket.android.authentication.ui.newServerIntent import chat.rocket.android.authentication.ui.newServerIntent
import chat.rocket.android.chatroom.ui.chatRoomIntent import chat.rocket.android.chatroom.ui.chatRoomIntent
import chat.rocket.android.chatrooms.ui.ChatRoomsFragment import chat.rocket.android.chatrooms.ui.ChatRoomsFragment
import chat.rocket.android.createchannel.ui.CreateChannelFragment
import chat.rocket.android.main.ui.MainActivity import chat.rocket.android.main.ui.MainActivity
import chat.rocket.android.profile.ui.ProfileFragment import chat.rocket.android.profile.ui.ProfileFragment
import chat.rocket.android.server.ui.changeServerIntent import chat.rocket.android.server.ui.changeServerIntent
...@@ -18,6 +19,12 @@ class MainNavigator(internal val activity: MainActivity) { ...@@ -18,6 +19,12 @@ class MainNavigator(internal val activity: MainActivity) {
} }
} }
fun toCreateChannel() {
activity.addFragment("CreateChannelFragment", R.id.fragment_container) {
CreateChannelFragment.newInstance()
}
}
fun toUserProfile() { fun toUserProfile() {
activity.addFragment("ProfileFragment", R.id.fragment_container) { activity.addFragment("ProfileFragment", R.id.fragment_container) {
ProfileFragment.newInstance() ProfileFragment.newInstance()
...@@ -30,15 +37,26 @@ class MainNavigator(internal val activity: MainActivity) { ...@@ -30,15 +37,26 @@ class MainNavigator(internal val activity: MainActivity) {
} }
} }
fun toChatRoom(chatRoomId: String, fun toChatRoom(
chatRoomId: String,
chatRoomName: String, chatRoomName: String,
chatRoomType: String, chatRoomType: String,
isChatRoomReadOnly: Boolean, isChatRoomReadOnly: Boolean,
chatRoomLastSeen: Long, chatRoomLastSeen: Long,
isChatRoomSubscribed: Boolean, isChatRoomSubscribed: Boolean,
isChatRoomCreator: Boolean) { isChatRoomCreator: Boolean
activity.startActivity(activity.chatRoomIntent(chatRoomId, chatRoomName, chatRoomType, ) {
isChatRoomReadOnly, chatRoomLastSeen, isChatRoomSubscribed, isChatRoomCreator)) activity.startActivity(
activity.chatRoomIntent(
chatRoomId,
chatRoomName,
chatRoomType,
isChatRoomReadOnly,
chatRoomLastSeen,
isChatRoomSubscribed,
isChatRoomCreator
)
)
activity.overridePendingTransition(R.anim.open_enter, R.anim.open_exit) activity.overridePendingTransition(R.anim.open_enter, R.anim.open_exit)
} }
......
...@@ -55,6 +55,8 @@ class MainPresenter @Inject constructor( ...@@ -55,6 +55,8 @@ class MainPresenter @Inject constructor(
fun toSettings() = navigator.toSettings() fun toSettings() = navigator.toSettings()
fun toCreateChannel() = navigator.toCreateChannel()
fun loadCurrentInfo() { fun loadCurrentInfo() {
checkServerInfo(currentServer) checkServerInfo(currentServer)
launchUI(strategy) { launchUI(strategy) {
......
...@@ -4,7 +4,9 @@ import DrawableHelper ...@@ -4,7 +4,9 @@ import DrawableHelper
import android.app.Activity import android.app.Activity
import android.app.AlertDialog import android.app.AlertDialog
import android.os.Bundle import android.os.Bundle
import android.support.annotation.IdRes
import android.support.v4.app.Fragment import android.support.v4.app.Fragment
import android.support.v4.widget.DrawerLayout
import android.support.v7.app.AppCompatActivity import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.LinearLayoutManager import android.support.v7.widget.LinearLayoutManager
import android.view.Gravity import android.view.Gravity
...@@ -26,7 +28,6 @@ import chat.rocket.android.util.extensions.showToast ...@@ -26,7 +28,6 @@ import chat.rocket.android.util.extensions.showToast
import chat.rocket.common.model.UserStatus import chat.rocket.common.model.UserStatus
import com.google.firebase.iid.FirebaseInstanceId import com.google.firebase.iid.FirebaseInstanceId
import com.google.firebase.messaging.FirebaseMessaging import com.google.firebase.messaging.FirebaseMessaging
import com.google.android.gms.common.api.GoogleApiClient
import dagger.android.AndroidInjection import dagger.android.AndroidInjection
import dagger.android.AndroidInjector import dagger.android.AndroidInjector
import dagger.android.DispatchingAndroidInjector import dagger.android.DispatchingAndroidInjector
...@@ -186,14 +187,14 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, ...@@ -186,14 +187,14 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector,
setSupportActionBar(toolbar) setSupportActionBar(toolbar)
toolbar.setNavigationIcon(R.drawable.ic_menu_white_24dp) toolbar.setNavigationIcon(R.drawable.ic_menu_white_24dp)
toolbar.setNavigationOnClickListener { toolbar.setNavigationOnClickListener {
drawer_layout.openDrawer(Gravity.START) openDrawer()
} }
} }
private fun setupNavigationView() { private fun setupNavigationView() {
view_navigation.setNavigationItemSelectedListener { menuItem -> view_navigation.setNavigationItemSelectedListener { menuItem ->
menuItem.isChecked = true menuItem.isChecked = true
drawer_layout.closeDrawer(Gravity.START) closeDrawer()
onNavDrawerItemSelected(menuItem) onNavDrawerItemSelected(menuItem)
true true
} }
...@@ -207,6 +208,9 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, ...@@ -207,6 +208,9 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector,
R.id.action_profile -> { R.id.action_profile -> {
presenter.toUserProfile() presenter.toUserProfile()
} }
R.id.action_channel -> {
presenter.toCreateChannel()
}
R.id.action_settings -> { R.id.action_settings -> {
presenter.toSettings() presenter.toSettings()
} }
...@@ -244,9 +248,25 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, ...@@ -244,9 +248,25 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector,
} }
header.image_avatar.setOnClickListener { header.image_avatar.setOnClickListener {
view_navigation.menu.findItem(R.id.action_profile).isChecked = true view_navigation.menu.findItem(R.id.action_update_profile).isChecked = true
presenter.toUserProfile() presenter.toUserProfile()
drawer_layout.closeDrawer(Gravity.START) drawer_layout.closeDrawer(Gravity.START)
} }
} }
fun getDrawerLayout(): DrawerLayout {
return drawer_layout
}
fun openDrawer() {
drawer_layout.openDrawer(Gravity.START)
}
fun closeDrawer() {
drawer_layout.closeDrawer(Gravity.START)
}
fun setCheckedNavDrawerItem(@IdRes item: Int) {
view_navigation.setCheckedItem(item)
}
} }
\ No newline at end of file
...@@ -10,17 +10,22 @@ import chat.rocket.android.util.extensions.inflate ...@@ -10,17 +10,22 @@ import chat.rocket.android.util.extensions.inflate
import kotlinx.android.synthetic.main.avatar.view.* import kotlinx.android.synthetic.main.avatar.view.*
import kotlinx.android.synthetic.main.item_member.view.* import kotlinx.android.synthetic.main.item_member.view.*
class MembersAdapter(private val listener: (MemberViewModel) -> Unit) : RecyclerView.Adapter<MembersAdapter.ViewHolder>() { class MembersAdapter(private val listener: (MemberViewModel) -> Unit) :
private var dataSet: List<MemberViewModel> = ArrayList() RecyclerView.Adapter<MembersAdapter.ViewHolder>() {
private var dataSet = emptyList<MemberViewModel>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MembersAdapter.ViewHolder = ViewHolder(parent.inflate(R.layout.item_member)) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MembersAdapter.ViewHolder =
ViewHolder(parent.inflate(R.layout.item_member))
override fun onBindViewHolder(holder: MembersAdapter.ViewHolder, position: Int) = holder.bind(dataSet[position], listener) override fun onBindViewHolder(holder: MembersAdapter.ViewHolder, position: Int) =
holder.bind(dataSet[position], listener)
override fun getItemCount(): Int = dataSet.size override fun getItemCount(): Int = dataSet.size
fun reAllocateArrayList(){ fun clearData() {
this.dataSet = ArrayList() val itemCount = dataSet.size
dataSet = emptyList()
notifyItemRangeRemoved(0, itemCount)
} }
fun prependData(dataSet: List<MemberViewModel>) { fun prependData(dataSet: List<MemberViewModel>) {
...@@ -36,10 +41,10 @@ class MembersAdapter(private val listener: (MemberViewModel) -> Unit) : Recycler ...@@ -36,10 +41,10 @@ class MembersAdapter(private val listener: (MemberViewModel) -> Unit) : Recycler
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(memberViewModel: MemberViewModel, listener: (MemberViewModel) -> Unit) = with(itemView) { fun bind(memberViewModel: MemberViewModel, listener: (MemberViewModel) -> Unit) =
with(itemView) {
image_avatar.setImageURI(memberViewModel.avatarUri) image_avatar.setImageURI(memberViewModel.avatarUri)
text_member.content = memberViewModel.displayName text_member.content = memberViewModel.displayName
setOnClickListener { listener(memberViewModel) } setOnClickListener { listener(memberViewModel) }
} }
} }
......
...@@ -36,8 +36,7 @@ private const val BUNDLE_CHAT_ROOM_ID = "chat_room_id" ...@@ -36,8 +36,7 @@ private const val BUNDLE_CHAT_ROOM_ID = "chat_room_id"
class MembersFragment : Fragment(), MembersView { class MembersFragment : Fragment(), MembersView {
@Inject @Inject
lateinit var presenter: MembersPresenter lateinit var presenter: MembersPresenter
private val adapter: MembersAdapter = private val adapter: MembersAdapter = MembersAdapter { presenter.toMemberDetails(it) }
MembersAdapter { memberViewModel -> presenter.toMemberDetails(memberViewModel) }
private val linearLayoutManager = private val linearLayoutManager =
LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
private lateinit var chatRoomId: String private lateinit var chatRoomId: String
......
...@@ -36,11 +36,6 @@ class MemberViewModel( ...@@ -36,11 +36,6 @@ class MemberViewModel(
private fun getUserDisplayName(): String { private fun getUserDisplayName(): String {
val username = member.username val username = member.username
val realName = member.name val realName = member.name
if (username == null && realName != null) {
return realName
} else if (username != null && realName == null) {
return username
}
val senderName = if (settings.useRealName()) realName else username val senderName = if (settings.useRealName()) realName else username
return senderName ?: username.toString() return senderName ?: username.toString()
} }
......
...@@ -13,20 +13,21 @@ import chat.rocket.android.profile.presentation.ProfilePresenter ...@@ -13,20 +13,21 @@ import chat.rocket.android.profile.presentation.ProfilePresenter
import chat.rocket.android.profile.presentation.ProfileView import chat.rocket.android.profile.presentation.ProfileView
import chat.rocket.android.util.extensions.* import chat.rocket.android.util.extensions.*
import dagger.android.support.AndroidSupportInjection import dagger.android.support.AndroidSupportInjection
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.Disposable
import io.reactivex.rxkotlin.Observables import io.reactivex.rxkotlin.Observables
import kotlinx.android.synthetic.main.avatar_profile.* import kotlinx.android.synthetic.main.avatar_profile.*
import kotlinx.android.synthetic.main.fragment_profile.* import kotlinx.android.synthetic.main.fragment_profile.*
import javax.inject.Inject import javax.inject.Inject
class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback { class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
@Inject lateinit var presenter: ProfilePresenter @Inject
lateinit var presenter: ProfilePresenter
private lateinit var currentName: String private lateinit var currentName: String
private lateinit var currentUsername: String private lateinit var currentUsername: String
private lateinit var currentEmail: String private lateinit var currentEmail: String
private lateinit var currentAvatar: String private lateinit var currentAvatar: String
private var actionMode: ActionMode? = null private var actionMode: ActionMode? = null
private val disposables = CompositeDisposable() private lateinit var editTextsDisposable: Disposable
companion object { companion object {
fun newInstance() = ProfileFragment() fun newInstance() = ProfileFragment()
...@@ -37,7 +38,11 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback { ...@@ -37,7 +38,11 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = container?.inflate(R.layout.fragment_profile) override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? = container?.inflate(R.layout.fragment_profile)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
...@@ -51,8 +56,8 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback { ...@@ -51,8 +56,8 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
} }
override fun onDestroyView() { override fun onDestroyView() {
disposables.clear()
super.onDestroyView() super.onDestroyView()
unsubscribeEditTexts()
} }
override fun showProfile(avatarUrl: String, name: String, username: String, email: String?) { override fun showProfile(avatarUrl: String, name: String, username: String, email: String?) {
...@@ -71,7 +76,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback { ...@@ -71,7 +76,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
profile_container.setVisible(true) profile_container.setVisible(true)
listenToChanges() subscribeEditTexts()
} }
} }
...@@ -119,8 +124,13 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback { ...@@ -119,8 +124,13 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
override fun onActionItemClicked(mode: ActionMode, menuItem: MenuItem): Boolean { override fun onActionItemClicked(mode: ActionMode, menuItem: MenuItem): Boolean {
return when (menuItem.itemId) { return when (menuItem.itemId) {
R.id.action_profile -> { R.id.action_update_profile -> {
presenter.updateUserProfile(text_email.textContent, text_name.textContent, text_username.textContent, text_avatar_url.textContent) presenter.updateUserProfile(
text_email.textContent,
text_name.textContent,
text_username.textContent,
text_avatar_url.textContent
)
mode.finish() mode.finish()
true true
} }
...@@ -135,28 +145,36 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback { ...@@ -135,28 +145,36 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
} }
private fun setupToolbar() { private fun setupToolbar() {
(activity as AppCompatActivity?)?.supportActionBar?.title = getString(R.string.title_profile) (activity as AppCompatActivity?)?.supportActionBar?.title =
getString(R.string.title_profile)
} }
private fun tintEditTextDrawableStart() { private fun tintEditTextDrawableStart() {
(activity as MainActivity).apply { (activity as MainActivity).apply {
val personDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_person_black_24dp, this) val personDrawable =
DrawableHelper.getDrawableFromId(R.drawable.ic_person_black_24dp, this)
val atDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_at_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 emailDrawable =
DrawableHelper.getDrawableFromId(R.drawable.ic_email_black_24dp, this)
val linkDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_link_black_24dp, this) val linkDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_link_black_24dp, this)
val drawables = arrayOf(personDrawable, atDrawable, emailDrawable, linkDrawable) val drawables = arrayOf(personDrawable, atDrawable, emailDrawable, linkDrawable)
DrawableHelper.wrapDrawables(drawables) DrawableHelper.wrapDrawables(drawables)
DrawableHelper.tintDrawables(drawables, this, R.color.colorDrawableTintGrey) DrawableHelper.tintDrawables(drawables, this, R.color.colorDrawableTintGrey)
DrawableHelper.compoundDrawables(arrayOf(text_name, text_username, text_email, text_avatar_url), drawables) DrawableHelper.compoundDrawables(
arrayOf(text_name, text_username, text_email, text_avatar_url),
drawables
)
} }
} }
private fun listenToChanges() { private fun subscribeEditTexts() {
disposables.add(Observables.combineLatest(text_name.asObservable(), editTextsDisposable = Observables.combineLatest(
text_name.asObservable(),
text_username.asObservable(), text_username.asObservable(),
text_email.asObservable(), text_email.asObservable(),
text_avatar_url.asObservable()) { text_name, text_username, text_email, text_avatar_url -> text_avatar_url.asObservable()
) { text_name, text_username, text_email, text_avatar_url ->
return@combineLatest (text_name.toString() != currentName || return@combineLatest (text_name.toString() != currentName ||
text_username.toString() != currentUsername || text_username.toString() != currentUsername ||
text_email.toString() != currentEmail || text_email.toString() != currentEmail ||
...@@ -167,7 +185,11 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback { ...@@ -167,7 +185,11 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
} else { } else {
finishActionMode() finishActionMode()
} }
}) }
}
private fun unsubscribeEditTexts() {
editTextsDisposable.dispose()
} }
private fun startActionMode() { private fun startActionMode() {
......
package chat.rocket.android.settings.di package chat.rocket.android.settings.di
import android.arch.lifecycle.LifecycleOwner import android.arch.lifecycle.LifecycleOwner
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.dagger.scope.PerFragment import chat.rocket.android.dagger.scope.PerFragment
import chat.rocket.android.settings.presentation.SettingsView import chat.rocket.android.settings.presentation.SettingsView
import chat.rocket.android.settings.ui.SettingsFragment import chat.rocket.android.settings.ui.SettingsFragment
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import kotlinx.coroutines.experimental.Job
@Module @Module
@PerFragment @PerFragment
class SettingsFragmentModule { class SettingsFragmentModule {
@Provides @Provides
fun settingsView(frag: SettingsFragment): SettingsView { fun settingsView(frag: SettingsFragment): SettingsView {
return frag return frag
} }
@Provides @Provides
fun settingsLifecycleOwner(frag: SettingsFragment): LifecycleOwner { fun provideLifecycleOwner(frag: SettingsFragment): LifecycleOwner {
return frag return frag
} }
@Provides
fun provideCancelStrategy(owner: LifecycleOwner, jobs: Job): CancelStrategy {
return CancelStrategy(owner, jobs)
}
} }
\ No newline at end of file
...@@ -6,6 +6,7 @@ import dagger.android.ContributesAndroidInjector ...@@ -6,6 +6,7 @@ import dagger.android.ContributesAndroidInjector
@Module @Module
abstract class SettingsFragmentProvider { abstract class SettingsFragmentProvider {
@ContributesAndroidInjector(modules = [SettingsFragmentModule::class]) @ContributesAndroidInjector(modules = [SettingsFragmentModule::class])
abstract fun provideSettingsFragment(): SettingsFragment abstract fun provideSettingsFragment(): SettingsFragment
} }
\ No newline at end of file
...@@ -16,16 +16,19 @@ import chat.rocket.android.util.extensions.inflate ...@@ -16,16 +16,19 @@ import chat.rocket.android.util.extensions.inflate
import kotlinx.android.synthetic.main.fragment_settings.* import kotlinx.android.synthetic.main.fragment_settings.*
import kotlin.reflect.KClass import kotlin.reflect.KClass
class SettingsFragment: Fragment(), SettingsView, AdapterView.OnItemClickListener { class SettingsFragment : Fragment(), SettingsView, AdapterView.OnItemClickListener {
companion object { companion object {
fun newInstance() = SettingsFragment() fun newInstance() = SettingsFragment()
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = container?.inflate(R.layout.fragment_settings) override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? = container?.inflate(R.layout.fragment_settings)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
setupToolbar() setupToolbar()
setupListView() setupListView()
} }
...@@ -34,7 +37,8 @@ class SettingsFragment: Fragment(), SettingsView, AdapterView.OnItemClickListene ...@@ -34,7 +37,8 @@ class SettingsFragment: Fragment(), SettingsView, AdapterView.OnItemClickListene
when (parent?.getItemAtPosition(position).toString()) { when (parent?.getItemAtPosition(position).toString()) {
resources.getString(R.string.title_password) -> { resources.getString(R.string.title_password) -> {
startNewActivity(PasswordActivity::class) startNewActivity(PasswordActivity::class)
}resources.getString(R.string.title_about) -> { }
resources.getString(R.string.title_about) -> {
startNewActivity(AboutActivity::class) startNewActivity(AboutActivity::class)
} }
} }
...@@ -45,7 +49,8 @@ class SettingsFragment: Fragment(), SettingsView, AdapterView.OnItemClickListene ...@@ -45,7 +49,8 @@ class SettingsFragment: Fragment(), SettingsView, AdapterView.OnItemClickListene
} }
private fun setupToolbar() { private fun setupToolbar() {
(activity as AppCompatActivity?)?.supportActionBar?.title = getString(R.string.title_settings) (activity as AppCompatActivity?)?.supportActionBar?.title =
getString(R.string.title_settings)
} }
private fun startNewActivity(classType: KClass<out AppCompatActivity>) { private fun startNewActivity(classType: KClass<out AppCompatActivity>) {
......
...@@ -4,10 +4,10 @@ import android.widget.EditText ...@@ -4,10 +4,10 @@ import android.widget.EditText
import com.jakewharton.rxbinding2.widget.RxTextView import com.jakewharton.rxbinding2.widget.RxTextView
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import java.util.concurrent.TimeUnit import io.reactivex.schedulers.Schedulers
fun EditText.asObservable(): Observable<CharSequence> { fun EditText.asObservable(): Observable<CharSequence> {
return RxTextView.textChanges(this) return RxTextView.textChanges(this)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribeOn(AndroidSchedulers.mainThread())
} }
\ 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">
<gradient
android:endColor="@color/default_background"
android:startColor="@color/default_background" />
<stroke
android:width="1dp"
android:color="@color/colorRed" />
<corners
android:bottomRightRadius="5dp"
android:topRightRadius="5dp" />
</shape>
\ 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">
<solid android:color="@color/colorRed" />
<corners
android:bottomLeftRadius="5dp"
android:topLeftRadius="5dp" />
</shape>
\ No newline at end of file
...@@ -4,6 +4,6 @@ ...@@ -4,6 +4,6 @@
android:viewportWidth="24.0" android:viewportWidth="24.0"
android:viewportHeight="24.0"> android:viewportHeight="24.0">
<path <path
android:fillColor="@color/colorSecondaryText" android:fillColor="#FF000000"
android:pathData="M15,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM6,10L6,7L4,7v3L1,10v2h3v3h2v-3h3v-2L6,10zM15,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/> android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
</vector> </vector>
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android" <shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval"> android:shape="oval">
<solid <solid android:color="@color/colorAccent" />
android:color="@color/colorAccent" />
</shape> </shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" <shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"> android:shape="rectangle">
<solid android:color="#10000000" /> <solid android:color="#10000000" />
<corners android:radius="5dp" /> <corners android:radius="5dp" />
<size android:height="2dp" /> <size android:height="2dp" />
</shape> </shape>
\ No newline at end of file
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="8dp" android:layout_margin="8dp"
android:visibility="gone"
app:chipSpacing="3dp" app:chipSpacing="3dp"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"> app:layout_constraintTop_toTopOf="parent">
...@@ -45,7 +46,7 @@ ...@@ -45,7 +46,7 @@
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<EditText <EditText
android:id="@+id/search_view" android:id="@+id/text_search_member"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:backgroundTint="@android:color/transparent" android:backgroundTint="@android:color/transparent"
...@@ -60,15 +61,14 @@ ...@@ -60,15 +61,14 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0.2dp" android:layout_height="0.2dp"
android:background="@color/colorDividerMessageComposer" android:background="@color/colorDividerMessageComposer"
app:layout_constraintTop_toBottomOf="@id/search_view" /> app:layout_constraintTop_toBottomOf="@id/text_search_member" />
<android.support.v7.widget.RecyclerView <android.support.v7.widget.RecyclerView
android:id="@+id/search_results" android:id="@+id/recycler_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_margin="8dp"
android:scrollbars="vertical" android:scrollbars="vertical"
app:layout_constraintTop_toBottomOf="@id/separator_1" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/> app:layout_constraintTop_toBottomOf="@id/separator_1" />
</android.support.constraint.ConstraintLayout> </android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout> </android.support.constraint.ConstraintLayout>
\ 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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
android:id="@+id/toolbar_layout"
layout="@layout/layout_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@+id/layout_container"
app:layout_constraintTop_toTopOf="parent" />
<com.wang.avi.AVLoadingIndicatorView
android:id="@+id/view_loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:indicatorColor="@color/colorBlack"
app:indicatorName="BallPulseIndicator"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/toolbar_layout"
tools:visibility="visible" />
<android.support.constraint.ConstraintLayout
android:id="@+id/layout_container"
android:layout_width="0dp"
android:layout_height="0dp"
android:paddingTop="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/toolbar_layout">
<android.support.constraint.Guideline
android:id="@+id/button_top_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.03" />
<android.support.constraint.Guideline
android:id="@+id/button_bottom_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.09" />
<Button
android:id="@+id/public_channel"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:background="@drawable/button_solid"
android:text="@string/public_channel_type"
android:textColor="@color/default_background"
app:layout_constraintBottom_toBottomOf="@id/button_bottom_guideline"
app:layout_constraintEnd_toStartOf="@+id/private_channel"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/button_top_guideline" />
<Button
android:id="@+id/private_channel"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:background="@drawable/button_border"
android:text="@string/private_channel_type"
android:textColor="@color/colorRed"
app:layout_constraintBottom_toBottomOf="@id/button_bottom_guideline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/public_channel"
app:layout_constraintTop_toTopOf="@id/button_top_guideline" />
<TextView
android:id="@+id/channel_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:text="@string/public_channel_type"
android:textColor="@color/colorPrimaryText"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/public_channel" />
<TextView
android:id="@+id/channel_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="4dp"
android:text="@string/public_channel_description"
android:textColor="@color/colorSecondaryText"
android:textSize="12sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/channel_type" />
<View
android:id="@+id/separator_1"
android:layout_width="0dp"
android:layout_height="0.5dp"
android:layout_marginTop="8dp"
android:background="@color/colorDividerMessageComposer"
app:layout_constraintTop_toBottomOf="@id/channel_description" />
<ImageView
android:id="@+id/placeholder"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:src="@drawable/ic_hashtag_black_12dp"
app:layout_constraintBottom_toBottomOf="@id/channel_name_text_input_layout"
app:layout_constraintEnd_toStartOf="@id/channel_name_text_input_layout"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/channel_name_text_input_layout" />
<android.support.design.widget.TextInputLayout
android:id="@+id/channel_name_text_input_layout"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:focusable="true"
android:hint="@string/msg_channel_name"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/placeholder"
app:layout_constraintTop_toBottomOf="@id/separator_1">
<android.support.design.widget.TextInputEditText
android:id="@+id/channel_name_edit_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="16sp" />
</android.support.design.widget.TextInputLayout>
<View
android:id="@+id/separator_2"
android:layout_width="0dp"
android:layout_height="0.5dp"
android:layout_marginTop="8dp"
android:background="@color/colorDividerMessageComposer"
app:layout_constraintTop_toBottomOf="@id/channel_name_text_input_layout" />
<android.support.constraint.ConstraintLayout
android:id="@+id/add_members_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:paddingBottom="8dp"
android:paddingTop="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/separator_2">
<TextView
android:id="@+id/add_members_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:text="@string/msg_add_members"
android:textColor="@color/colorSecondaryText"
android:textSize="16sp"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginTop="8dp"
android:src="@drawable/ic_person_add_black_24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1"
app:layout_constraintStart_toEndOf="@id/add_members_text"
app:layout_constraintTop_toTopOf="parent" />
<android.support.design.chip.ChipGroup
android:id="@+id/selected_members_chips"
style="@style/Widget.MaterialComponents.Chip.Entry"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
app:chipSpacing="3dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/add_members_text">
</android.support.design.chip.ChipGroup>
</android.support.constraint.ConstraintLayout>
<View
android:id="@+id/separator_3"
android:layout_width="0dp"
android:layout_height="0.5dp"
android:background="@color/colorDividerMessageComposer"
app:layout_constraintTop_toBottomOf="@id/add_members_view" />
</android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout>
\ No newline at end of file
...@@ -46,25 +46,13 @@ ...@@ -46,25 +46,13 @@
tools:visibility="visible" /> tools:visibility="visible" />
<TextView <TextView
android:id="@+id/text_no_search" android:id="@+id/text_no_result_found"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="56dp" android:layout_marginTop="56dp"
android:text="@string/msg_no_search_found" android:text="@string/msg_no_search_found"
android:textSize="20sp" android:textSize="20sp"
android:layout_centerHorizontal="true"
android:visibility="gone" android:visibility="gone"
tools:visibility="visible" /> tools:visibility="visible" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/create_new_channel_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
app:useCompatPadding="true"
android:layout_alignParentBottom="true"
android:src="@drawable/ic_add_white_24dp"
app:backgroundTint="@color/colorAccent"
/>
</RelativeLayout> </RelativeLayout>
\ 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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="16dp"
android:focusableInTouchMode="true"
tools:context="createchannel.ui.CreateChannelFragment">
<com.wang.avi.AVLoadingIndicatorView
android:id="@+id/view_loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:indicatorColor="@color/colorBlack"
app:indicatorName="BallPulseIndicator"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" />
<TextView
android:id="@+id/text_channel_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/msg_public_channel"
android:textColor="@color/colorPrimaryText"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/text_channel_type_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/msg_public_channel_description"
android:textColor="@color/colorSecondaryText"
android:textSize="12sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_channel_type" />
<Switch
android:id="@+id/switch_channel_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="@+id/text_channel_type_description"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/text_channel_type" />
<TextView
android:id="@+id/text_read_only"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/msg_ready_only_channel"
android:textColor="@color/colorPrimaryText"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_channel_type_description" />
<TextView
android:id="@+id/text_read_only_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/msg_ready_only_channel_description"
android:textColor="@color/colorSecondaryText"
android:textSize="12sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_read_only" />
<Switch
android:id="@+id/switch_read_only"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="@+id/text_read_only_description"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/text_read_only" />
<ImageView
android:id="@+id/image_channel_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="22dp"
android:src="@drawable/ic_hashtag_black_12dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_read_only_description" />
<EditText
android:id="@+id/text_channel_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="@color/colorDim"
android:hint="@string/msg_channel_name"
android:inputType="text"
android:maxLines="1"
android:paddingEnd="10dp"
android:paddingStart="24dp"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="@+id/image_channel_icon"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/image_channel_icon"
app:layout_constraintTop_toTopOf="@+id/image_channel_icon" />
<ImageView
android:id="@+id/image_invite_member"
android:layout_width="14dp"
android:layout_height="14dp"
android:layout_marginTop="16dp"
android:src="@drawable/ic_at_black_24dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_channel_name" />
<EditText
android:id="@+id/text_invite_members"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="@color/colorDim"
android:hint="@string/msg_invite_members"
android:inputType="text"
android:maxLines="1"
android:paddingEnd="10dp"
android:paddingStart="24dp"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="@+id/image_invite_member"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/image_invite_member"
app:layout_constraintTop_toTopOf="@+id/image_invite_member" />
<android.support.constraint.ConstraintLayout
android:id="@+id/view_member_suggestion"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginEnd="12dp"
android:layout_marginStart="12dp"
android:background="@color/colorWhite"
android:elevation="2dp"
android:orientation="vertical"
android:visibility="gone"
app:layout_constraintBottom_toTopOf="@+id/text_invite_members">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
<com.wang.avi.AVLoadingIndicatorView
android:id="@+id/view_member_suggestion_loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:indicatorColor="@color/colorBlack"
app:indicatorName="BallPulseIndicator"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/text_member_not_found"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/msg_member_not_found"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
<android.support.design.chip.ChipGroup
android:id="@+id/chip_group_member"
style="@style/Widget.MaterialComponents.Chip.Entry"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:visibility="gone"
app:chipSpacing="3dp"
app:layout_constraintTop_toBottomOf="@+id/text_invite_members" />
</android.support.constraint.ConstraintLayout>
\ No newline at end of file
...@@ -19,17 +19,15 @@ ...@@ -19,17 +19,15 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textColor="@color/colorLightTheme" android:textColor="@color/colorLightTheme"
android:textSize="20sp" /> android:textSize="18sp" />
<TextView <TextView
android:id="@+id/toolbar_action_text" android:id="@+id/toolbar_action_text"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="16dp" android:layout_marginEnd="16dp"
android:alpha="0.7"
android:enabled="false"
android:gravity="end" android:gravity="end"
android:textSize="16sp" /> android:textSize="14sp" />
</android.support.v7.widget.Toolbar> </android.support.v7.widget.Toolbar>
......
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/action_create_channel"
android:icon="@drawable/ic_check_white_24dp"
android:title="@string/action_create" />
</menu>
\ No newline at end of file
...@@ -11,6 +11,16 @@ ...@@ -11,6 +11,16 @@
android:icon="@drawable/ic_chat_bubble_black_24dp" android:icon="@drawable/ic_chat_bubble_black_24dp"
android:title="@string/title_chats" /> android:title="@string/title_chats" />
<item
android:id="@+id/action_channel"
android:icon="@drawable/ic_create_black_24dp"
android:title="@string/action_create_channel" />
</group>
<group
android:id="@+id/menu_section_2"
android:checkableBehavior="single">
<item <item
android:id="@+id/action_profile" android:id="@+id/action_profile"
android:icon="@drawable/ic_person_black_24dp" android:icon="@drawable/ic_person_black_24dp"
...@@ -19,16 +29,16 @@ ...@@ -19,16 +29,16 @@
<item <item
android:id="@+id/action_settings" android:id="@+id/action_settings"
android:icon="@drawable/ic_settings_black_24dp" android:icon="@drawable/ic_settings_black_24dp"
android:title="@string/title_settings"/> android:title="@string/title_settings" />
</group> </group>
<group <group
android:id="@+id/menu_section_2" android:id="@+id/menu_section_3"
android:checkableBehavior="none"> android:checkableBehavior="single">
<item <item
android:id="@+id/action_logout" android:id="@+id/action_logout"
android:icon="@drawable/ic_exit_to_app_black_24dp" android:icon="@drawable/ic_exit_to_app_black_24dp"
android:title="@string/action_logout" /> android:title="@string/action_logout" />
</group> </group>
</menu> </menu>
\ No newline at end of file
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"> <menu xmlns:android="http://schemas.android.com/apk/res/android">
<item <item
android:id="@+id/action_profile" android:id="@+id/action_update_profile"
android:icon="@drawable/ic_check_white_24dp" android:icon="@drawable/ic_check_white_24dp"
android:title="@string/action_update" /> android:title="@string/action_update" />
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
<string name="title_update_profile">Actualización del perfil</string> <string name="title_update_profile">Actualización del perfil</string>
<string name="title_about">Acerca de</string> <string name="title_about">Acerca de</string>
// TODO: Add proper translation. // TODO: Add proper translation.
<string name="title_create_new_channel">Create New Channel</string> <string name="title_create_channel">Create Channel</string>
<string name="title_add_members">Invita a los miembros (%s)</string> <string name="title_add_members">Invita a los miembros (%s)</string>
<!-- Actions --> <!-- Actions -->
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
<string name="action_search">Buscar</string> <string name="action_search">Buscar</string>
<string name="action_update">Actualizar</string> <string name="action_update">Actualizar</string>
<string name="action_settings">Configuraciones</string> <string name="action_settings">Configuraciones</string>
// TODO: Add proper translation.
<string name="action_create_channel">Create channel</string>
<string name="action_logout">Cerrar sesión</string> <string name="action_logout">Cerrar sesión</string>
<string name="action_files">Archivos</string> <string name="action_files">Archivos</string>
<string name="action_confirm_password">Confirmar cambio de contraseña</string> <string name="action_confirm_password">Confirmar cambio de contraseña</string>
...@@ -130,11 +132,7 @@ ...@@ -130,11 +132,7 @@
<string name="msg_several_users_are_typing">Several users are typing…</string> <string name="msg_several_users_are_typing">Several users are typing…</string>
<string name="msg_no_search_found">No se han encontrado resultados</string> <string name="msg_no_search_found">No se han encontrado resultados</string>
// TODO: Add proper translation. // TODO: Add proper translation.
<string name="msg_member_already_added">You have already selected this user</string> <string name="msg_channel_name">Channel name</string>
// TODO: Add proper translation.
<string name="msg_channel_created_successfully">"Channel created successfully</string>
// TODO: Add proper translation.
<string name="msg_channel_name">Channel Name</string>
// TODO: Add proper translation. // TODO: Add proper translation.
<string name="msg_add_members">Add Members</string> <string name="msg_add_members">Add Members</string>
// TODO: Add proper translation. // TODO: Add proper translation.
...@@ -142,6 +140,20 @@ ...@@ -142,6 +140,20 @@
<string name="msg_message_copied">Mensaje copiado</string> <string name="msg_message_copied">Mensaje copiado</string>
<string name="msg_channel_name_required">Por favor ingrese un nombre de canal</string> <string name="msg_channel_name_required">Por favor ingrese un nombre de canal</string>
<!-- Create channel messages -->
// TODO: Add proper translation.
<string name="msg_private_channel">Private</string>
<string name="msg_public_channel">Public</string>
<string name="msg_private_channel_description">Only you and invited members can access this channel</string>
<string name="msg_public_channel_description">Everyone can access this channel</string>
<string name="msg_ready_only_channel">Read only channel</string>
<string name="msg_ready_only_channel_description">Only admin can write new messages</string>
<string name="msg_invite_members">Invite members to channel</string>
<string name="msg_member_already_added">You have already selected this user</string>
<string name="msg_member_not_found">Member not found</string>
<string name="msg_channel_created_successfully">Channel created successfully</string>
<!-- System messages --> <!-- System messages -->
<string name="message_room_name_changed">Nombre de la sala cambiado para: %1$s por %2$s</string> <string name="message_room_name_changed">Nombre de la sala cambiado para: %1$s por %2$s</string>
<string name="message_user_added_by">Usuario %1$s añadido por %2$s</string> <string name="message_user_added_by">Usuario %1$s añadido por %2$s</string>
...@@ -158,7 +170,6 @@ ...@@ -158,7 +170,6 @@
// TODO:Add proper translation. // TODO:Add proper translation.
<string name="message_credentials_saved_successfully">Credentials saved successfully</string> <string name="message_credentials_saved_successfully">Credentials saved successfully</string>
<!-- Message actions --> <!-- Message actions -->
<string name="action_msg_reply">Respuesta</string> <string name="action_msg_reply">Respuesta</string>
<string name="action_msg_edit">Editar</string> <string name="action_msg_edit">Editar</string>
...@@ -263,9 +274,4 @@ ...@@ -263,9 +274,4 @@
<string name="notif_action_reply_hint">RESPUESTA</string> <string name="notif_action_reply_hint">RESPUESTA</string>
<string name="notif_error_sending">La respuesta ha fallado. Inténtalo de nuevo.</string> <string name="notif_error_sending">La respuesta ha fallado. Inténtalo de nuevo.</string>
<string name="notif_success_sending">Mensaje enviado a %1$s!</string> <string name="notif_success_sending">Mensaje enviado a %1$s!</string>
<string name="private_channel_type">Privado</string>
<string name="public_channel_type">Público</string>
<string name="private_channel_type_description">Visible solo para ti y para aquellos a quienes invitas</string>
<string name="public_channel_description">Visible para todos</string>
</resources> </resources>
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
<string name="title_update_profile">Update profile</string> <string name="title_update_profile">Update profile</string>
<string name="title_about">Sur</string> <string name="title_about">Sur</string>
// TODO: Add proper translation. // TODO: Add proper translation.
<string name="title_create_new_channel">Create New Channel</string> <string name="title_create_channel">Create Channel</string>
<string name="title_add_members">Inviter des membres (%s)</string> <string name="title_add_members">Inviter des membres (%s)</string>
<!-- Actions --> <!-- Actions -->
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
<string name="action_search">Chercher</string> <string name="action_search">Chercher</string>
<string name="action_update">Mettre à jour</string> <string name="action_update">Mettre à jour</string>
<string name="action_settings">Paramètres</string> <string name="action_settings">Paramètres</string>
// TODO: Add proper translation.
<string name="action_create_channel">Create channel</string>
<string name="action_logout">Se déconnecter</string> <string name="action_logout">Se déconnecter</string>
<string name="action_files">Fichiers</string> <string name="action_files">Fichiers</string>
<string name="action_confirm_password">Confirmer le mot de passe</string> <string name="action_confirm_password">Confirmer le mot de passe</string>
...@@ -130,11 +132,7 @@ ...@@ -130,11 +132,7 @@
<string name="msg_several_users_are_typing">Several users are typing…</string> <string name="msg_several_users_are_typing">Several users are typing…</string>
<string name="msg_no_search_found">Aucun résultat trouvé</string> <string name="msg_no_search_found">Aucun résultat trouvé</string>
// TODO: Add proper translation. // TODO: Add proper translation.
<string name="msg_member_already_added">You have already selected this user</string> <string name="msg_channel_name">Channel name</string>
// TODO: Add proper translation.
<string name="msg_channel_created_successfully">"Channel created successfully</string>
// TODO: Add proper translation.
<string name="msg_channel_name">Channel Name</string>
// TODO: Add proper translation. // TODO: Add proper translation.
<string name="msg_add_members">Add Members</string> <string name="msg_add_members">Add Members</string>
// TODO: Add proper translation. // TODO: Add proper translation.
...@@ -142,6 +140,19 @@ ...@@ -142,6 +140,19 @@
<string name="msg_message_copied">Message copié</string> <string name="msg_message_copied">Message copié</string>
<string name="msg_channel_name_required">Veuillez entrer un nom de chaîne</string> <string name="msg_channel_name_required">Veuillez entrer un nom de chaîne</string>
<!-- Create channel messages -->
// TODO: Add proper translation.
<string name="msg_private_channel">Private</string>
<string name="msg_public_channel">Public</string>
<string name="msg_private_channel_description">Only you and invited members can access this channel</string>
<string name="msg_public_channel_description">Everyone can access this channel</string>
<string name="msg_ready_only_channel">Read only channel</string>
<string name="msg_ready_only_channel_description">Only admin can write new messages</string>
<string name="msg_invite_members">Invite members to channel</string>
<string name="msg_member_already_added">You have already selected this user</string>
<string name="msg_member_not_found">Member not found</string>
<string name="msg_channel_created_successfully">Channel created successfully</string>
<!-- System messages --> <!-- System messages -->
<string name="message_room_name_changed">Le nom de le salle a changé à: %1$s par %2$s</string> <string name="message_room_name_changed">Le nom de le salle a changé à: %1$s par %2$s</string>
<string name="message_user_added_by">Utilisateur %1$s ajouté par %2$s</string> <string name="message_user_added_by">Utilisateur %1$s ajouté par %2$s</string>
...@@ -155,10 +166,10 @@ ...@@ -155,10 +166,10 @@
<string name="message_unmuted">Utilisateur %1$s non muté par %2$s</string> <string name="message_unmuted">Utilisateur %1$s non muté par %2$s</string>
<string name="message_role_add">%1$s a été défini %2$s par %3$s</string> <string name="message_role_add">%1$s a été défini %2$s par %3$s</string>
<string name="message_role_removed">%1$s is no longer %2$s par %3$s</string> <string name="message_role_removed">%1$s is no longer %2$s par %3$s</string>
// TODO:Add proper translation. // TODO:Add proper translation.
<string name="message_credentials_saved_successfully">Credentials saved successfully</string> <string name="message_credentials_saved_successfully">Credentials saved successfully</string>
<!-- Message actions --> <!-- Message actions -->
<string name="action_msg_reply">Répondre</string> <string name="action_msg_reply">Répondre</string>
<string name="action_msg_edit">Modifier</string> <string name="action_msg_edit">Modifier</string>
...@@ -264,9 +275,4 @@ ...@@ -264,9 +275,4 @@
<string name="notif_action_reply_hint">RÉPONDRE</string> <string name="notif_action_reply_hint">RÉPONDRE</string>
<string name="notif_error_sending">La réponse a échoué. Veuillez réessayer.</string> <string name="notif_error_sending">La réponse a échoué. Veuillez réessayer.</string>
<string name="notif_success_sending">Message envoyé à %1$s!</string> <string name="notif_success_sending">Message envoyé à %1$s!</string>
<string name="private_channel_type">Privé</string>
<string name="public_channel_type">Public</string>
<string name="private_channel_type_description">Visible uniquement pour vous et ceux que vous invitez</string>
<string name="public_channel_description">Visible par tout le monde</string>
</resources> </resources>
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
<string name="title_update_profile">प्रोफ़ाइल अपडेट करें</string> <string name="title_update_profile">प्रोफ़ाइल अपडेट करें</string>
<string name="title_about">परिचय</string> <string name="title_about">परिचय</string>
// TODO: Add proper translation. // TODO: Add proper translation.
<string name="title_create_new_channel">Create New Channel</string> <string name="title_create_channel">Create Channel</string>
<string name="title_add_members">सदस्यों को आमंत्रित करें (%s)</string> <string name="title_add_members">सदस्यों को आमंत्रित करें (%s)</string>
<!-- Actions --> <!-- Actions -->
...@@ -29,6 +29,8 @@ ...@@ -29,6 +29,8 @@
<string name="action_search">खोजें</string> <string name="action_search">खोजें</string>
<string name="action_update">अद्यतन करें</string> <string name="action_update">अद्यतन करें</string>
<string name="action_settings">सेटिंग्स</string> <string name="action_settings">सेटिंग्स</string>
// TODO: Add proper translation.
<string name="action_create_channel">Create channel</string>
<string name="action_logout">लोग आउट करें</string> <string name="action_logout">लोग आउट करें</string>
<string name="action_files">फ़ाइलें</string> <string name="action_files">फ़ाइलें</string>
<string name="action_confirm_password">पासवर्ड परिवर्तन की पुष्टि करें</string> <string name="action_confirm_password">पासवर्ड परिवर्तन की पुष्टि करें</string>
...@@ -132,11 +134,7 @@ ...@@ -132,11 +134,7 @@
<string name="msg_several_users_are_typing">Several users are typing…</string> <string name="msg_several_users_are_typing">Several users are typing…</string>
<string name="msg_no_search_found">कोई परिणाम नहीं मिला</string> <string name="msg_no_search_found">कोई परिणाम नहीं मिला</string>
// TODO: Add proper translation. // TODO: Add proper translation.
<string name="msg_member_already_added">You have already selected this user</string> <string name="msg_channel_name">Channel name</string>
// TODO: Add proper translation.
<string name="msg_channel_created_successfully">"Channel created successfully</string>
// TODO: Add proper translation.
<string name="msg_channel_name">Channel Name</string>
// TODO: Add proper translation. // TODO: Add proper translation.
<string name="msg_add_members">Add Members</string> <string name="msg_add_members">Add Members</string>
// TODO: Add proper translation. // TODO: Add proper translation.
...@@ -144,6 +142,19 @@ ...@@ -144,6 +142,19 @@
<string name="msg_message_copied">संदेश कॉपी किया गया</string> <string name="msg_message_copied">संदेश कॉपी किया गया</string>
<string name="msg_channel_name_required">कृपया एक चैनल नाम दर्ज करें</string> <string name="msg_channel_name_required">कृपया एक चैनल नाम दर्ज करें</string>
<!-- Create channel messages -->
// TODO: Add proper translation.
<string name="msg_private_channel">Private</string>
<string name="msg_public_channel">Public</string>
<string name="msg_private_channel_description">Only you and invited members can access this channel</string>
<string name="msg_public_channel_description">Everyone can access this channel</string>
<string name="msg_ready_only_channel">Read only channel</string>
<string name="msg_ready_only_channel_description">Only admin can write new messages</string>
<string name="msg_invite_members">Invite members to channel</string>
<string name="msg_member_already_added">You have already selected this user</string>
<string name="msg_member_not_found">Member not found</string>
<string name="msg_channel_created_successfully">Channel created successfully</string>
<!-- System messages --> <!-- System messages -->
<string name="message_room_name_changed">%2$s ने रूम का नाम बदलकर %1$s किया</string> <string name="message_room_name_changed">%2$s ने रूम का नाम बदलकर %1$s किया</string>
<string name="message_user_added_by">उपयोगकर्ता %1$s द्वारा %2$s को जोड़ा गया</string> <string name="message_user_added_by">उपयोगकर्ता %1$s द्वारा %2$s को जोड़ा गया</string>
...@@ -265,9 +276,4 @@ ...@@ -265,9 +276,4 @@
<string name="notif_action_reply_hint">जवाब</string> <string name="notif_action_reply_hint">जवाब</string>
<string name="notif_error_sending">उत्तर विफल हुआ है। कृपया फिर से प्रयास करें।</string> <string name="notif_error_sending">उत्तर विफल हुआ है। कृपया फिर से प्रयास करें।</string>
<string name="notif_success_sending">संदेश भेजा गया %1$s!</string> <string name="notif_success_sending">संदेश भेजा गया %1$s!</string>
<string name="private_channel_type">निजी</string>
<string name="public_channel_type">सार्वजनिक</string>
<string name="private_channel_type_description">केवल आप के लिए दृश्यमान और जिन्हें आप आमंत्रित करते हैं</string>
<string name="public_channel_description">हर किसी के लिए दृश्यमान</string>
</resources> </resources>
\ No newline at end of file
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
<string name="title_update_profile">Editar perfil</string> <string name="title_update_profile">Editar perfil</string>
<string name="title_about">Sobre</string> <string name="title_about">Sobre</string>
// TODO: Add proper translation. // TODO: Add proper translation.
<string name="title_create_new_channel">Create New Channel</string> <string name="title_create_channel">Create Channel</string>
<string name="title_add_members">Convidar membros (%s)</string> <string name="title_add_members">Convidar membros (%s)</string>
<!-- Actions --> <!-- Actions -->
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
<string name="action_search">Pesquisar</string> <string name="action_search">Pesquisar</string>
<string name="action_update">Atualizar</string> <string name="action_update">Atualizar</string>
<string name="action_settings">Configurações</string> <string name="action_settings">Configurações</string>
// TODO: Add proper translation.
<string name="action_create_channel">Create channel</string>
<string name="action_logout">Sair</string> <string name="action_logout">Sair</string>
<string name="action_files">Arquivos</string> <string name="action_files">Arquivos</string>
<string name="action_confirm_password">Confirme a nova senha</string> <string name="action_confirm_password">Confirme a nova senha</string>
...@@ -121,19 +123,25 @@ ...@@ -121,19 +123,25 @@
<string name="msg_are_typing">\u0020estão digitando…</string> <string name="msg_are_typing">\u0020estão digitando…</string>
<string name="msg_several_users_are_typing">Vários usuários estão digitando…</string> <string name="msg_several_users_are_typing">Vários usuários estão digitando…</string>
<string name="msg_no_search_found">nenhum resultado encontrado</string> <string name="msg_no_search_found">nenhum resultado encontrado</string>
// TODO: Add proper translation. <string name="msg_channel_name">Nome do chat</string>
<string name="msg_member_already_added">You have already selected this user</string> <string name="msg_add_members">Adcionar membros</string>
// TODO: Add proper translation. <string name="msg_search">Buscar</string>
<string name="msg_channel_created_successfully">"Channel created successfully</string>
// TODO: Add proper translation.
<string name="msg_channel_name">Channel Name</string>
// TODO: Add proper translation.
<string name="msg_add_members">Add Members</string>
// TODO: Add proper translation.
<string name="msg_search">Search</string>
<string name="msg_message_copied">Mensagem copiada</string> <string name="msg_message_copied">Mensagem copiada</string>
<string name="msg_channel_name_required">Por favor insira um nome de canal</string> <string name="msg_channel_name_required">Por favor insira um nome de canal</string>
<!-- Create channel messages -->
// TODO: Add proper translation.
<string name="msg_private_channel">Private</string>
<string name="msg_public_channel">Public</string>
<string name="msg_private_channel_description">Only you and invited members can access this channel</string>
<string name="msg_public_channel_description">Everyone can access this channel</string>
<string name="msg_ready_only_channel">Read only channel</string>
<string name="msg_ready_only_channel_description">Only admin can write new messages</string>
<string name="msg_invite_members">Invite members to channel</string>
<string name="msg_member_already_added">You have already selected this user</string>
<string name="msg_member_not_found">Member not found</string>
<string name="msg_channel_created_successfully">Channel created successfully</string>
<!-- System messages --> <!-- System messages -->
<string name="message_room_name_changed">Nome da sala alterado para: %1$s por %2$s</string> <string name="message_room_name_changed">Nome da sala alterado para: %1$s por %2$s</string>
<string name="message_user_added_by">Usuário %1$s adicionado por %2$s</string> <string name="message_user_added_by">Usuário %1$s adicionado por %2$s</string>
...@@ -251,9 +259,4 @@ ...@@ -251,9 +259,4 @@
<string name="notif_action_reply_hint">RESPONDER</string> <string name="notif_action_reply_hint">RESPONDER</string>
<string name="notif_error_sending">Falha ao enviar a mensagem.</string> <string name="notif_error_sending">Falha ao enviar a mensagem.</string>
<string name="notif_success_sending">Mensagem enviada para %1$s!</string> <string name="notif_success_sending">Mensagem enviada para %1$s!</string>
<string name="private_channel_type">Privado</string>
<string name="public_channel_type">Público</string>
<string name="private_channel_type_description">Visível apenas para você e para aqueles a quem você convida</string>
<string name="public_channel_description">Visível para todos</string>
</resources> </resources>
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
<string name="title_password">Изменить пароль</string> <string name="title_password">Изменить пароль</string>
<string name="title_update_profile">Обновить профиль</string> <string name="title_update_profile">Обновить профиль</string>
<string name="title_about">О программе</string> <string name="title_about">О программе</string>
<string name="title_create_new_channel">Створити новий канал</string> <string name="title_create_channel">Створити новий канал</string>
<string name="title_add_members">Запросити учасників (%s)</string> <string name="title_add_members">Запросити учасників (%s)</string>
<!-- Actions --> <!-- Actions -->
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
<string name="action_search">Поиск</string> <string name="action_search">Поиск</string>
<string name="action_update">Обновить</string> <string name="action_update">Обновить</string>
<string name="action_settings">Настройки</string> <string name="action_settings">Настройки</string>
// TODO: Add proper translation.
<string name="action_create_channel">Create channel</string>
<string name="action_logout">Выйти</string> <string name="action_logout">Выйти</string>
<string name="action_files">Файлы</string> <string name="action_files">Файлы</string>
<string name="action_confirm_password">Подтверждение изменения пароля</string> <string name="action_confirm_password">Подтверждение изменения пароля</string>
...@@ -115,18 +117,23 @@ ...@@ -115,18 +117,23 @@
<string name="msg_several_users_are_typing">Несколько пользователей печатают…</string> <string name="msg_several_users_are_typing">Несколько пользователей печатают…</string>
<string name="msg_no_search_found">Результатов не найдено</string> <string name="msg_no_search_found">Результатов не найдено</string>
<string name="msg_message_copied">Сообщение скопировано</string> <string name="msg_message_copied">Сообщение скопировано</string>
<string name="msg_channel_created_successfully">Канал створений успішно</string>
<string name="msg_channel_name">Назва каналу</string> <string name="msg_channel_name">Назва каналу</string>
<string name="msg_add_members">Додати членів</string> <string name="msg_add_members">Додати членів</string>
<string name="msg_search">Пошук</string> <string name="msg_search">Пошук</string>
<string name="msg_member_already_added">Ви вже вибрали цього користувача</string>
<string name="msg_channel_name_required">Будь ласка, введіть назву каналу</string> <string name="msg_channel_name_required">Будь ласка, введіть назву каналу</string>
<!--info for creating a channel--> <!-- Create channel messages -->
<string name="private_channel_type">Приватно</string> // TODO: Add proper translation.
<string name="public_channel_type">Громадський</string> <string name="msg_private_channel">Private</string>
<string name="private_channel_type_description">Видно лише вам та тими, кого ви запрошуєте</string> <string name="msg_public_channel">Public</string>
<string name="public_channel_description">Видимий для всіх</string> <string name="msg_private_channel_description">Only you and invited members can access this channel</string>
<string name="msg_public_channel_description">Everyone can access this channel</string>
<string name="msg_ready_only_channel">Read only channel</string>
<string name="msg_ready_only_channel_description">Only admin can write new messages</string>
<string name="msg_invite_members">Invite members to channel</string>
<string name="msg_member_already_added">You have already selected this user</string>
<string name="msg_member_not_found">Member not found</string>
<string name="msg_channel_created_successfully">Channel created successfully</string>
<!-- System messages --> <!-- System messages -->
<string name="message_room_name_changed">Название канала изменено на: %1$s by %2$s</string> <string name="message_room_name_changed">Название канала изменено на: %1$s by %2$s</string>
......
...@@ -15,8 +15,7 @@ ...@@ -15,8 +15,7 @@
<string name="title_settings">Settings</string> <string name="title_settings">Settings</string>
<string name="title_password">Change Password</string> <string name="title_password">Change Password</string>
<string name="title_update_profile">Update profile</string> <string name="title_update_profile">Update profile</string>
<string name="title_create_new_channel">Create New Channel</string> <string name="title_create_channel">Create Channel</string>
<string name="title_add_members">Invite Members (%s)</string>
<string name="title_about">About</string> <string name="title_about">About</string>
<!-- Actions --> <!-- Actions -->
...@@ -27,7 +26,9 @@ ...@@ -27,7 +26,9 @@
<string name="action_privacy_policy">Privacy Policy</string> <string name="action_privacy_policy">Privacy Policy</string>
<string name="action_search">Search</string> <string name="action_search">Search</string>
<string name="action_update">Update</string> <string name="action_update">Update</string>
<string name="action_create">Create</string>
<string name="action_settings">Settings</string> <string name="action_settings">Settings</string>
<string name="action_create_channel">Create channel</string>
<string name="action_logout">Logout</string> <string name="action_logout">Logout</string>
<string name="action_files">Files</string> <string name="action_files">Files</string>
<string name="action_confirm_password">Confirm Password Change</string> <string name="action_confirm_password">Confirm Password Change</string>
...@@ -51,7 +52,6 @@ ...@@ -51,7 +52,6 @@
<string name="msg_generic_error">Sorry, an error has occurred, please try again</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_no_data_to_display">No data to display</string>
<string name="msg_profile_update_successfully">Profile update successfully</string> <string name="msg_profile_update_successfully">Profile update successfully</string>
<string name="msg_channel_created_successfully">"Channel created successfully</string>
<string name="msg_username">username</string> <string name="msg_username">username</string>
<string name="msg_username_or_email">username or email</string> <string name="msg_username_or_email">username or email</string>
<string name="msg_password">password</string> <string name="msg_password">password</string>
...@@ -88,7 +88,7 @@ ...@@ -88,7 +88,7 @@
<string name="msg_utc_offset">UTC offset</string> <string name="msg_utc_offset">UTC offset</string>
<string name="msg_new_password">Enter New Password</string> <string name="msg_new_password">Enter New Password</string>
<string name="msg_confirm_password">Confirm New Password</string> <string name="msg_confirm_password">Confirm New Password</string>
<string name="msg_channel_name">Channel Name</string> <string name="msg_channel_name">Channel name</string>
<string name="msg_add_members">Add Members</string> <string name="msg_add_members">Add Members</string>
<string name="msg_search">Search</string> <string name="msg_search">Search</string>
<string name="msg_unread_messages">Unread messages</string> <string name="msg_unread_messages">Unread messages</string>
...@@ -122,14 +122,20 @@ ...@@ -122,14 +122,20 @@
<string name="msg_are_typing">\u0020are typing…</string> <string name="msg_are_typing">\u0020are typing…</string>
<string name="msg_several_users_are_typing">Several users are typing…</string> <string name="msg_several_users_are_typing">Several users are typing…</string>
<string name="msg_no_search_found">No result found</string> <string name="msg_no_search_found">No result found</string>
<string name="msg_member_already_added">You have already selected this user</string>
<string name="msg_channel_name_required">Please enter a channel name</string> <string name="msg_channel_name_required">Please enter a channel name</string>
<!--info for creating a channel--> <!-- Create channel messages -->
<string name="private_channel_type">Private</string> <string name="msg_private_channel">Private</string>
<string name="public_channel_type">Public</string> <string name="msg_public_channel">Public</string>
<string name="private_channel_type_description">Visible only to you and those whom you invite</string> <string name="msg_private_channel_description">Only you and invited members can access this channel</string>
<string name="public_channel_description">Visible to everyone</string> <string name="msg_public_channel_description">Everyone can access this channel</string>
<string name="msg_ready_only_channel">Read only channel</string>
<string name="msg_ready_only_channel_description">Only admin can write new messages</string>
<string name="msg_invite_members">Invite members to channel</string>
<string name="msg_member_already_added">You have already selected this user</string>
<string name="msg_member_not_found">Member not found</string>
<string name="msg_channel_created_successfully">Channel created successfully</string>
<string name="msg_message_copied">Message copied</string> <string name="msg_message_copied">Message copied</string>
<!-- System messages --> <!-- System messages -->
......
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