Commit 590aedde authored by Filipe de Lima Brito's avatar Filipe de Lima Brito

Merge branch 'feature/compress-image' of...

Merge branch 'feature/compress-image' of github.com:RocketChat/Rocket.Chat.Android into feature/compress-image
parents c7c89643 af2a52f0
package chat.rocket.android.chatroom.adapter
import android.app.AlertDialog
import android.content.Context
import androidx.recyclerview.widget.RecyclerView
import android.view.MenuItem
import android.view.ViewGroup
......@@ -18,7 +20,8 @@ class ChatRoomAdapter(
private val roomName: String? = null,
private val presenter: ChatRoomPresenter? = null,
private val enableActions: Boolean = true,
private val reactionListener: EmojiReactionListener? = null
private val reactionListener: EmojiReactionListener? = null,
private val context: Context? = null
) : RecyclerView.Adapter<BaseViewHolder<*>>() {
private val dataSet = ArrayList<BaseUiModel<*>>()
......@@ -233,7 +236,16 @@ class ChatRoomAdapter(
presenter?.unpinMessage(id)
}
}
R.id.action_message_delete -> presenter?.deleteMessage(roomId, id)
R.id.action_message_delete -> {
context?.let {
val builder = AlertDialog.Builder(it)
builder.setTitle(it.getString(R.string.msg_delete_message))
.setMessage(it.getString(R.string.msg_delete_description))
.setPositiveButton(it.getString(R.string.msg_ok)) { _, _ -> presenter?.deleteMessage(roomId, id) }
.setNegativeButton(it.getString(R.string.msg_cancel)) { _, _ -> }
.show()
}
}
R.id.action_menu_msg_react -> presenter?.showReactions(id)
else -> TODO("Not implemented")
}
......
......@@ -257,7 +257,8 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
chatRoomType,
chatRoomName,
presenter,
reactionListener = this@ChatRoomFragment
reactionListener = this@ChatRoomFragment,
context = context
)
recycler_view.adapter = adapter
if (dataSet.size >= 30) {
......@@ -407,7 +408,6 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
override fun showNewMessage(message: List<BaseUiModel<*>>) {
ui {
adapter.prependData(message)
recycler_view.scrollToPosition(0)
verticalScrollOffset.set(0)
empty_chat_view.isVisible = adapter.itemCount == 0
}
......
......@@ -239,8 +239,7 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
}
}
override suspend fun updateChatRooms(newDataSet: List<ChatRoom>) {
}
override suspend fun updateChatRooms(newDataSet: List<ChatRoom>) {}
override fun showNoChatRoomsToDisplay() {
ui { text_no_data_to_display.setVisible(true) }
......
package chat.rocket.android.createchannel.di
import androidx.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
class CreateChannelModule {
@Provides
@PerFragment
fun createChannelView(fragment: CreateChannelFragment): CreateChannelView {
return fragment
}
@Provides
@PerFragment
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 chat.rocket.android.dagger.scope.PerFragment
import dagger.Module
import dagger.android.ContributesAndroidInjector
@Module
abstract class CreateChannelProvider {
@ContributesAndroidInjector(modules = [CreateChannelModule::class])
@PerFragment
abstract fun provideCreateChannelFragment(): CreateChannelFragment
}
\ No newline at end of file
package chat.rocket.android.createchannel.presentation
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.main.presentation.MainNavigator
import chat.rocket.android.members.uimodel.MemberUiModelMapper
import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.extensions.launchUI
import chat.rocket.common.RocketChatException
import chat.rocket.common.model.RoomType
import chat.rocket.common.util.ifNull
import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.rest.createChannel
import chat.rocket.core.internal.rest.spotlight
import javax.inject.Inject
class CreateChannelPresenter @Inject constructor(
private val view: CreateChannelView,
private val strategy: CancelStrategy,
private val mapper: MemberUiModelMapper,
private val navigator: MainNavigator,
val serverInteractor: GetCurrentServerInteractor,
val factory: RocketChatClientFactory
) {
private val client: RocketChatClient = factory.create(serverInteractor.get()!!)
fun createChannel(
roomType: RoomType,
channelName: String,
usersList: List<String>,
readOnly: Boolean
) {
launchUI(strategy) {
view.showLoading()
view.disableUserInput()
try {
client.createChannel(roomType, channelName, usersList, readOnly)
view.prepareToShowChatList()
view.showChannelCreatedSuccessfullyMessage()
toChatList()
} catch (exception: RocketChatException) {
exception.message?.let {
view.showMessage(it)
}.ifNull {
view.showGenericErrorMessage()
}
} finally {
view.hideLoading()
view.enableUserInput()
}
}
}
fun searchUser(query: String) {
launchUI(strategy) {
view.showSuggestionViewInProgress()
try {
val users = client.spotlight(query).users
if (users.isEmpty()) {
view.showNoUserSuggestion()
} else {
view.showUserSuggestion(mapper.mapToUiModelList(users))
}
} catch (ex: RocketChatException) {
ex.message?.let {
view.showMessage(it)
}.ifNull {
view.showGenericErrorMessage()
}
} finally {
view.hideSuggestionViewInProgress()
}
}
}
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.uimodel.MemberUiModel
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<MemberUiModel>)
/**
* Shows no server's users suggestion.
*/
fun showNoUserSuggestion()
/**
* Shows the SuggestionView in progress.
*/
fun showSuggestionViewInProgress()
/**
* Hides the progress shown in the SuggestionView.
*/
fun hideSuggestionViewInProgress()
/**
* 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.view.*
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.view.ActionMode
import androidx.core.view.isVisible
import androidx.core.view.postDelayed
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
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.uimodel.MemberUiModel
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 chat.rocket.common.model.roomTypeOf
import com.google.android.material.chip.Chip
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: String = 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 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(
roomTypeOf(channelType),
text_channel_name.text.toString(),
memberList,
isChannelReadOnly
)
mode.finish()
true
}
else -> {
false
}
}
}
override fun onDestroyActionMode(mode: ActionMode) {
actionMode = null
}
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<MemberUiModel>) {
adapter.clearData()
adapter.prependData(dataSet)
text_member_not_found.isVisible = false
recycler_view.isVisible = true
view_member_suggestion.isVisible = true
}
override fun showNoUserSuggestion() {
recycler_view.isVisible = false
text_member_not_found.isVisible = true
view_member_suggestion.isVisible = true
}
override fun showSuggestionViewInProgress() {
recycler_view.isVisible = false
text_member_not_found.isVisible = false
view_member_suggestion_loading.isVisible = true
view_member_suggestion.isVisible = true
}
override fun hideSuggestionViewInProgress() {
view_member_suggestion_loading.isVisible = false
}
override fun prepareToShowChatList() {
with(activity as MainActivity) {
setCheckedNavDrawerItem(R.id.action_chat_rooms)
openDrawer()
getDrawerLayout().postDelayed(1000) {
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
}
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())
.filter { t -> t.isNotBlank() }
.subscribe {
if (it.length >= 3) {
createChannelPresenter.searchUser(it.toString())
} else {
view_member_suggestion.isVisible = false
}
}
compositeDisposable.addAll(channelNameDisposable, inviteMembersDisposable)
}
private fun unsubscribeEditTexts() {
compositeDisposable.dispose()
}
private fun startActionMode() {
if (actionMode == null) {
actionMode = (activity as AppCompatActivity).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 {
view_member_suggestion.isVisible = false
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()
}
}
\ No newline at end of file
......@@ -13,6 +13,7 @@ import chat.rocket.android.chatroom.di.ChatRoomModule
import chat.rocket.android.chatroom.di.FavoriteMessagesFragmentProvider
import chat.rocket.android.chatroom.ui.ChatRoomActivity
import chat.rocket.android.chatrooms.di.ChatRoomsFragmentProvider
import chat.rocket.android.createchannel.di.CreateChannelProvider
import chat.rocket.android.dagger.scope.PerActivity
import chat.rocket.android.files.di.FilesFragmentProvider
import chat.rocket.android.main.di.MainModule
......@@ -22,6 +23,7 @@ import chat.rocket.android.pinnedmessages.di.PinnedMessagesFragmentProvider
import chat.rocket.android.profile.di.ProfileFragmentProvider
import chat.rocket.android.server.di.ChangeServerModule
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.ui.PasswordActivity
import dagger.Module
......@@ -47,7 +49,9 @@ abstract class ActivityBuilder {
@ContributesAndroidInjector(
modules = [MainModule::class,
ChatRoomsFragmentProvider::class,
ProfileFragmentProvider::class
CreateChannelProvider::class,
ProfileFragmentProvider::class,
SettingsFragmentProvider::class
]
)
abstract fun bindMainActivity(): MainActivity
......
......@@ -4,6 +4,7 @@ import chat.rocket.android.R
import chat.rocket.android.authentication.ui.newServerIntent
import chat.rocket.android.chatroom.ui.chatRoomIntent
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.profile.ui.ProfileFragment
import chat.rocket.android.server.ui.changeServerIntent
......@@ -18,6 +19,12 @@ class MainNavigator(internal val activity: MainActivity) {
}
}
fun toCreateChannel() {
activity.addFragment("CreateChannelFragment", R.id.fragment_container) {
CreateChannelFragment.newInstance()
}
}
fun toUserProfile() {
activity.addFragment("ProfileFragment", R.id.fragment_container) {
ProfileFragment.newInstance()
......@@ -30,15 +37,26 @@ class MainNavigator(internal val activity: MainActivity) {
}
}
fun toChatRoom(chatRoomId: String,
fun toChatRoom(
chatRoomId: String,
chatRoomName: String,
chatRoomType: String,
isChatRoomReadOnly: Boolean,
chatRoomLastSeen: Long,
isChatRoomSubscribed: Boolean,
isChatRoomCreator: Boolean) {
activity.startActivity(activity.chatRoomIntent(chatRoomId, chatRoomName, chatRoomType,
isChatRoomReadOnly, chatRoomLastSeen, isChatRoomSubscribed, isChatRoomCreator))
isChatRoomCreator: Boolean
) {
activity.startActivity(
activity.chatRoomIntent(
chatRoomId,
chatRoomName,
chatRoomType,
isChatRoomReadOnly,
chatRoomLastSeen,
isChatRoomSubscribed,
isChatRoomCreator
)
)
activity.overridePendingTransition(R.anim.open_enter, R.anim.open_exit)
}
......
......@@ -55,6 +55,8 @@ class MainPresenter @Inject constructor(
fun toSettings() = navigator.toSettings()
fun toCreateChannel() = navigator.toCreateChannel()
fun loadCurrentInfo() {
checkServerInfo(currentServer)
launchUI(strategy) {
......
......@@ -10,6 +10,8 @@ import androidx.recyclerview.widget.LinearLayoutManager
import android.view.Gravity
import android.view.MenuItem
import android.view.View
import androidx.annotation.IdRes
import androidx.drawerlayout.widget.DrawerLayout
import chat.rocket.android.BuildConfig
import chat.rocket.android.R
import chat.rocket.android.main.adapter.AccountsAdapter
......@@ -185,14 +187,14 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector,
setSupportActionBar(toolbar)
toolbar.setNavigationIcon(R.drawable.ic_menu_white_24dp)
toolbar.setNavigationOnClickListener {
drawer_layout.openDrawer(Gravity.START)
openDrawer()
}
}
private fun setupNavigationView() {
view_navigation.setNavigationItemSelectedListener { menuItem ->
menuItem.isChecked = true
drawer_layout.closeDrawer(Gravity.START)
closeDrawer()
onNavDrawerItemSelected(menuItem)
true
}
......@@ -206,6 +208,9 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector,
R.id.action_profile -> {
presenter.toUserProfile()
}
R.id.action_channel -> {
presenter.toCreateChannel()
}
R.id.action_settings -> {
presenter.toSettings()
}
......@@ -243,9 +248,25 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector,
}
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()
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
package chat.rocket.android.members.adapter
import androidx.recyclerview.widget.RecyclerView
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import chat.rocket.android.R
import chat.rocket.android.members.uimodel.MemberUiModel
import chat.rocket.android.util.extensions.content
......@@ -10,15 +10,23 @@ import chat.rocket.android.util.extensions.inflate
import kotlinx.android.synthetic.main.avatar.view.*
import kotlinx.android.synthetic.main.item_member.view.*
class MembersAdapter(private val listener: (MemberUiModel) -> Unit) : RecyclerView.Adapter<MembersAdapter.ViewHolder>() {
class MembersAdapter(private val listener: (MemberUiModel) -> Unit) :
RecyclerView.Adapter<MembersAdapter.ViewHolder>() {
private var dataSet: List<MemberUiModel> = ArrayList()
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
fun clearData() {
dataSet = emptyList()
notifyDataSetChanged()
}
fun prependData(dataSet: List<MemberUiModel>) {
this.dataSet = dataSet
notifyItemRangeInserted(0, dataSet.size)
......@@ -35,7 +43,6 @@ class MembersAdapter(private val listener: (MemberUiModel) -> Unit) : RecyclerVi
fun bind(memberUiModel: MemberUiModel, listener: (MemberUiModel) -> Unit) = with(itemView) {
image_avatar.setImageURI(memberUiModel.avatarUri)
text_member.content = memberUiModel.displayName
setOnClickListener { listener(memberUiModel) }
}
}
......
package chat.rocket.android.members.di
import chat.rocket.android.dagger.scope.PerFragment
import chat.rocket.android.members.ui.MembersFragment
import chat.rocket.android.dagger.scope.PerFragment
import dagger.Module
import dagger.android.ContributesAndroidInjector
......
......@@ -5,7 +5,11 @@ import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.common.model.User
import chat.rocket.core.model.Value
class MemberUiModel(private val member: User, private val settings: Map<String, Value<Any>>, private val baseUrl: String?) {
class MemberUiModel(
private val member: User,
private val settings: Map<String, Value<Any>>,
private val baseUrl: String?
) {
val avatarUri: String?
val displayName: String
val realName: String?
......
......@@ -13,20 +13,21 @@ import chat.rocket.android.profile.presentation.ProfilePresenter
import chat.rocket.android.profile.presentation.ProfileView
import chat.rocket.android.util.extensions.*
import dagger.android.support.AndroidSupportInjection
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import io.reactivex.rxkotlin.Observables
import kotlinx.android.synthetic.main.avatar_profile.*
import kotlinx.android.synthetic.main.fragment_profile.*
import javax.inject.Inject
class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
@Inject lateinit var presenter: ProfilePresenter
@Inject
lateinit var presenter: ProfilePresenter
private lateinit var currentName: String
private lateinit var currentUsername: String
private lateinit var currentEmail: String
private lateinit var currentAvatar: String
private var actionMode: ActionMode? = null
private val disposables = CompositeDisposable()
private lateinit var editTextsDisposable: Disposable
companion object {
fun newInstance() = ProfileFragment()
......@@ -37,7 +38,11 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
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?) {
super.onViewCreated(view, savedInstanceState)
......@@ -51,8 +56,8 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
}
override fun onDestroyView() {
disposables.clear()
super.onDestroyView()
unsubscribeEditTexts()
}
override fun showProfile(avatarUrl: String, name: String, username: String, email: String?) {
......@@ -71,7 +76,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
profile_container.setVisible(true)
listenToChanges()
subscribeEditTexts()
}
}
......@@ -119,8 +124,13 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
override fun onActionItemClicked(mode: ActionMode, menuItem: MenuItem): Boolean {
return when (menuItem.itemId) {
R.id.action_profile -> {
presenter.updateUserProfile(text_email.textContent, text_name.textContent, text_username.textContent, text_avatar_url.textContent)
R.id.action_update_profile -> {
presenter.updateUserProfile(
text_email.textContent,
text_name.textContent,
text_username.textContent,
text_avatar_url.textContent
)
mode.finish()
true
}
......@@ -135,28 +145,36 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
}
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() {
(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 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 drawables = arrayOf(personDrawable, atDrawable, emailDrawable, linkDrawable)
DrawableHelper.wrapDrawables(drawables)
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() {
disposables.add(Observables.combineLatest(text_name.asObservable(),
private fun subscribeEditTexts() {
editTextsDisposable = Observables.combineLatest(
text_name.asObservable(),
text_username.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 ||
text_username.toString() != currentUsername ||
text_email.toString() != currentEmail ||
......@@ -167,7 +185,11 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
} else {
finishActionMode()
}
})
}
}
private fun unsubscribeEditTexts() {
editTextsDisposable.dispose()
}
private fun startActionMode() {
......
......@@ -11,6 +11,7 @@ import kotlinx.coroutines.experimental.Job
@Module
class SettingsFragmentModule {
@Provides
@PerFragment
fun settingsView(frag: SettingsFragment): SettingsView {
......
......@@ -6,6 +6,7 @@ import dagger.android.ContributesAndroidInjector
@Module
abstract class SettingsFragmentProvider {
@ContributesAndroidInjector(modules = [SettingsFragmentModule::class])
abstract fun provideSettingsFragment(): SettingsFragment
}
\ No newline at end of file
......@@ -16,16 +16,19 @@ import chat.rocket.android.util.extensions.inflate
import kotlinx.android.synthetic.main.fragment_settings.*
import kotlin.reflect.KClass
class SettingsFragment: Fragment(), SettingsView, AdapterView.OnItemClickListener {
class SettingsFragment : Fragment(), SettingsView, AdapterView.OnItemClickListener {
companion object {
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?) {
super.onViewCreated(view, savedInstanceState)
setupToolbar()
setupListView()
}
......@@ -34,7 +37,8 @@ class SettingsFragment: Fragment(), SettingsView, AdapterView.OnItemClickListene
when (parent?.getItemAtPosition(position).toString()) {
resources.getString(R.string.title_password) -> {
startNewActivity(PasswordActivity::class)
}resources.getString(R.string.title_about) -> {
}
resources.getString(R.string.title_about) -> {
startNewActivity(AboutActivity::class)
}
}
......@@ -45,7 +49,8 @@ class SettingsFragment: Fragment(), SettingsView, AdapterView.OnItemClickListene
}
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>) {
......
......@@ -4,10 +4,10 @@ import android.widget.EditText
import com.jakewharton.rxbinding2.widget.RxTextView
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import java.util.concurrent.TimeUnit
import io.reactivex.schedulers.Schedulers
fun EditText.asObservable(): Observable<CharSequence> {
return RxTextView.textChanges(this)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(AndroidSchedulers.mainThread())
}
\ No newline at end of file
package chat.rocket.android.widget.autocompletion.ui
import android.content.Context
import androidx.recyclerview.widget.RecyclerView
import android.util.AttributeSet
import android.util.DisplayMetrics
import android.view.WindowManager
import androidx.recyclerview.widget.RecyclerView
import chat.rocket.android.R
internal class PopupRecyclerView : RecyclerView {
private var displayWidth: Int = 0
constructor(context: Context) : this(context, null)
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(context: Context, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle) {
val wm = context!!.getSystemService(Context.WINDOW_SERVICE) as WindowManager
constructor(context: Context, attrs: AttributeSet?, defStyle: Int) : super(
context,
attrs,
defStyle
) {
val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
val display = wm.defaultDisplay
val size = DisplayMetrics()
display.getMetrics(size)
......@@ -23,8 +26,11 @@ internal class PopupRecyclerView : RecyclerView {
}
override fun onMeasure(widthSpec: Int, heightSpec: Int) {
val hSpec = MeasureSpec.makeMeasureSpec(resources.getDimensionPixelSize(
R.dimen.popup_max_height), MeasureSpec.AT_MOST)
val hSpec = MeasureSpec.makeMeasureSpec(
resources.getDimensionPixelSize(
R.dimen.popup_max_height
), MeasureSpec.AT_MOST
)
val wSpec = MeasureSpec.makeMeasureSpec(displayWidth, MeasureSpec.EXACTLY)
super.onMeasure(wSpec, hSpec)
}
......
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="@color/colorWhite"
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
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 xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
</vector>
......@@ -2,7 +2,6 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid
android:color="@color/colorAccent" />
<solid android:color="@color/colorAccent" />
</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="#10000000" />
<corners android:radius="5dp" />
<size android:height="2dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
android:id="@+id/toolbar_layout"
layout="@layout/layout_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent" />
<android.support.constraint.ConstraintLayout
android:id="@+id/layout_container"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/toolbar_layout">
<android.support.design.chip.ChipGroup
android:id="@+id/members_chips"
style="@style/Widget.MaterialComponents.Chip.Entry"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:visibility="gone"
app:chipSpacing="3dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
</android.support.design.chip.ChipGroup>
<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/colorPrimary"
app:indicatorName="BallPulseIndicator"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/text_search_member"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="@android:color/transparent"
android:hint="@string/msg_search"
android:paddingBottom="8dp"
android:paddingEnd="8dp"
android:paddingStart="8dp"
app:layout_constraintTop_toBottomOf="@id/members_chips" />
<View
android:id="@+id/separator_1"
android:layout_width="match_parent"
android:layout_height="0.2dp"
android:background="@color/colorDividerMessageComposer"
app:layout_constraintTop_toBottomOf="@id/text_search_member" />
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:scrollbars="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/separator_1" />
</android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout>
\ No newline at end of file
......@@ -19,6 +19,8 @@
<include
android:id="@+id/picker_container"
layout="@layout/emoji_picker"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/emoji_actions_container"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
......
......@@ -46,14 +46,13 @@
tools:visibility="visible" />
<TextView
android:id="@+id/text_no_search"
android:id="@+id/text_no_result_found"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="56dp"
android:text="@string/msg_no_search_found"
android:textSize="20sp"
android:layout_centerHorizontal="true"
android:visibility="gone"
tools:visibility="visible" />
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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" />
<androidx.constraintlayout.widget.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">
<androidx.recyclerview.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" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.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" />
</androidx.constraintlayout.widget.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"
android:id="@+id/toolbar_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="@dimen/toolbar_height"
android:background="@color/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<TextView
android:id="@+id/toolbar_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/colorLightTheme"
android:textSize="18sp" />
<TextView
android:id="@+id/toolbar_action_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:gravity="end"
android:textSize="14sp" />
</android.support.v7.widget.Toolbar>
</android.support.constraint.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/action_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 @@
android:icon="@drawable/ic_chat_bubble_black_24dp"
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
android:id="@+id/action_profile"
android:icon="@drawable/ic_person_black_24dp"
......@@ -19,16 +29,16 @@
<item
android:id="@+id/action_settings"
android:icon="@drawable/ic_settings_black_24dp"
android:title="@string/title_settings"/>
android:title="@string/title_settings" />
</group>
<group
android:id="@+id/menu_section_2"
android:checkableBehavior="none">
android:id="@+id/menu_section_3"
android:checkableBehavior="single">
<item
android:id="@+id/action_logout"
android:icon="@drawable/ic_exit_to_app_black_24dp"
android:title="@string/action_logout" />
</group>
</menu>
\ No newline at end of file
......@@ -2,7 +2,7 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/action_profile"
android:id="@+id/action_update_profile"
android:icon="@drawable/ic_check_white_24dp"
android:title="@string/action_update" />
......
......@@ -15,6 +15,8 @@
<string name="title_password">Cambia la contraseña</string>
<string name="title_update_profile">Actualización del perfil</string>
<string name="title_about">Acerca de</string>
// TODO: Add proper translation.
<string name="title_create_channel">Create Channel</string>
<!-- Actions -->
<string name="action_connect">Conectar</string>
......@@ -25,6 +27,9 @@
<string name="action_search">Buscar</string>
<string name="action_update">Actualizar</string>
<string name="action_settings">Configuraciones</string>
// TODO: Add proper translation.
<string name="action_create_channel">Create channel</string>
<string name="action_create">Create</string>
<string name="action_logout">Cerrar sesión</string>
<string name="action_files">Archivos</string>
<string name="action_confirm_password">Confirmar cambio de contraseña</string>
......@@ -37,7 +42,6 @@
// TODO: Add proper translation.
<string name="action_save_to_gallery">Save to gallery</string>
<!-- Settings List -->
<string-array name="settings_actions">
<item name="item_password">Cambia la contraseña</item>
......@@ -123,7 +127,28 @@
// TODO: Add proper translation.
<string name="msg_several_users_are_typing">Several users are typing…</string>
<string name="msg_no_search_found">No se han encontrado resultados</string>
// TODO: Add proper translation.
<string name="msg_channel_name">Channel name</string>
// TODO: Add proper translation.
<string name="msg_search">Search</string>
<string name="msg_message_copied">Mensaje copiado</string>
// TODO: Add proper translation.
<string name="msg_delete_message">Delete Message</string>
<string name="msg_delete_description">Are you sure you want to delete this message</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 -->
<string name="message_room_name_changed">Nombre de la sala cambiado para: %1$s por %2$s</string>
......@@ -141,7 +166,6 @@
// TODO:Add proper translation.
<string name="message_credentials_saved_successfully">Credentials saved successfully</string>
<!-- Message actions -->
<string name="action_msg_reply">Respuesta</string>
<string name="action_msg_edit">Editar</string>
......
......@@ -15,6 +15,8 @@
<string name="title_password">Changer le mot de passe</string>
<string name="title_update_profile">Update profile</string>
<string name="title_about">Sur</string>
// TODO: Add proper translation.
<string name="title_create_channel">Create Channel</string>
<!-- Actions -->
<string name="action_connect">Se connecter</string>
......@@ -25,6 +27,9 @@
<string name="action_search">Chercher</string>
<string name="action_update">Mettre à jour</string>
<string name="action_settings">Paramètres</string>
// TODO: Add proper translation.
<string name="action_create_channel">Create channel</string>
<string name="action_create">Create</string>
<string name="action_logout">Se déconnecter</string>
<string name="action_files">Fichiers</string>
<string name="action_confirm_password">Confirmer le mot de passe</string>
......@@ -122,7 +127,27 @@
// TODO: Add proper translation.
<string name="msg_several_users_are_typing">Several users are typing…</string>
<string name="msg_no_search_found">Aucun résultat trouvé</string>
// TODO: Add proper translation.
<string name="msg_channel_name">Channel name</string>
// TODO: Add proper translation.
<string name="msg_search">Search</string>
<string name="msg_message_copied">Message copié</string>
// TODO: Add proper translation.
<string name="msg_delete_message">Delete Message</string>
<string name="msg_delete_description">Are you sure you want to delete this message</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 -->
<string name="message_room_name_changed">Le nom de le salle a changé à: %1$s par %2$s</string>
......@@ -137,10 +162,10 @@
<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_removed">%1$s is no longer %2$s par %3$s</string>
// TODO:Add proper translation.
<string name="message_credentials_saved_successfully">Credentials saved successfully</string>
<!-- Message actions -->
<string name="action_msg_reply">Répondre</string>
<string name="action_msg_edit">Modifier</string>
......
......@@ -15,6 +15,8 @@
<string name="title_password">पासवर्ड बदलें</string>
<string name="title_update_profile">प्रोफ़ाइल अपडेट करें</string>
<string name="title_about">परिचय</string>
// TODO: Add proper translation.
<string name="title_create_channel">Create Channel</string>
<!-- Actions -->
<string name="action_connect">जुडिये</string>
......@@ -25,6 +27,9 @@
<string name="action_search">खोजें</string>
<string name="action_update">अद्यतन करें</string>
<string name="action_settings">सेटिंग्स</string>
// TODO: Add proper translation.
<string name="action_create_channel">Create channel</string>
<string name="action_create">Create</string>
<string name="action_logout">लोग आउट करें</string>
<string name="action_files">फ़ाइलें</string>
<string name="action_confirm_password">पासवर्ड परिवर्तन की पुष्टि करें</string>
......@@ -113,7 +118,26 @@
<string name="msg_are_typing">\u0020टाइप कर रहे हैं…</string>
<string name="msg_several_users_are_typing">कई उपयोगकर्ता टाइप कर रहे हैं…</string>
<string name="msg_no_search_found">कोई परिणाम नहीं मिला</string>
// TODO: Add proper translation.
<string name="msg_channel_name">Channel name</string>
// TODO: Add proper translation.
<string name="msg_search">Search</string>
<string name="msg_message_copied">संदेश कॉपी किया गया</string>
<string name="msg_delete_message">संदेश को हटाएं</string>
<string name="msg_delete_description">क्या आप निश्चित रूप से यह संदेश हटाना चाहते हैं</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 -->
<string name="message_room_name_changed">%2$s ने रूम का नाम बदलकर %1$s किया</string>
......
......@@ -15,6 +15,7 @@
<string name="title_password">Alterar senha</string>
<string name="title_update_profile">Editar perfil</string>
<string name="title_about">Sobre</string>
<string name="title_create_channel">Criar chat</string>
<!-- Actions -->
<string name="action_connect">Conectar</string>
......@@ -25,6 +26,8 @@
<string name="action_search">Pesquisar</string>
<string name="action_update">Atualizar</string>
<string name="action_settings">Configurações</string>
<string name="action_create_channel">Criar chat</string>
<string name="action_create">Criar</string>
<string name="action_logout">Sair</string>
<string name="action_files">Arquivos</string>
<string name="action_confirm_password">Confirme a nova senha</string>
......@@ -113,7 +116,24 @@
<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_no_search_found">nenhum resultado encontrado</string>
<string name="msg_channel_name">Nome do chat</string>
<string name="msg_search">Buscar</string>
<string name="msg_message_copied">Mensagem copiada</string>
// TODO: Add proper translation.
<string name="msg_delete_message">Delete Message</string>
<string name="msg_delete_description">Are you sure you want to delete this message</string>
<!-- Create channel messages -->
<string name="msg_private_channel">Privado</string>
<string name="msg_public_channel">Público</string>
<string name="msg_private_channel_description">Somente você e membros convidados poderão acessar este chat</string>
<string name="msg_public_channel_description">Todos poderão acessar este canal</string>
<string name="msg_ready_only_channel">Read only channel</string>
<string name="msg_ready_only_channel_description">Somemnte administradores podem escrever mensagens</string>
<string name="msg_invite_members">Convidar membros para o chat</string>
<string name="msg_member_already_added">Você já selecionou este usuário</string>
<string name="msg_member_not_found">Membro não encontrado</string>
<string name="msg_channel_created_successfully">Chat criado com sucesso</string>
<!-- System messages -->
<string name="message_room_name_changed">Nome da sala alterado para: %1$s por %2$s</string>
......
......@@ -15,6 +15,7 @@
<string name="title_password">Изменить пароль</string>
<string name="title_update_profile">Обновить профиль</string>
<string name="title_about">О программе</string>
<string name="title_create_channel">Створити новий канал</string>
<!-- Actions -->
<string name="action_connect">Соединение</string>
......@@ -25,6 +26,9 @@
<string name="action_search">Поиск</string>
<string name="action_update">Обновить</string>
<string name="action_settings">Настройки</string>
// TODO: Add proper translation.
<string name="action_create_channel">Create channel</string>
<string name="action_create">Create</string>
<string name="action_logout">Выйти</string>
<string name="action_files">Файлы</string>
<string name="action_confirm_password">Подтверждение изменения пароля</string>
......@@ -113,6 +117,24 @@
<string name="msg_several_users_are_typing">Несколько пользователей печатают…</string>
<string name="msg_no_search_found">Результатов не найдено</string>
<string name="msg_message_copied">Сообщение скопировано</string>
// TODO: Add proper translation.
<string name="msg_delete_message">Delete Message</string>
<string name="msg_delete_description">Are you sure you want to delete this message</string>
<string name="msg_channel_name">Назва каналу</string>
<string name="msg_search">Пошук</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 -->
<string name="message_room_name_changed">Название канала изменено на: %1$s by %2$s</string>
......
......@@ -32,6 +32,9 @@
<dimen name="picker_popup_height">250dp</dimen>
<dimen name="picker_popup_width">300dp</dimen>
<!--Toolbar-->
<dimen name="toolbar_height">56dp</dimen>
<!-- Message -->
<dimen name="padding_quote">8dp</dimen>
<dimen name="padding_mention">4dp</dimen>
......
......@@ -16,6 +16,7 @@
<string name="title_password">Change Password</string>
<string name="title_update_profile">Update profile</string>
<string name="title_about">About</string>
<string name="title_create_channel">Create Channel</string>
<!-- Actions -->
<string name="action_connect">Connect</string>
......@@ -26,6 +27,8 @@
<string name="action_search">Search</string>
<string name="action_update">Update</string>
<string name="action_settings">Settings</string>
<string name="action_create_channel">Create channel</string>
<string name="action_create">Create</string>
<string name="action_logout">Logout</string>
<string name="action_files">Files</string>
<string name="action_confirm_password">Confirm Password Change</string>
......@@ -83,6 +86,8 @@
<string name="msg_utc_offset">UTC offset</string>
<string name="msg_new_password">Enter New Password</string>
<string name="msg_confirm_password">Confirm New Password</string>
<string name="msg_channel_name">Channel name</string>
<string name="msg_search">Search</string>
<string name="msg_unread_messages">Unread messages</string>
<string name="msg_preview_video">Video</string>
<string name="msg_preview_audio">Audio</string>
......@@ -114,7 +119,22 @@
<string name="msg_are_typing">\u0020are typing…</string>
<string name="msg_several_users_are_typing">Several users are typing…</string>
<string name="msg_no_search_found">No result found</string>
<!-- Create channel messages -->
<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>
<string name="msg_message_copied">Message copied</string>
<string name="msg_delete_message">Delete Message</string>
<string name="msg_delete_description">Are you sure you want to delete this message</string>
<!-- System messages -->
<string name="message_room_name_changed">Room name changed to: %1$s by %2$s</string>
......
......@@ -11,6 +11,10 @@
<item name="windowActionModeOverlay">true</item>
</style>
<style name="ToolbarTheme" parent="Base.Widget.AppCompat.Toolbar">
<item name="android:colorAccent">@color/colorLightTheme</item>
</style>
<style name="AuthenticationTheme" parent="Theme.AppCompat.NoActionBar">
<item name="android:statusBarColor">@color/colorPrimaryDark</item>
<item name="android:windowBackground">@color/colorPrimary</item>
......
#Wed Sep 06 11:04:56 UYT 2017
#Fri May 18 17:08:16 IST 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
......
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