Initial new group conversation view

Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
Mario Danic 2020-01-30 21:21:30 +01:00
parent 8fef0c314b
commit e3451342f3
No known key found for this signature in database
GPG Key ID: CDE0BBD2738C4CC0
19 changed files with 393 additions and 40 deletions

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -197,7 +197,7 @@ 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))
@ -217,7 +217,7 @@ class ChatMessage : IMessage, MessageContentType, MessageContentType.Image {
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,7 +226,7 @@ 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))
@ -246,7 +246,7 @@ class ChatMessage : IMessage, MessageContentType, MessageContentType.Image {
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))

View File

@ -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

View File

@ -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,

View File

@ -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)

View File

@ -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>

View File

@ -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]
)
}
}

View File

@ -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

View File

@ -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) {
} }

View File

@ -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

View File

@ -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(

View File

@ -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
}
}

View File

@ -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))
}
})
}
}

View File

@ -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
}
}

View File

@ -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"

View File

@ -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_marginHorizontal="8dp"
android:layout_marginBottom="8dp">
</com.google.android.material.switchmaterial.SwitchMaterial>
<com.google.android.material.textfield.TextInputLayout
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/conversationNameTextInputLayout"
android:layout_below="@id/allowGuestsSwitchMaterial"
android:id="@+id/passwordTextInputLayout">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_marginHorizontal="8dp" android:layout_marginHorizontal="8dp"
android:layout_marginBottom="8dp" android:layout_marginBottom="8dp"
android:layout_height="match_parent"/> android:text="@string/nc_allow_guests"></com.google.android.material.switchmaterial.SwitchMaterial>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/passwordTextInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/allowGuestsSwitchMaterial"
android:visibility="gone"
android:hint="@string/nc_password_optional">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/passwordInputEditText"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginHorizontal="8dp"
android:layout_marginBottom="8dp" />
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
</RelativeLayout> </RelativeLayout>
</ScrollView> </ScrollView>