mirror of
https://github.com/nextcloud/talk-android
synced 2025-07-20 19:25:01 +01:00
Initial new group conversation view
Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
parent
8fef0c314b
commit
e3451342f3
@ -353,7 +353,7 @@ class CallController(args: Bundle) : BaseController() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onNext(roomsOverall: RoomsOverall) {
|
override fun onNext(roomsOverall: RoomsOverall) {
|
||||||
for (conversation in roomsOverall?.ocs?.data!!) {
|
for (conversation in roomsOverall.ocs?.data!!) {
|
||||||
if (roomId == conversation.conversationId) {
|
if (roomId == conversation.conversationId) {
|
||||||
roomToken = conversation.token.toString()
|
roomToken = conversation.token.toString()
|
||||||
break
|
break
|
||||||
|
@ -241,7 +241,7 @@ class CallNotificationController(private val originalBundle: Bundle) : BaseContr
|
|||||||
override fun onSubscribe(d: Disposable) {}
|
override fun onSubscribe(d: Disposable) {}
|
||||||
|
|
||||||
override fun onNext(roomsOverall: RoomsOverall) {
|
override fun onNext(roomsOverall: RoomsOverall) {
|
||||||
for (conversation in roomsOverall.ocs.data!!) {
|
for (conversation in roomsOverall.ocs.data) {
|
||||||
if (roomId == conversation.conversationId) {
|
if (roomId == conversation.conversationId) {
|
||||||
currentConversation = conversation
|
currentConversation = conversation
|
||||||
runAllThings()
|
runAllThings()
|
||||||
|
@ -260,7 +260,7 @@ class ChatController(args: Bundle) : BaseController(), MessagesListAdapter
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onNext(roomsOverall: RoomsOverall) {
|
override fun onNext(roomsOverall: RoomsOverall) {
|
||||||
for (conversation in roomsOverall.ocs.data!!) {
|
for (conversation in roomsOverall.ocs.data) {
|
||||||
if (roomId == conversation.conversationId) {
|
if (roomId == conversation.conversationId) {
|
||||||
roomToken = conversation.token
|
roomToken = conversation.token
|
||||||
currentConversation = conversation
|
currentConversation = conversation
|
||||||
|
@ -31,6 +31,7 @@ import android.view.ViewGroup
|
|||||||
import android.view.inputmethod.EditorInfo
|
import android.view.inputmethod.EditorInfo
|
||||||
import android.view.inputmethod.InputMethodManager
|
import android.view.inputmethod.InputMethodManager
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
|
import android.widget.ProgressBar
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.appcompat.app.ActionBar
|
import androidx.appcompat.app.ActionBar
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
@ -87,6 +88,17 @@ abstract class BaseController : ButterKnifeController(), ComponentCallbacks {
|
|||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected val toolbarProgressBar: View?
|
||||||
|
get() {
|
||||||
|
var view: ProgressBar? = null
|
||||||
|
activity?.let {
|
||||||
|
if (it is MainActivity) {
|
||||||
|
view = it.toolbarProgressBar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected val floatingActionButton: FloatingActionButton?
|
protected val floatingActionButton: FloatingActionButton?
|
||||||
get() {
|
get() {
|
||||||
@ -127,6 +139,7 @@ abstract class BaseController : ButterKnifeController(), ComponentCallbacks {
|
|||||||
actionBar?.setIcon(null)
|
actionBar?.setIcon(null)
|
||||||
setOptionsMenuHidden(true)
|
setOptionsMenuHidden(true)
|
||||||
if (changeType == ControllerChangeType.POP_EXIT || changeType == ControllerChangeType.PUSH_EXIT) {
|
if (changeType == ControllerChangeType.POP_EXIT || changeType == ControllerChangeType.PUSH_EXIT) {
|
||||||
|
toolbarProgressBar?.isVisible = false
|
||||||
activity?.inputEditText?.text = null
|
activity?.inputEditText?.text = null
|
||||||
searchLayout?.searchProgressBar?.isVisible = false
|
searchLayout?.searchProgressBar?.isVisible = false
|
||||||
floatingActionButton?.isVisible = false
|
floatingActionButton?.isVisible = false
|
||||||
|
@ -158,8 +158,8 @@ class ChatMessage : IMessage, MessageContentType, MessageContentType.Image {
|
|||||||
}
|
}
|
||||||
return ApiUtils.getUrlForFilePreviewWithFileId(activeUser!!.baseUrl,
|
return ApiUtils.getUrlForFilePreviewWithFileId(activeUser!!.baseUrl,
|
||||||
individualHashMap["id"], sharedApplication
|
individualHashMap["id"], sharedApplication
|
||||||
!!.resources
|
!!.resources
|
||||||
!!.getDimensionPixelSize(R.dimen.maximum_file_preview_size))
|
!!.getDimensionPixelSize(R.dimen.maximum_file_preview_size))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -197,27 +197,27 @@ class ChatMessage : IMessage, MessageContentType, MessageContentType.Image {
|
|||||||
sharedApplication!!.getString(R.string.nc_sent_a_gif_you)
|
sharedApplication!!.getString(R.string.nc_sent_a_gif_you)
|
||||||
} else {
|
} else {
|
||||||
String.format(sharedApplication
|
String.format(sharedApplication
|
||||||
!!.getResources()
|
!!.resources
|
||||||
.getString(R.string.nc_sent_a_gif),
|
.getString(R.string.nc_sent_a_gif),
|
||||||
if (!TextUtils.isEmpty(actorDisplayName)) actorDisplayName else sharedApplication
|
if (!TextUtils.isEmpty(actorDisplayName)) actorDisplayName else sharedApplication
|
||||||
!!.getString(R.string.nc_guest))
|
!!.getString(R.string.nc_guest))
|
||||||
}
|
}
|
||||||
} else if (messageType == MessageType.SINGLE_NC_ATTACHMENT_MESSAGE) {
|
} else if (messageType == MessageType.SINGLE_NC_ATTACHMENT_MESSAGE) {
|
||||||
return if (actorId.equals(activeUser!!.userId)) {
|
return if (actorId.equals(activeUser!!.userId)) {
|
||||||
sharedApplication!!.resources.getString(R.string.nc_sent_an_attachment_you)
|
sharedApplication!!.resources.getString(R.string.nc_sent_an_attachment_you)
|
||||||
} else {
|
} else {
|
||||||
String.format(sharedApplication
|
String.format(sharedApplication
|
||||||
!!.resources
|
!!.resources
|
||||||
.getString(R.string.nc_sent_an_attachment),
|
.getString(R.string.nc_sent_an_attachment),
|
||||||
if (!TextUtils.isEmpty(actorDisplayName)) actorDisplayName else sharedApplication
|
if (!TextUtils.isEmpty(actorDisplayName)) actorDisplayName else sharedApplication
|
||||||
!!.getString(R.string.nc_guest))
|
!!.getString(R.string.nc_guest))
|
||||||
}
|
}
|
||||||
} else if (messageType == MessageType.SINGLE_LINK_MESSAGE) {
|
} else if (messageType == MessageType.SINGLE_LINK_MESSAGE) {
|
||||||
return if (actorId.equals(activeUser!!.userId)) {
|
return if (actorId.equals(activeUser!!.userId)) {
|
||||||
sharedApplication!!.resources.getString(R.string.nc_sent_a_link_you)
|
sharedApplication!!.resources.getString(R.string.nc_sent_a_link_you)
|
||||||
} else {
|
} else {
|
||||||
String.format(sharedApplication
|
String.format(sharedApplication
|
||||||
!! .getResources()
|
!!.resources
|
||||||
.getString(R.string.nc_sent_a_link),
|
.getString(R.string.nc_sent_a_link),
|
||||||
if (!TextUtils.isEmpty(actorDisplayName)) actorDisplayName else sharedApplication!!.getString(R.string.nc_guest))
|
if (!TextUtils.isEmpty(actorDisplayName)) actorDisplayName else sharedApplication!!.getString(R.string.nc_guest))
|
||||||
}
|
}
|
||||||
@ -226,30 +226,30 @@ class ChatMessage : IMessage, MessageContentType, MessageContentType.Image {
|
|||||||
sharedApplication!!.resources.getString(R.string.nc_sent_an_audio_you)
|
sharedApplication!!.resources.getString(R.string.nc_sent_an_audio_you)
|
||||||
} else {
|
} else {
|
||||||
String.format(sharedApplication
|
String.format(sharedApplication
|
||||||
!!.getResources()
|
!!.resources
|
||||||
.getString(R.string.nc_sent_an_audio),
|
.getString(R.string.nc_sent_an_audio),
|
||||||
if (!TextUtils.isEmpty(actorDisplayName)) actorDisplayName else sharedApplication
|
if (!TextUtils.isEmpty(actorDisplayName)) actorDisplayName else sharedApplication
|
||||||
!!.getString(R.string.nc_guest))
|
!!.getString(R.string.nc_guest))
|
||||||
}
|
}
|
||||||
} else if (messageType == MessageType.SINGLE_LINK_VIDEO_MESSAGE) {
|
} else if (messageType == MessageType.SINGLE_LINK_VIDEO_MESSAGE) {
|
||||||
return if (actorId.equals(activeUser!!.userId)) {
|
return if (actorId.equals(activeUser!!.userId)) {
|
||||||
sharedApplication!!.resources.getString(R.string.nc_sent_a_video_you)
|
sharedApplication!!.resources.getString(R.string.nc_sent_a_video_you)
|
||||||
} else {
|
} else {
|
||||||
String.format(sharedApplication
|
String.format(sharedApplication
|
||||||
!!.resources
|
!!.resources
|
||||||
.getString(R.string.nc_sent_a_video),
|
.getString(R.string.nc_sent_a_video),
|
||||||
if (!TextUtils.isEmpty(actorDisplayName)) actorDisplayName else sharedApplication
|
if (!TextUtils.isEmpty(actorDisplayName)) actorDisplayName else sharedApplication
|
||||||
!!.getString(R.string.nc_guest))
|
!!.getString(R.string.nc_guest))
|
||||||
}
|
}
|
||||||
} else if (messageType == MessageType.SINGLE_LINK_IMAGE_MESSAGE) {
|
} else if (messageType == MessageType.SINGLE_LINK_IMAGE_MESSAGE) {
|
||||||
return if (actorId.equals(activeUser!!.userId)) {
|
return if (actorId.equals(activeUser!!.userId)) {
|
||||||
sharedApplication!!.getString(R.string.nc_sent_an_image_you)
|
sharedApplication!!.getString(R.string.nc_sent_an_image_you)
|
||||||
} else {
|
} else {
|
||||||
String.format(sharedApplication
|
String.format(sharedApplication
|
||||||
!!.getResources()
|
!!.resources
|
||||||
.getString(R.string.nc_sent_an_image),
|
.getString(R.string.nc_sent_an_image),
|
||||||
if (!TextUtils.isEmpty(actorDisplayName)) actorDisplayName else sharedApplication
|
if (!TextUtils.isEmpty(actorDisplayName)) actorDisplayName else sharedApplication
|
||||||
!!.getString(R.string.nc_guest))
|
!!.getString(R.string.nc_guest))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,6 +93,10 @@ class NextcloudTalkRepositoryImpl(private val apiService: ApiService) : Nextclou
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun setPasswordForConversation(user: UserNgEntity, conversationToken: String, password: String): GenericOverall {
|
||||||
|
return apiService.setPasswordForConversation(user.getCredentials(), ApiUtils.getUrlForPassword(user.baseUrl, conversationToken), password)
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun addParticipantToConversation(user: UserNgEntity, conversationToken: String, participantId: String, source: String): AddParticipantOverall {
|
override suspend fun addParticipantToConversation(user: UserNgEntity, conversationToken: String, participantId: String, source: String): AddParticipantOverall {
|
||||||
return apiService.addParticipant(user.getCredentials(), ApiUtils.getUrlForParticipants(user.baseUrl, conversationToken), participantId, source)
|
return apiService.addParticipant(user.getCredentials(), ApiUtils.getUrlForParticipants(user.baseUrl, conversationToken), participantId, source)
|
||||||
}
|
}
|
||||||
@ -102,7 +106,7 @@ class NextcloudTalkRepositoryImpl(private val apiService: ApiService) : Nextclou
|
|||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getContactsForUser(user: UserNgEntity, groupConversation: Boolean, searchQuery: String?, conversationToken: String?): List<Participant> {
|
override suspend fun getContactsForUser(user: UserNgEntity, groupConversation: Boolean, searchQuery: String?, conversationToken: String?): List<Participant> {
|
||||||
return apiService.getContacts(authorization = user.getCredentials(), url = ApiUtils.getUrlForContactsSearch(user.baseUrl), shareTypes = ApiUtils.getShareTypesForContactsSearch(groupConversation), options = ApiUtils.getQueryMapForContactsSearch(searchQuery, conversationToken)).ocs.data.map {
|
return apiService.getContacts(authorization = user.getCredentials(), url = ApiUtils.getUrlForContactsSearch(user.baseUrl), shareTypes = ApiUtils.getShareTypesForContactsSearch(user, groupConversation), options = ApiUtils.getQueryMapForContactsSearch(searchQuery, conversationToken)).ocs.data.map {
|
||||||
val participant = Participant()
|
val participant = Participant()
|
||||||
participant.userId = it.id
|
participant.userId = it.id
|
||||||
participant.displayName = it.label
|
participant.displayName = it.label
|
||||||
|
@ -34,6 +34,12 @@ import com.nextcloud.talk.models.json.userprofile.UserProfileOverall
|
|||||||
import retrofit2.http.*
|
import retrofit2.http.*
|
||||||
|
|
||||||
interface ApiService {
|
interface ApiService {
|
||||||
|
@FormUrlEncoded
|
||||||
|
@PUT
|
||||||
|
suspend fun setPasswordForConversation(@Header("Authorization") authorization: String,
|
||||||
|
@Url url: String?,
|
||||||
|
@Field("password") password: String): GenericOverall
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
suspend fun addParticipant(@Header("Authorization") authorization: String,
|
suspend fun addParticipant(@Header("Authorization") authorization: String,
|
||||||
@Url url: String,
|
@Url url: String,
|
||||||
|
@ -50,9 +50,15 @@ val UseCasesModule = module {
|
|||||||
single { createGetContactsUseCase(get(), get()) }
|
single { createGetContactsUseCase(get(), get()) }
|
||||||
single { createCreateConversationUseCase(get(), get()) }
|
single { createCreateConversationUseCase(get(), get()) }
|
||||||
single { createAddParticipantToConversationUseCase(get(), get()) }
|
single { createAddParticipantToConversationUseCase(get(), get()) }
|
||||||
|
single { setConversationPasswordUseCase(get(), get()) }
|
||||||
factory { createChatViewModelFactory(get(), get(), get(), get(), get(), get()) }
|
factory { createChatViewModelFactory(get(), get(), get(), get(), get(), get()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setConversationPasswordUseCase(nextcloudTalkRepository: NextcloudTalkRepository,
|
||||||
|
apiErrorHandler: ApiErrorHandler): SetConversationPasswordUseCase {
|
||||||
|
return SetConversationPasswordUseCase(nextcloudTalkRepository, apiErrorHandler)
|
||||||
|
}
|
||||||
|
|
||||||
fun createAddParticipantToConversationUseCase(nextcloudTalkRepository: NextcloudTalkRepository,
|
fun createAddParticipantToConversationUseCase(nextcloudTalkRepository: NextcloudTalkRepository,
|
||||||
apiErrorHandler: ApiErrorHandler): AddParticipantToConversationUseCase {
|
apiErrorHandler: ApiErrorHandler): AddParticipantToConversationUseCase {
|
||||||
return AddParticipantToConversationUseCase(nextcloudTalkRepository, apiErrorHandler)
|
return AddParticipantToConversationUseCase(nextcloudTalkRepository, apiErrorHandler)
|
||||||
|
@ -34,6 +34,7 @@ import com.nextcloud.talk.models.json.userprofile.UserProfileOverall
|
|||||||
import com.nextcloud.talk.newarch.local.models.UserNgEntity
|
import com.nextcloud.talk.newarch.local.models.UserNgEntity
|
||||||
|
|
||||||
interface NextcloudTalkRepository {
|
interface NextcloudTalkRepository {
|
||||||
|
suspend fun setPasswordForConversation(user: UserNgEntity, conversationToken: String, password: String): GenericOverall
|
||||||
suspend fun addParticipantToConversation(user: UserNgEntity, conversationToken: String, participantId: String, source: String): AddParticipantOverall
|
suspend fun addParticipantToConversation(user: UserNgEntity, conversationToken: String, participantId: String, source: String): AddParticipantOverall
|
||||||
suspend fun createConversationForUser(user: UserNgEntity, conversationType: Int, invite: String?, source: String?, conversationName: String?): ConversationOverall
|
suspend fun createConversationForUser(user: UserNgEntity, conversationType: Int, invite: String?, source: String?, conversationName: String?): ConversationOverall
|
||||||
suspend fun getContactsForUser(user: UserNgEntity, groupConversation: Boolean, searchQuery: String?, conversationToken: String?): List<Participant>
|
suspend fun getContactsForUser(user: UserNgEntity, groupConversation: Boolean, searchQuery: String?, conversationToken: String?): List<Participant>
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* * Nextcloud Talk application
|
||||||
|
* *
|
||||||
|
* * @author Mario Danic
|
||||||
|
* * Copyright (C) 2017-2020 Mario Danic <mario@lovelyhq.com>
|
||||||
|
* *
|
||||||
|
* * This program is free software: you can redistribute it and/or modify
|
||||||
|
* * it under the terms of the GNU General Public License as published by
|
||||||
|
* * the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* * at your option) any later version.
|
||||||
|
* *
|
||||||
|
* * This program is distributed in the hope that it will be useful,
|
||||||
|
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* * GNU General Public License for more details.
|
||||||
|
* *
|
||||||
|
* * You should have received a copy of the GNU General Public License
|
||||||
|
* * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.nextcloud.talk.newarch.domain.usecases
|
||||||
|
|
||||||
|
import com.nextcloud.talk.models.json.generic.GenericOverall
|
||||||
|
import com.nextcloud.talk.newarch.data.source.remote.ApiErrorHandler
|
||||||
|
import com.nextcloud.talk.newarch.domain.repository.online.NextcloudTalkRepository
|
||||||
|
import com.nextcloud.talk.newarch.domain.usecases.base.UseCase
|
||||||
|
import org.koin.core.parameter.DefinitionParameters
|
||||||
|
|
||||||
|
class SetConversationPasswordUseCase constructor(
|
||||||
|
private val nextcloudTalkRepository: NextcloudTalkRepository,
|
||||||
|
apiErrorHandler: ApiErrorHandler?
|
||||||
|
) : UseCase<GenericOverall, Any?>(apiErrorHandler) {
|
||||||
|
|
||||||
|
override suspend fun run(params: Any?): GenericOverall {
|
||||||
|
val definitionParameters = params as DefinitionParameters
|
||||||
|
return nextcloudTalkRepository.setPasswordForConversation(
|
||||||
|
definitionParameters[0],
|
||||||
|
definitionParameters[1],
|
||||||
|
definitionParameters[2]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -20,7 +20,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.nextcloud.talk.newarch.features.contactsflow.contacts
|
package com.nextcloud.talk.newarch.features.contactsflow
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@ -28,7 +28,9 @@ enum class ContactsViewOperationState {
|
|||||||
WAITING,
|
WAITING,
|
||||||
PROCESSING,
|
PROCESSING,
|
||||||
OK,
|
OK,
|
||||||
CONVERSATION_CREATION_FAILED
|
CONVERSATION_CREATION_FAILED,
|
||||||
|
CONVERSATION_CREATED_WITH_MISSING_TOKEN,
|
||||||
|
CONVERSATION_PASSWORD_NOT_SET
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
@ -37,6 +37,8 @@ import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
|
|||||||
import com.nextcloud.talk.R
|
import com.nextcloud.talk.R
|
||||||
import com.nextcloud.talk.controllers.ChatController
|
import com.nextcloud.talk.controllers.ChatController
|
||||||
import com.nextcloud.talk.models.json.participants.Participant
|
import com.nextcloud.talk.models.json.participants.Participant
|
||||||
|
import com.nextcloud.talk.newarch.features.contactsflow.ContactsViewOperationState
|
||||||
|
import com.nextcloud.talk.newarch.features.contactsflow.groupconversation.GroupConversationView
|
||||||
import com.nextcloud.talk.newarch.features.contactsflow.source.FixedListSource
|
import com.nextcloud.talk.newarch.features.contactsflow.source.FixedListSource
|
||||||
import com.nextcloud.talk.newarch.features.search.DebouncingTextWatcher
|
import com.nextcloud.talk.newarch.features.search.DebouncingTextWatcher
|
||||||
import com.nextcloud.talk.newarch.mvvm.BaseView
|
import com.nextcloud.talk.newarch.mvvm.BaseView
|
||||||
@ -224,7 +226,9 @@ class ContactsView(private val bundle: Bundle? = null) : BaseView() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (element.type == ParticipantElementType.PARTICIPANT_NEW_GROUP.ordinal) {
|
} else if (element.type == ParticipantElementType.PARTICIPANT_NEW_GROUP.ordinal) {
|
||||||
|
router.replaceTopController(RouterTransaction.with(GroupConversationView())
|
||||||
|
.popChangeHandler(HorizontalChangeHandler())
|
||||||
|
.pushChangeHandler(HorizontalChangeHandler()))
|
||||||
} else if (element.type == ParticipantElementType.PARTICIPANT_JOIN_VIA_LINK.ordinal) {
|
} else if (element.type == ParticipantElementType.PARTICIPANT_JOIN_VIA_LINK.ordinal) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,8 @@ import com.nextcloud.talk.newarch.domain.usecases.AddParticipantToConversationUs
|
|||||||
import com.nextcloud.talk.newarch.domain.usecases.CreateConversationUseCase
|
import com.nextcloud.talk.newarch.domain.usecases.CreateConversationUseCase
|
||||||
import com.nextcloud.talk.newarch.domain.usecases.GetContactsUseCase
|
import com.nextcloud.talk.newarch.domain.usecases.GetContactsUseCase
|
||||||
import com.nextcloud.talk.newarch.domain.usecases.base.UseCaseResponse
|
import com.nextcloud.talk.newarch.domain.usecases.base.UseCaseResponse
|
||||||
|
import com.nextcloud.talk.newarch.features.contactsflow.ContactsViewOperationState
|
||||||
|
import com.nextcloud.talk.newarch.features.contactsflow.ContactsViewOperationStateWrapper
|
||||||
import com.nextcloud.talk.newarch.features.conversationslist.ConversationsListView
|
import com.nextcloud.talk.newarch.features.conversationslist.ConversationsListView
|
||||||
import com.nextcloud.talk.newarch.services.GlobalService
|
import com.nextcloud.talk.newarch.services.GlobalService
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
@ -26,7 +26,9 @@ import android.app.Application
|
|||||||
import com.nextcloud.talk.newarch.domain.usecases.AddParticipantToConversationUseCase
|
import com.nextcloud.talk.newarch.domain.usecases.AddParticipantToConversationUseCase
|
||||||
import com.nextcloud.talk.newarch.domain.usecases.CreateConversationUseCase
|
import com.nextcloud.talk.newarch.domain.usecases.CreateConversationUseCase
|
||||||
import com.nextcloud.talk.newarch.domain.usecases.GetContactsUseCase
|
import com.nextcloud.talk.newarch.domain.usecases.GetContactsUseCase
|
||||||
|
import com.nextcloud.talk.newarch.domain.usecases.SetConversationPasswordUseCase
|
||||||
import com.nextcloud.talk.newarch.features.contactsflow.contacts.ContactsViewModelFactory
|
import com.nextcloud.talk.newarch.features.contactsflow.contacts.ContactsViewModelFactory
|
||||||
|
import com.nextcloud.talk.newarch.features.contactsflow.groupconversation.GroupConversationViewModelFactory
|
||||||
import com.nextcloud.talk.newarch.services.GlobalService
|
import com.nextcloud.talk.newarch.services.GlobalService
|
||||||
import org.koin.android.ext.koin.androidApplication
|
import org.koin.android.ext.koin.androidApplication
|
||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
@ -37,6 +39,20 @@ val ContactsFlowModule = module {
|
|||||||
androidApplication(), get(), get(), get(), get()
|
androidApplication(), get(), get(), get(), get()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
factory {
|
||||||
|
createGroupConversationViewModelFactory(
|
||||||
|
androidApplication(), get(), get(), get()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createGroupConversationViewModelFactory(
|
||||||
|
application: Application,
|
||||||
|
createConversationUseCase: CreateConversationUseCase,
|
||||||
|
setConversationPasswordUseCase: SetConversationPasswordUseCase,
|
||||||
|
globalService: GlobalService
|
||||||
|
): GroupConversationViewModelFactory {
|
||||||
|
return GroupConversationViewModelFactory(application, createConversationUseCase, setConversationPasswordUseCase, globalService)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createContactsViewModelFactory(
|
fun createContactsViewModelFactory(
|
||||||
|
@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* * Nextcloud Talk application
|
||||||
|
* *
|
||||||
|
* * @author Mario Danic
|
||||||
|
* * Copyright (C) 2017-2020 Mario Danic <mario@lovelyhq.com>
|
||||||
|
* *
|
||||||
|
* * This program is free software: you can redistribute it and/or modify
|
||||||
|
* * it under the terms of the GNU General Public License as published by
|
||||||
|
* * the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* * at your option) any later version.
|
||||||
|
* *
|
||||||
|
* * This program is distributed in the hope that it will be useful,
|
||||||
|
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* * GNU General Public License for more details.
|
||||||
|
* *
|
||||||
|
* * You should have received a copy of the GNU General Public License
|
||||||
|
* * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.nextcloud.talk.newarch.features.contactsflow.groupconversation
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.core.widget.doOnTextChanged
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
|
import com.bluelinelabs.conductor.RouterTransaction
|
||||||
|
import com.bluelinelabs.conductor.autodispose.ControllerScopeProvider
|
||||||
|
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
|
||||||
|
import com.nextcloud.talk.R
|
||||||
|
import com.nextcloud.talk.newarch.features.contactsflow.ContactsViewOperationState
|
||||||
|
import com.nextcloud.talk.newarch.features.contactsflow.contacts.ContactsView
|
||||||
|
import com.nextcloud.talk.newarch.mvvm.BaseView
|
||||||
|
import com.nextcloud.talk.utils.bundle.BundleKeys
|
||||||
|
import com.uber.autodispose.lifecycle.LifecycleScopeProvider
|
||||||
|
import kotlinx.android.synthetic.main.new_group_conversation_view.view.*
|
||||||
|
import org.koin.android.ext.android.inject
|
||||||
|
|
||||||
|
class GroupConversationView : BaseView() {
|
||||||
|
override val scopeProvider: LifecycleScopeProvider<*> = ControllerScopeProvider.from(this)
|
||||||
|
|
||||||
|
private lateinit var viewModel: GroupConversationViewModel
|
||||||
|
val factory: GroupConversationViewModelFactory by inject()
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup): View {
|
||||||
|
setHasOptionsMenu(true)
|
||||||
|
viewModel = viewModelProvider(factory).get(GroupConversationViewModel::class.java)
|
||||||
|
val view = super.onCreateView(inflater, container)
|
||||||
|
|
||||||
|
view.apply {
|
||||||
|
conversationNameInputEditText.doOnTextChanged { text, start, count, after ->
|
||||||
|
floatingActionButton?.isVisible = !text.isNullOrBlank()
|
||||||
|
}
|
||||||
|
|
||||||
|
allowGuestsSwitchMaterial.setOnCheckedChangeListener { buttonView, isChecked ->
|
||||||
|
passwordTextInputLayout.isVisible = isChecked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.operationState.observe(this, Observer { operationState ->
|
||||||
|
when (operationState.operationState) {
|
||||||
|
ContactsViewOperationState.WAITING -> {
|
||||||
|
// do nothing, just sit there and wait
|
||||||
|
}
|
||||||
|
ContactsViewOperationState.PROCESSING -> {
|
||||||
|
view.passwordInputEditText.isEnabled = false
|
||||||
|
view.conversationNameInputEditText.isEnabled = false
|
||||||
|
view.allowGuestsSwitchMaterial.isEnabled = false
|
||||||
|
toolbarProgressBar?.isVisible = true
|
||||||
|
|
||||||
|
}
|
||||||
|
ContactsViewOperationState.OK -> {
|
||||||
|
val bundle = Bundle()
|
||||||
|
bundle.putString(BundleKeys.KEY_CONVERSATION_TOKEN, operationState.conversationToken)
|
||||||
|
bundle.putBoolean(BundleKeys.KEY_NEW_GROUP_CONVERSATION, true)
|
||||||
|
router.replaceTopController(RouterTransaction.with(ContactsView(bundle))
|
||||||
|
.popChangeHandler(HorizontalChangeHandler())
|
||||||
|
.pushChangeHandler(HorizontalChangeHandler()))
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
// we should do something else as well, but this will do for now
|
||||||
|
// we failed, I'm afraid :(
|
||||||
|
toolbarProgressBar?.isVisible = false
|
||||||
|
view.passwordInputEditText.isEnabled = true
|
||||||
|
view.conversationNameInputEditText.isEnabled = true
|
||||||
|
view.allowGuestsSwitchMaterial.isEnabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getLayoutId(): Int {
|
||||||
|
return R.layout.new_group_conversation_view
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getTitle(): String? {
|
||||||
|
return context.getString(R.string.nc_new_group)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFloatingActionButtonClick() {
|
||||||
|
view?.conversationNameInputEditText?.text?.let { conversationName ->
|
||||||
|
val conversationType = if (view?.allowGuestsSwitchMaterial?.isChecked == true) 2 else 3
|
||||||
|
viewModel.createConversation(conversationType, conversationName.toString(), view?.passwordInputEditText?.text?.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getFloatingActionButtonDrawableRes(): Int {
|
||||||
|
return R.drawable.ic_arrow_forward_white_24px
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* * Nextcloud Talk application
|
||||||
|
* *
|
||||||
|
* * @author Mario Danic
|
||||||
|
* * Copyright (C) 2017-2020 Mario Danic <mario@lovelyhq.com>
|
||||||
|
* *
|
||||||
|
* * This program is free software: you can redistribute it and/or modify
|
||||||
|
* * it under the terms of the GNU General Public License as published by
|
||||||
|
* * the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* * at your option) any later version.
|
||||||
|
* *
|
||||||
|
* * This program is distributed in the hope that it will be useful,
|
||||||
|
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* * GNU General Public License for more details.
|
||||||
|
* *
|
||||||
|
* * You should have received a copy of the GNU General Public License
|
||||||
|
* * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.nextcloud.talk.newarch.features.contactsflow.groupconversation
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.distinctUntilChanged
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.nextcloud.talk.models.json.conversations.ConversationOverall
|
||||||
|
import com.nextcloud.talk.models.json.generic.GenericOverall
|
||||||
|
import com.nextcloud.talk.newarch.conversationsList.mvp.BaseViewModel
|
||||||
|
import com.nextcloud.talk.newarch.data.model.ErrorModel
|
||||||
|
import com.nextcloud.talk.newarch.domain.usecases.CreateConversationUseCase
|
||||||
|
import com.nextcloud.talk.newarch.domain.usecases.SetConversationPasswordUseCase
|
||||||
|
import com.nextcloud.talk.newarch.domain.usecases.base.UseCaseResponse
|
||||||
|
import com.nextcloud.talk.newarch.features.contactsflow.ContactsViewOperationState
|
||||||
|
import com.nextcloud.talk.newarch.features.contactsflow.ContactsViewOperationStateWrapper
|
||||||
|
import com.nextcloud.talk.newarch.features.conversationslist.ConversationsListView
|
||||||
|
import com.nextcloud.talk.newarch.services.GlobalService
|
||||||
|
import org.koin.core.parameter.parametersOf
|
||||||
|
|
||||||
|
class GroupConversationViewModel constructor(
|
||||||
|
application: Application,
|
||||||
|
private val createConversationUseCase: CreateConversationUseCase,
|
||||||
|
private val setPasswordUseCase: SetConversationPasswordUseCase,
|
||||||
|
val globalService: GlobalService
|
||||||
|
) : BaseViewModel<ConversationsListView>(application) {
|
||||||
|
private val _operationState = MutableLiveData(ContactsViewOperationStateWrapper(ContactsViewOperationState.WAITING, null, null))
|
||||||
|
val operationState: LiveData<ContactsViewOperationStateWrapper> = _operationState.distinctUntilChanged()
|
||||||
|
|
||||||
|
fun createConversation(conversationType: Int, conversationName: String, conversationPassword: String? = null) {
|
||||||
|
_operationState.postValue(ContactsViewOperationStateWrapper(ContactsViewOperationState.PROCESSING, null, null))
|
||||||
|
createConversationUseCase.invoke(viewModelScope, parametersOf(globalService.currentUserLiveData.value, conversationType, null, null, conversationName), object : UseCaseResponse<ConversationOverall> {
|
||||||
|
override suspend fun onSuccess(result: ConversationOverall) {
|
||||||
|
result.ocs.data.token?.let { token ->
|
||||||
|
if (conversationPassword != null) {
|
||||||
|
setPasswordForConversation(token, conversationPassword)
|
||||||
|
} else {
|
||||||
|
_operationState.postValue(ContactsViewOperationStateWrapper(ContactsViewOperationState.OK, null, token))
|
||||||
|
}
|
||||||
|
} ?: run {
|
||||||
|
_operationState.postValue(ContactsViewOperationStateWrapper(ContactsViewOperationState.CONVERSATION_CREATED_WITH_MISSING_TOKEN, null, null))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun onError(errorModel: ErrorModel?) {
|
||||||
|
_operationState.postValue(ContactsViewOperationStateWrapper(ContactsViewOperationState.CONVERSATION_CREATION_FAILED, errorModel?.getErrorMessage(), null))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setPasswordForConversation(conversationToken: String, conversationPassword: String) {
|
||||||
|
setPasswordUseCase.invoke(viewModelScope, parametersOf(globalService.currentUserLiveData.value, conversationToken, conversationPassword), object : UseCaseResponse<GenericOverall> {
|
||||||
|
override suspend fun onSuccess(result: GenericOverall) {
|
||||||
|
_operationState.postValue(ContactsViewOperationStateWrapper(ContactsViewOperationState.OK, null, conversationToken))
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun onError(errorModel: ErrorModel?) {
|
||||||
|
_operationState.postValue(ContactsViewOperationStateWrapper(ContactsViewOperationState.CONVERSATION_PASSWORD_NOT_SET, errorModel?.getErrorMessage(), conversationToken))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* * Nextcloud Talk application
|
||||||
|
* *
|
||||||
|
* * @author Mario Danic
|
||||||
|
* * Copyright (C) 2017-2020 Mario Danic <mario@lovelyhq.com>
|
||||||
|
* *
|
||||||
|
* * This program is free software: you can redistribute it and/or modify
|
||||||
|
* * it under the terms of the GNU General Public License as published by
|
||||||
|
* * the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* * at your option) any later version.
|
||||||
|
* *
|
||||||
|
* * This program is distributed in the hope that it will be useful,
|
||||||
|
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* * GNU General Public License for more details.
|
||||||
|
* *
|
||||||
|
* * You should have received a copy of the GNU General Public License
|
||||||
|
* * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.nextcloud.talk.newarch.features.contactsflow.groupconversation
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import com.nextcloud.talk.newarch.domain.usecases.CreateConversationUseCase
|
||||||
|
import com.nextcloud.talk.newarch.domain.usecases.SetConversationPasswordUseCase
|
||||||
|
import com.nextcloud.talk.newarch.services.GlobalService
|
||||||
|
|
||||||
|
class GroupConversationViewModelFactory constructor(
|
||||||
|
private val application: Application,
|
||||||
|
private val createConversationUseCase: CreateConversationUseCase,
|
||||||
|
private val setConversationPasswordUseCase: SetConversationPasswordUseCase,
|
||||||
|
private val globalService: GlobalService
|
||||||
|
) : ViewModelProvider.Factory {
|
||||||
|
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
|
||||||
|
return GroupConversationViewModel(application, createConversationUseCase, setConversationPasswordUseCase, globalService) as T
|
||||||
|
}
|
||||||
|
}
|
@ -27,7 +27,6 @@
|
|||||||
android:animateLayoutChanges="true"
|
android:animateLayoutChanges="true"
|
||||||
tools:context=".activities.MainActivity">
|
tools:context=".activities.MainActivity">
|
||||||
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/appBar"
|
android:id="@+id/appBar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -49,7 +48,18 @@
|
|||||||
android:theme="@style/ThemeOverlay.MaterialComponents.Dark.ActionBar"
|
android:theme="@style/ThemeOverlay.MaterialComponents.Dark.ActionBar"
|
||||||
app:contentInsetStartWithNavigation="0dp"
|
app:contentInsetStartWithNavigation="0dp"
|
||||||
app:layout_scrollFlags="enterAlwaysCollapsed|noScroll"
|
app:layout_scrollFlags="enterAlwaysCollapsed|noScroll"
|
||||||
app:popupTheme="@style/appActionBarPopupMenu" />
|
app:popupTheme="@style/appActionBarPopupMenu">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/toolbarProgressBar"
|
||||||
|
android:layout_width="32dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:layout_gravity="center_vertical|end"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:indeterminateTint="@color/hwSecurityRed"
|
||||||
|
android:scaleType="fitCenter" />
|
||||||
|
|
||||||
|
</com.google.android.material.appbar.MaterialToolbar>
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
@ -58,7 +68,7 @@
|
|||||||
android:id="@+id/controller_container"
|
android:id="@+id/controller_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"/>
|
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
android:id="@+id/floatingActionButton"
|
android:id="@+id/floatingActionButton"
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?><!--
|
||||||
<!--
|
|
||||||
~ /*
|
~ /*
|
||||||
~ * Nextcloud Talk application
|
~ * Nextcloud Talk application
|
||||||
~ *
|
~ *
|
||||||
@ -23,45 +22,49 @@
|
|||||||
|
|
||||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent"
|
||||||
|
android:animateLayoutChanges="true">
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/conversationNameTextInputLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="@string/nc_call_name"
|
android:hint="@string/nc_call_name">
|
||||||
android:id="@+id/conversationNameTextInputLayout">
|
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/conversationNameInputEditText"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_margin="8dp"
|
android:layout_height="match_parent"
|
||||||
android:layout_height="match_parent"/>
|
android:layout_margin="8dp" />
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_below="@id/conversationNameTextInputLayout"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:id="@+id/allowGuestsSwitchMaterial"
|
android:id="@+id/allowGuestsSwitchMaterial"
|
||||||
android:text="@string/nc_allow_guests"
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/conversationNameTextInputLayout"
|
||||||
android:layout_marginHorizontal="8dp"
|
android:layout_marginHorizontal="8dp"
|
||||||
android:layout_marginBottom="8dp">
|
android:layout_marginBottom="8dp"
|
||||||
</com.google.android.material.switchmaterial.SwitchMaterial>
|
android:text="@string/nc_allow_guests"></com.google.android.material.switchmaterial.SwitchMaterial>
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/passwordTextInputLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="@string/nc_password_optional"
|
|
||||||
android:layout_below="@id/allowGuestsSwitchMaterial"
|
android:layout_below="@id/allowGuestsSwitchMaterial"
|
||||||
android:id="@+id/passwordTextInputLayout">
|
android:visibility="gone"
|
||||||
|
android:hint="@string/nc_password_optional">
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/passwordInputEditText"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
android:layout_marginHorizontal="8dp"
|
android:layout_marginHorizontal="8dp"
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp" />
|
||||||
android:layout_height="match_parent"/>
|
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
Loading…
Reference in New Issue
Block a user