diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingPollMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingPollMessageViewHolder.kt index fdbb4f2a4..ccf339b64 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingPollMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingPollMessageViewHolder.kt @@ -24,27 +24,35 @@ package com.nextcloud.talk.adapters.messages import android.annotation.SuppressLint import android.content.Context import android.graphics.PorterDuff -import android.os.Handler +import android.util.Log import android.view.View import androidx.appcompat.content.res.AppCompatResources import androidx.core.view.ViewCompat import autodagger.AutoInjector import coil.load import com.nextcloud.talk.R +import com.nextcloud.talk.activities.MainActivity +import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication import com.nextcloud.talk.databinding.ItemCustomOutcomingPollMessageBinding import com.nextcloud.talk.models.json.chat.ChatMessage import com.nextcloud.talk.models.json.chat.ReadStatus +import com.nextcloud.talk.polls.repositories.model.PollOverall +import com.nextcloud.talk.polls.ui.PollMainDialogFragment import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.DisplayUtils import com.nextcloud.talk.utils.preferences.AppPreferences import com.stfalcon.chatkit.messages.MessageHolders +import io.reactivex.Observer +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.Schedulers import javax.inject.Inject @AutoInjector(NextcloudTalkApplication::class) -class OutcomingPollMessageViewHolder(outcomingView: View) : MessageHolders -.OutcomingTextMessageViewHolder(outcomingView) { +class OutcomingPollMessageViewHolder(outcomingView: View, payload: Any) : MessageHolders +.OutcomingTextMessageViewHolder(outcomingView, payload) { private val binding: ItemCustomOutcomingPollMessageBinding = ItemCustomOutcomingPollMessageBinding.bind(itemView) @@ -57,9 +65,11 @@ class OutcomingPollMessageViewHolder(outcomingView: View) : MessageHolders @Inject var appPreferences: AppPreferences? = null - lateinit var message: ChatMessage + @Inject + @JvmField + var ncApi: NcApi? = null - lateinit var handler: Handler + lateinit var message: ChatMessage lateinit var reactionsInterface: ReactionsInterface @@ -98,6 +108,8 @@ class OutcomingPollMessageViewHolder(outcomingView: View) : MessageHolders binding.checkMark.setContentDescription(readStatusContentDescriptionString) + setPollPreview(message) + Reaction().showReactions(message, binding.reactions, binding.messageTime.context, true) binding.reactions.reactionsEmojiWrapper.setOnClickListener { reactionsInterface.onClickReactions(message) @@ -108,6 +120,73 @@ class OutcomingPollMessageViewHolder(outcomingView: View) : MessageHolders } } + private fun setPollPreview(message: ChatMessage) { + var pollId: String? = null + var pollName: String? = null + + if (message.messageParameters != null && message.messageParameters!!.size > 0) { + for (key in message.messageParameters!!.keys) { + val individualHashMap: Map = message.messageParameters!![key]!! + if (individualHashMap["type"] == "talk-poll") { + pollId = individualHashMap["id"] + pollName = individualHashMap["name"].toString() + } + } + } + + if (pollId != null && pollName != null) { + binding.messagePollTitle.text = pollName + + val roomToken = (payload as? MessagePayload)!!.roomToken + + binding.bubble.setOnClickListener { + val pollVoteDialog = PollMainDialogFragment.newInstance( + roomToken, + pollId, + pollName + ) + pollVoteDialog.show( + (binding.messagePollIcon.context as MainActivity).supportFragmentManager, + TAG + ) + } + + val credentials = ApiUtils.getCredentials(message.activeUser?.username, message.activeUser?.token) + ncApi!!.getPoll( + credentials, + ApiUtils.getUrlForPoll( + message.activeUser?.baseUrl, + roomToken, + pollId + ) + ).subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : Observer { + override fun onSubscribe(d: Disposable) { + // unused atm + } + + override fun onNext(pollOverall: PollOverall) { + if (pollOverall.ocs!!.data!!.status == 0) { + binding.messagePollSubtitle.text = + context?.resources?.getString(R.string.message_poll_tap_to_vote) + } else { + binding.messagePollSubtitle.text = + context?.resources?.getString(R.string.message_poll_tap_see_results) + } + } + + override fun onError(e: Throwable) { + Log.e(TAG, "Error while fetching poll", e) + } + + override fun onComplete() { + // unused atm + } + }) + } + } + private fun setParentMessageDataOnMessageItem(message: ChatMessage) { if (!message.isDeleted && message.parentMessage != null) { val parentChatMessage = message.parentMessage diff --git a/app/src/main/java/com/nextcloud/talk/api/NcApi.java b/app/src/main/java/com/nextcloud/talk/api/NcApi.java index 8b4689b99..5a531f5c7 100644 --- a/app/src/main/java/com/nextcloud/talk/api/NcApi.java +++ b/app/src/main/java/com/nextcloud/talk/api/NcApi.java @@ -532,9 +532,14 @@ public interface NcApi { Observable getPoll(@Header("Authorization") String authorization, @Url String url); + @FormUrlEncoded @POST Observable createPoll(@Header("Authorization") String authorization, - @Url String url); + @Url String url, + @Query("question") String question, + @Field("options[]") List options, + @Query("resultMode") Integer resultMode, + @Query("maxVotes") Integer maxVotes); @FormUrlEncoded @POST diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt b/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt index 2b9a698b6..0927abf94 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt +++ b/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt @@ -142,6 +142,7 @@ import com.nextcloud.talk.models.json.conversations.RoomOverall import com.nextcloud.talk.models.json.conversations.RoomsOverall import com.nextcloud.talk.models.json.generic.GenericOverall import com.nextcloud.talk.models.json.mention.Mention +import com.nextcloud.talk.polls.ui.PollCreateDialogFragment import com.nextcloud.talk.presenters.MentionAutocompletePresenter import com.nextcloud.talk.remotefilebrowser.activities.RemoteFileBrowserActivity import com.nextcloud.talk.shareditems.activities.SharedItemsActivity @@ -3138,6 +3139,16 @@ class ChatController(args: Bundle) : } } + fun createPoll() { + val pollVoteDialog = PollCreateDialogFragment.newInstance( + roomToken!! + ) + pollVoteDialog.show( + (activity as MainActivity?)!!.supportFragmentManager, + TAG + ) + } + companion object { private const val TAG = "ChatController" private const val CONTENT_TYPE_SYSTEM_MESSAGE: Byte = 1 diff --git a/app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt b/app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt index 338c0d340..3d8ee7535 100644 --- a/app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt +++ b/app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt @@ -25,8 +25,9 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import com.nextcloud.talk.remotefilebrowser.viewmodels.RemoteFileBrowserItemsViewModel import com.nextcloud.talk.messagesearch.MessageSearchViewModel +import com.nextcloud.talk.polls.viewmodels.PollCreateViewModel +import com.nextcloud.talk.polls.viewmodels.PollMainViewModel import com.nextcloud.talk.polls.viewmodels.PollResultsViewModel -import com.nextcloud.talk.polls.viewmodels.PollViewModel import com.nextcloud.talk.polls.viewmodels.PollVoteViewModel import com.nextcloud.talk.shareditems.viewmodels.SharedItemsViewModel import dagger.Binds @@ -66,8 +67,8 @@ abstract class ViewModelModule { @Binds @IntoMap - @ViewModelKey(PollViewModel::class) - abstract fun pollViewModel(viewModel: PollViewModel): ViewModel + @ViewModelKey(PollMainViewModel::class) + abstract fun pollViewModel(viewModel: PollMainViewModel): ViewModel @Binds @IntoMap @@ -79,6 +80,11 @@ abstract class ViewModelModule { @ViewModelKey(PollResultsViewModel::class) abstract fun pollResultsViewModel(viewModel: PollResultsViewModel): ViewModel + @Binds + @IntoMap + @ViewModelKey(PollCreateViewModel::class) + abstract fun pollCreateViewModel(viewModel: PollCreateViewModel): ViewModel + @Binds @IntoMap @ViewModelKey(RemoteFileBrowserItemsViewModel::class) diff --git a/app/src/main/java/com/nextcloud/talk/polls/adapters/PollCreateOptionItem.kt b/app/src/main/java/com/nextcloud/talk/polls/adapters/PollCreateOptionItem.kt new file mode 100644 index 000000000..ae70d60d4 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/polls/adapters/PollCreateOptionItem.kt @@ -0,0 +1,5 @@ +package com.nextcloud.talk.polls.adapters + +class PollCreateOptionItem( + var pollOption: String +) diff --git a/app/src/main/java/com/nextcloud/talk/polls/adapters/PollCreateOptionViewHolder.kt b/app/src/main/java/com/nextcloud/talk/polls/adapters/PollCreateOptionViewHolder.kt new file mode 100644 index 000000000..c41d883c8 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/polls/adapters/PollCreateOptionViewHolder.kt @@ -0,0 +1,53 @@ +package com.nextcloud.talk.polls.adapters + +import android.annotation.SuppressLint +import androidx.recyclerview.widget.RecyclerView +import com.nextcloud.talk.databinding.PollCreateOptionsItemBinding + +class PollCreateOptionViewHolder( + private val binding: PollCreateOptionsItemBinding +) : RecyclerView.ViewHolder(binding.root) { + + @SuppressLint("SetTextI18n") + fun bind( + pollCreateOptionItem: PollCreateOptionItem, + clickListener: PollCreateOptionsItemClickListener, + position: Int + ) { + // binding.root.setOnClickListener { } + + binding.pollOptionDelete.setOnClickListener { + clickListener.onDeleteClick(pollCreateOptionItem, position) + } + + // binding.pollOptionText.addTextChangedListener(object : TextWatcher { + // override fun afterTextChanged(s: Editable) { + // // unused atm + // } + // + // override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { + // // unused atm + // } + // + // override fun onTextChanged(option: CharSequence, start: Int, before: Int, count: Int) { + // pollCreateOptionItem.pollOption = option.toString() + // } + // }) + } + + // fun onBind(item: SharedItem) { + // Log.d("","bbbb") + // } + // + // fun onLongClick(view: View?): Boolean { + // // moviesList.remove(getAdapterPosition()) + // // notifyItemRemoved(getAdapterPosition()) + // + // Log.d("", "dfdrg") + // return true + // } + // + // override fun onClick(v: View?) { + // Log.d("", "dfdrg") + // } +} diff --git a/app/src/main/java/com/nextcloud/talk/polls/adapters/PollCreateOptionsAdapter.kt b/app/src/main/java/com/nextcloud/talk/polls/adapters/PollCreateOptionsAdapter.kt new file mode 100644 index 000000000..e39e1c507 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/polls/adapters/PollCreateOptionsAdapter.kt @@ -0,0 +1,27 @@ +package com.nextcloud.talk.polls.adapters + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.nextcloud.talk.databinding.PollCreateOptionsItemBinding + +class PollCreateOptionsAdapter( + private val clickListener: PollCreateOptionsItemClickListener +) : RecyclerView.Adapter() { + + internal var list: MutableList = ArrayList() + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PollCreateOptionViewHolder { + val itemBinding = PollCreateOptionsItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) + + return PollCreateOptionViewHolder(itemBinding) + } + + override fun onBindViewHolder(holder: PollCreateOptionViewHolder, position: Int) { + holder.bind(list[position], clickListener, position) + } + + override fun getItemCount(): Int { + return list.size + } +} diff --git a/app/src/main/java/com/nextcloud/talk/polls/adapters/PollCreateOptionsItemClickListener.kt b/app/src/main/java/com/nextcloud/talk/polls/adapters/PollCreateOptionsItemClickListener.kt new file mode 100644 index 000000000..6c17d0f0b --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/polls/adapters/PollCreateOptionsItemClickListener.kt @@ -0,0 +1,5 @@ +package com.nextcloud.talk.polls.adapters + +interface PollCreateOptionsItemClickListener { + fun onDeleteClick(pollCreateOptionItem: PollCreateOptionItem, position: Int) +} diff --git a/app/src/main/java/com/nextcloud/talk/polls/repositories/PollRepository.kt b/app/src/main/java/com/nextcloud/talk/polls/repositories/PollRepository.kt index cfc8b6d55..4654e170f 100644 --- a/app/src/main/java/com/nextcloud/talk/polls/repositories/PollRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/polls/repositories/PollRepository.kt @@ -8,4 +8,12 @@ interface PollRepository { fun getPoll(roomToken: String, pollId: String): Observable? fun vote(roomToken: String, pollId: String, option: Int): Observable? + + fun createPoll( + roomToken: String, + question: String, + options: List, + resultMode: Int, + maxVotes: Int + ): Observable? } diff --git a/app/src/main/java/com/nextcloud/talk/polls/repositories/PollRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/polls/repositories/PollRepositoryImpl.kt index 9604baabc..c10e862cb 100644 --- a/app/src/main/java/com/nextcloud/talk/polls/repositories/PollRepositoryImpl.kt +++ b/app/src/main/java/com/nextcloud/talk/polls/repositories/PollRepositoryImpl.kt @@ -38,6 +38,24 @@ class PollRepositoryImpl(private val ncApi: NcApi, private val currentUserProvid currentUserProvider.currentUser?.token ) + override fun createPoll( + roomToken: String, question: String, options: List, resultMode: Int, maxVotes: + Int + ): + Observable? { + return ncApi.createPoll( + credentials, + ApiUtils.getUrlForPoll( + currentUserProvider.currentUser?.baseUrl, + roomToken + ), + question, + options, + resultMode, + maxVotes + ).map { mapToPoll(it.ocs?.data!!) } + } + override fun getPoll(roomToken: String, pollId: String): Observable { return ncApi.getPoll( diff --git a/app/src/main/java/com/nextcloud/talk/polls/ui/PollCreateDialogFragment.kt b/app/src/main/java/com/nextcloud/talk/polls/ui/PollCreateDialogFragment.kt new file mode 100644 index 000000000..8f4b06e72 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/polls/ui/PollCreateDialogFragment.kt @@ -0,0 +1,155 @@ +package com.nextcloud.talk.polls.ui + +import android.annotation.SuppressLint +import android.app.Dialog +import android.os.Bundle +import android.text.Editable +import android.text.TextWatcher +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.app.AlertDialog +import androidx.fragment.app.DialogFragment +import androidx.lifecycle.ViewModelProvider +import androidx.recyclerview.widget.LinearLayoutManager +import autodagger.AutoInjector +import com.nextcloud.talk.application.NextcloudTalkApplication +import com.nextcloud.talk.databinding.DialogPollCreateBinding +import com.nextcloud.talk.polls.adapters.PollCreateOptionItem +import com.nextcloud.talk.polls.adapters.PollCreateOptionsAdapter +import com.nextcloud.talk.polls.adapters.PollCreateOptionsItemClickListener +import com.nextcloud.talk.polls.viewmodels.PollCreateViewModel +import javax.inject.Inject + +@AutoInjector(NextcloudTalkApplication::class) +class PollCreateDialogFragment( + private val roomToken: String +) : DialogFragment(), PollCreateOptionsItemClickListener { + + @Inject + lateinit var viewModelFactory: ViewModelProvider.Factory + + private lateinit var binding: DialogPollCreateBinding + private lateinit var viewModel: PollCreateViewModel + + private var adapter: PollCreateOptionsAdapter? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this) + + viewModel = ViewModelProvider(this, viewModelFactory)[PollCreateViewModel::class.java] + } + + @SuppressLint("InflateParams") + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + binding = DialogPollCreateBinding.inflate(LayoutInflater.from(context)) + + val dialog = AlertDialog.Builder(requireContext()) + .setView(binding.root) + .create() + + return dialog + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + adapter = PollCreateOptionsAdapter(this) + binding?.pollCreateOptionsList?.adapter = adapter + binding?.pollCreateOptionsList?.layoutManager = LinearLayoutManager(context) + + viewModel.initialize(roomToken) + + for (i in 1..3) { + val item = PollCreateOptionItem("a") + adapter?.list?.add(item) + } + + binding.pollAddOption.setOnClickListener { + val item = PollCreateOptionItem("a") + adapter?.list?.add(item) + adapter?.notifyDataSetChanged() + } + + binding.pollDismiss.setOnClickListener { + dismiss() + } + + + + + binding.pollCreateQuestion.addTextChangedListener(object : TextWatcher { + override fun afterTextChanged(s: Editable) { + // unused atm + } + + override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { + // unused atm + } + + override fun onTextChanged(question: CharSequence, start: Int, before: Int, count: Int) { + viewModel.question = question.toString() + } + }) + + // binding.option1.addTextChangedListener(object : TextWatcher { + // override fun afterTextChanged(s: Editable) { + // // unused atm + // } + // + // override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { + // // unused atm + // } + // + // override fun onTextChanged(option: CharSequence, start: Int, before: Int, count: Int) { + // viewModel.options = listOf(option.toString()) + // } + // }) + + binding.pollPrivatePollCheckbox.setOnClickListener { + viewModel.multipleAnswer = binding.pollMultipleAnswersCheckbox.isChecked + } + + binding.pollMultipleAnswersCheckbox.setOnClickListener { + viewModel.multipleAnswer = binding.pollMultipleAnswersCheckbox.isChecked + } + + binding.pollCreateButton.setOnClickListener { + viewModel.createPoll() + } + + viewModel.viewState.observe(viewLifecycleOwner) { state -> + when (state) { + PollCreateViewModel.InitialState -> {} + + is PollCreateViewModel.PollCreatedState -> { + dismiss() + } + } + } + + viewModel.initialize(roomToken) + } + + override fun onDeleteClick(pollCreateOptionItem: PollCreateOptionItem, position: Int) { + adapter?.list?.remove(pollCreateOptionItem) + adapter?.notifyItemRemoved(position) + } + + /** + * Fragment creator + */ + companion object { + private val TAG = PollCreateDialogFragment::class.java.simpleName + + @JvmStatic + fun newInstance( + roomTokenParam: String + ): PollCreateDialogFragment = PollCreateDialogFragment(roomTokenParam) + } +} diff --git a/app/src/main/java/com/nextcloud/talk/polls/ui/PollMainDialogFragment.kt b/app/src/main/java/com/nextcloud/talk/polls/ui/PollMainDialogFragment.kt index 942e24b7d..f7bb368c5 100644 --- a/app/src/main/java/com/nextcloud/talk/polls/ui/PollMainDialogFragment.kt +++ b/app/src/main/java/com/nextcloud/talk/polls/ui/PollMainDialogFragment.kt @@ -13,7 +13,7 @@ import autodagger.AutoInjector import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.databinding.DialogPollMainBinding import com.nextcloud.talk.polls.model.Poll -import com.nextcloud.talk.polls.viewmodels.PollViewModel +import com.nextcloud.talk.polls.viewmodels.PollMainViewModel import javax.inject.Inject @AutoInjector(NextcloudTalkApplication::class) @@ -27,13 +27,13 @@ class PollMainDialogFragment( lateinit var viewModelFactory: ViewModelProvider.Factory private lateinit var binding: DialogPollMainBinding - private lateinit var viewModel: PollViewModel + private lateinit var viewModel: PollMainViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this) - viewModel = ViewModelProvider(this, viewModelFactory)[PollViewModel::class.java] + viewModel = ViewModelProvider(this, viewModelFactory)[PollMainViewModel::class.java] } @SuppressLint("InflateParams") @@ -58,9 +58,9 @@ class PollMainDialogFragment( viewModel.viewState.observe(viewLifecycleOwner) { state -> when (state) { - PollViewModel.InitialState -> {} + PollMainViewModel.InitialState -> {} - is PollViewModel.PollVotedState -> { + is PollMainViewModel.PollVotedState -> { if (state.poll.resultMode == Poll.RESULT_MODE_HIDDEN) { showVoteFragment() } else { @@ -68,7 +68,7 @@ class PollMainDialogFragment( } } - is PollViewModel.PollUnvotedState -> { + is PollMainViewModel.PollUnvotedState -> { if (state.poll.status == Poll.STATUS_CLOSED) { showResultsFragment() } else { diff --git a/app/src/main/java/com/nextcloud/talk/polls/ui/PollResultsFragment.kt b/app/src/main/java/com/nextcloud/talk/polls/ui/PollResultsFragment.kt index 6613c8f14..0f42523a5 100644 --- a/app/src/main/java/com/nextcloud/talk/polls/ui/PollResultsFragment.kt +++ b/app/src/main/java/com/nextcloud/talk/polls/ui/PollResultsFragment.kt @@ -37,13 +37,13 @@ import com.nextcloud.talk.polls.adapters.PollResultItem import com.nextcloud.talk.polls.adapters.PollResultItemClickListener import com.nextcloud.talk.polls.adapters.PollResultsAdapter import com.nextcloud.talk.polls.model.Poll +import com.nextcloud.talk.polls.viewmodels.PollMainViewModel import com.nextcloud.talk.polls.viewmodels.PollResultsViewModel -import com.nextcloud.talk.polls.viewmodels.PollViewModel import javax.inject.Inject @AutoInjector(NextcloudTalkApplication::class) class PollResultsFragment( - private val parentViewModel: PollViewModel, + private val parentViewModel: PollMainViewModel, private val roomToken: String, private val pollId: String ) : Fragment(), PollResultItemClickListener { @@ -82,14 +82,14 @@ class PollResultsFragment( _binding?.pollResultsList?.layoutManager = LinearLayoutManager(context) parentViewModel.viewState.observe(viewLifecycleOwner) { state -> - if (state is PollViewModel.PollVotedState && + if (state is PollMainViewModel.PollVotedState && state.poll.resultMode == Poll.RESULT_MODE_PUBLIC ) { initPollResults(state.poll) initAmountVotersInfo(state) initEditButton(state) - } else if (state is PollViewModel.PollUnvotedState && + } else if (state is PollMainViewModel.PollUnvotedState && state.poll.status == Poll.STATUS_CLOSED ) { Log.d(TAG, "show results also if self never voted") @@ -129,14 +129,14 @@ class PollResultsFragment( } } - private fun initAmountVotersInfo(state: PollViewModel.PollVotedState) { + private fun initAmountVotersInfo(state: PollMainViewModel.PollVotedState) { _binding?.pollAmountVoters?.text = String.format( resources.getString(R.string.polls_amount_voters), state.poll.numVoters ) } - private fun initEditButton(state: PollViewModel.PollVotedState) { + private fun initEditButton(state: PollMainViewModel.PollVotedState) { if (state.poll.status == Poll.STATUS_OPEN && state.poll.resultMode == Poll.RESULT_MODE_PUBLIC) { _binding?.editVoteButton?.visibility = View.VISIBLE _binding?.editVoteButton?.setOnClickListener { @@ -147,6 +147,10 @@ class PollResultsFragment( } } + override fun onClick(pollResultItem: PollResultItem) { + Log.d(TAG, "click..") + } + override fun onDestroyView() { super.onDestroyView() _binding = null @@ -155,8 +159,4 @@ class PollResultsFragment( companion object { private val TAG = PollResultsFragment::class.java.simpleName } - - override fun onClick(pollResultItem: PollResultItem) { - Log.d(TAG, "click..") - } } diff --git a/app/src/main/java/com/nextcloud/talk/polls/ui/PollVoteFragment.kt b/app/src/main/java/com/nextcloud/talk/polls/ui/PollVoteFragment.kt index c908053d8..0f74d7af6 100644 --- a/app/src/main/java/com/nextcloud/talk/polls/ui/PollVoteFragment.kt +++ b/app/src/main/java/com/nextcloud/talk/polls/ui/PollVoteFragment.kt @@ -33,13 +33,13 @@ import autodagger.AutoInjector import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.databinding.DialogPollVoteBinding import com.nextcloud.talk.polls.model.Poll -import com.nextcloud.talk.polls.viewmodels.PollViewModel +import com.nextcloud.talk.polls.viewmodels.PollMainViewModel import com.nextcloud.talk.polls.viewmodels.PollVoteViewModel import javax.inject.Inject @AutoInjector(NextcloudTalkApplication::class) class PollVoteFragment( - private val parentViewModel: PollViewModel, + private val parentViewModel: PollMainViewModel, private val roomToken: String, private val pollId: String ) : Fragment() { @@ -71,7 +71,7 @@ class PollVoteFragment( override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) parentViewModel.viewState.observe(viewLifecycleOwner) { state -> - if (state is PollViewModel.PollUnvotedState) { + if (state is PollMainViewModel.PollUnvotedState) { val poll = state.poll binding.radioGroup.removeAllViews() poll.options?.map { option -> @@ -80,7 +80,7 @@ class PollVoteFragment( radioButton.id = index binding.radioGroup.addView(radioButton) } - } else if (state is PollViewModel.PollVotedState && state.poll.resultMode == Poll.RESULT_MODE_HIDDEN) { + } else if (state is PollMainViewModel.PollVotedState && state.poll.resultMode == Poll.RESULT_MODE_HIDDEN) { Log.d(TAG, "show vote screen also for resultMode hidden poll when already voted") // TODO: other text for submit button } diff --git a/app/src/main/java/com/nextcloud/talk/polls/viewmodels/PollCreateViewModel.kt b/app/src/main/java/com/nextcloud/talk/polls/viewmodels/PollCreateViewModel.kt new file mode 100644 index 000000000..268f96ff1 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/polls/viewmodels/PollCreateViewModel.kt @@ -0,0 +1,84 @@ +package com.nextcloud.talk.polls.viewmodels + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import com.nextcloud.talk.polls.model.Poll +import com.nextcloud.talk.polls.repositories.PollRepository +import io.reactivex.Observer +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.Schedulers +import javax.inject.Inject + +class PollCreateViewModel @Inject constructor(private val repository: PollRepository) : ViewModel() { + + private lateinit var roomToken: String + + lateinit var question: String + lateinit var options: List + var privatePoll: Boolean = false + var multipleAnswer: Boolean = false + + sealed interface ViewState + object InitialState : ViewState + open class PollCreatingState() : ViewState + open class PollCreatedState() : ViewState + open class PollCreationFailedState() : ViewState + + private val _viewState: MutableLiveData = MutableLiveData(InitialState) + val viewState: LiveData + get() = _viewState + + private var disposable: Disposable? = null + + fun initialize(roomToken: String) { + this.roomToken = roomToken + } + + override fun onCleared() { + super.onCleared() + disposable?.dispose() + } + + fun createPoll() { + var maxVotes = 1 + if (multipleAnswer) { + maxVotes = 0 + } + + var resultMode = 0 + if (privatePoll) { + resultMode = 1 + } + + repository.createPoll(roomToken, question, options, resultMode, maxVotes) + ?.doOnSubscribe { disposable = it } + ?.subscribeOn(Schedulers.io()) + ?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribe(PollObserver()) + } + + inner class PollObserver : Observer { + + lateinit var poll: Poll + + override fun onSubscribe(d: Disposable) = Unit + + override fun onNext(response: Poll) { + poll = response + } + + override fun onError(e: Throwable) { + _viewState.value = PollCreationFailedState() + } + + override fun onComplete() { + _viewState.value = PollCreatedState() + } + } + + companion object { + private val TAG = PollCreateViewModel::class.java.simpleName + } +} diff --git a/app/src/main/java/com/nextcloud/talk/polls/viewmodels/PollViewModel.kt b/app/src/main/java/com/nextcloud/talk/polls/viewmodels/PollMainViewModel.kt similarity index 93% rename from app/src/main/java/com/nextcloud/talk/polls/viewmodels/PollViewModel.kt rename to app/src/main/java/com/nextcloud/talk/polls/viewmodels/PollMainViewModel.kt index 6bbb67b42..28594beab 100644 --- a/app/src/main/java/com/nextcloud/talk/polls/viewmodels/PollViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/polls/viewmodels/PollMainViewModel.kt @@ -23,7 +23,7 @@ import javax.inject.Inject * InitialState --> PollClosedState * @enduml */ -class PollViewModel @Inject constructor(private val repository: PollRepository) : ViewModel() { +class PollMainViewModel @Inject constructor(private val repository: PollRepository) : ViewModel() { private lateinit var roomToken: String private lateinit var pollId: String @@ -97,6 +97,6 @@ class PollViewModel @Inject constructor(private val repository: PollRepository) } companion object { - private val TAG = PollViewModel::class.java.simpleName + private val TAG = PollMainViewModel::class.java.simpleName } } diff --git a/app/src/main/java/com/nextcloud/talk/ui/dialog/AttachmentDialog.kt b/app/src/main/java/com/nextcloud/talk/ui/dialog/AttachmentDialog.kt index c760990ab..2da8b2d76 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/dialog/AttachmentDialog.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/dialog/AttachmentDialog.kt @@ -74,6 +74,11 @@ class AttachmentDialog(val activity: Activity, var chatController: ChatControlle dismiss() } + dialogAttachmentBinding.menuAttachPoll.setOnClickListener { + chatController.createPoll() + dismiss() + } + dialogAttachmentBinding.menuAttachFileFromCloud.setOnClickListener { chatController.showBrowserScreen() dismiss() diff --git a/app/src/main/res/drawable/ic_baseline_close_24.xml b/app/src/main/res/drawable/ic_baseline_close_24.xml new file mode 100644 index 000000000..1d6c00461 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_close_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/dialog_attachment.xml b/app/src/main/res/layout/dialog_attachment.xml index ed381203c..8280c8a90 100644 --- a/app/src/main/res/layout/dialog_attachment.xml +++ b/app/src/main/res/layout/dialog_attachment.xml @@ -39,6 +39,39 @@ android:textColor="@color/medium_emphasis_text" android:textSize="@dimen/bottom_sheet_text_size" /> + + + + + + + + + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2, + as published by the Free Software Foundation. + + 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 . +--> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/item_custom_outcoming_poll_message.xml b/app/src/main/res/layout/item_custom_outcoming_poll_message.xml index 0a52ee34b..9bfbf2adc 100644 --- a/app/src/main/res/layout/item_custom_outcoming_poll_message.xml +++ b/app/src/main/res/layout/item_custom_outcoming_poll_message.xml @@ -47,11 +47,36 @@ + android:gravity="center_vertical" + android:orientation="horizontal"> + + + + + + diff --git a/app/src/main/res/layout/poll_create_options_item.xml b/app/src/main/res/layout/poll_create_options_item.xml new file mode 100644 index 000000000..cfa9a0002 --- /dev/null +++ b/app/src/main/res/layout/poll_create_options_item.xml @@ -0,0 +1,27 @@ + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b0299a8f5..cab13f522 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -26,6 +26,7 @@ No Skip Set + Dismiss Sorry, something went wrong! Submit @@ -404,6 +405,7 @@ Add to conversation Take photo + Create poll Share from %1$s Sorry, upload failed Choose files @@ -536,6 +538,7 @@ Poll results - %1$s votes + Add Option Attachments