/* * Nextcloud Android client application * * @author Tobias Kaminsky * Copyright (C) 2020 Nextcloud GmbH * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE * License as published by the Free Software Foundation; either * version 3 of the License, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. * * You should have received a copy of the GNU Affero General Public * License along with this program. If not, see . */ package com.nextcloud.ui import android.accounts.Account import android.annotation.SuppressLint import android.app.Dialog import android.content.Context import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.view.inputmethod.InputMethodManager import androidx.annotation.VisibleForTesting import androidx.emoji.bundled.BundledEmojiCompatConfig import androidx.emoji.text.EmojiCompat import androidx.fragment.app.DialogFragment import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.core.AsyncRunner import com.nextcloud.client.di.Injectable import com.nextcloud.client.network.ClientFactory import com.owncloud.android.R import com.owncloud.android.datamodel.ArbitraryDataProvider import com.owncloud.android.lib.common.OwnCloudClientFactory import com.owncloud.android.lib.resources.users.ClearStatusMessageRemoteOperation import com.owncloud.android.lib.resources.users.PredefinedStatus import com.owncloud.android.lib.resources.users.SetPredefinedCustomStatusMessageRemoteOperation import com.owncloud.android.lib.resources.users.SetStatusRemoteOperation import com.owncloud.android.lib.resources.users.SetUserDefinedCustomStatusMessageRemoteOperation import com.owncloud.android.lib.resources.users.Status import com.owncloud.android.lib.resources.users.StatusType import com.owncloud.android.ui.activity.BaseActivity import com.owncloud.android.ui.adapter.PredefinedStatusClickListener import com.owncloud.android.ui.adapter.PredefinedStatusListAdapter import com.vanniktech.emoji.EmojiManager import com.vanniktech.emoji.EmojiPopup import com.vanniktech.emoji.googlecompat.GoogleCompatEmojiProvider import kotlinx.android.synthetic.main.dialog_set_status.* import java.util.ArrayList import javax.inject.Inject private const val ARG_CURRENT_USER_PARAM = "currentUser" private const val ARG_CURRENT_STATUS_PARAM = "currentStatus" class SetStatusDialogFragment : DialogFragment(), PredefinedStatusClickListener, Injectable { private lateinit var dialogView: View private var currentUser: User? = null private var currentStatus: Status? = null private lateinit var accountManager: UserAccountManager private lateinit var predefinedStatus: ArrayList private lateinit var adapter: PredefinedStatusListAdapter private var selectedPredefinedMessageId: String? = null private lateinit var popup: EmojiPopup @Inject lateinit var arbitraryDataProvider: ArbitraryDataProvider @Inject lateinit var asyncRunner: AsyncRunner @Inject lateinit var clientFactory: ClientFactory override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) arguments?.let { currentUser = it.getParcelable(ARG_CURRENT_USER_PARAM) currentStatus = it.getParcelable(ARG_CURRENT_STATUS_PARAM) val json = arbitraryDataProvider.getValue(currentUser, ArbitraryDataProvider.PREDEFINED_STATUS) if (json.isNotEmpty()) { val myType = object : TypeToken>() {}.type predefinedStatus = Gson().fromJson(json, myType) } } val config = BundledEmojiCompatConfig(requireContext()) config.setReplaceAll(true) val emojiCompat = EmojiCompat.init(config) EmojiManager.install(GoogleCompatEmojiProvider(emojiCompat)) } @SuppressLint("InflateParams") override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_set_status, null) return MaterialAlertDialogBuilder(requireContext()) .setView(dialogView) .create() } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) accountManager = (activity as BaseActivity).userAccountManager currentStatus?.let { emoji.setText(it.icon) customStatusInput.text.clear() customStatusInput.setText(it.message) } adapter = PredefinedStatusListAdapter(this, requireContext()) if (this::predefinedStatus.isInitialized) { adapter.list = predefinedStatus } predefinedStatusList.adapter = adapter predefinedStatusList.layoutManager = LinearLayoutManager(context) onlineStatus.setOnClickListener { setStatus(StatusType.ONLINE) } dndStatus.setOnClickListener { setStatus(StatusType.DND) } awayStatus.setOnClickListener { setStatus(StatusType.AWAY) } invisibleStatus.setOnClickListener { setStatus(StatusType.INVISIBLE) } clearStatus.setOnClickListener { clearStatus() } setStatus.setOnClickListener { setStatusMessage() } emoji.setOnClickListener { openEmojiPopup() } popup = EmojiPopup.Builder .fromRootView(view) .setOnEmojiClickListener { _, _ -> popup.dismiss() emoji.clearFocus() val imm: InputMethodManager = context?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager imm.hideSoftInputFromWindow(emoji.windowToken, 0) } .build(emoji) emoji.disableKeyboardInput(popup) emoji.forceSingleEmoji() } private fun openEmojiPopup() { popup.show() } private fun clearStatus() { asyncRunner.postQuickTask(ClearStatusTask(accountManager.currentOwnCloudAccount?.savedAccount, context), { dismiss(it) }) } private fun setStatus(statusType: StatusType) { asyncRunner.postQuickTask( SetStatusTask( statusType, accountManager.currentOwnCloudAccount?.savedAccount, context) ) } private fun setStatusMessage() { if (selectedPredefinedMessageId != null) { asyncRunner.postQuickTask( SetPredefinedCustomStatusTask( selectedPredefinedMessageId!!, 1603719631, accountManager.currentOwnCloudAccount?.savedAccount, context), { dismiss(it) } ) } else { asyncRunner.postQuickTask( SetUserDefinedCustomStatusTask( customStatusInput.text.toString(), emoji.text.toString(), 1603719631, accountManager.currentOwnCloudAccount?.savedAccount, context), { dismiss(it) } ) } } private fun dismiss(boolean: Boolean) { if (boolean) { dismiss() } } private class SetPredefinedCustomStatusTask(val messageId: String, val clearAt: Long, val account: Account?, val context: Context?) : Function0 { override fun invoke(): Boolean { val client = OwnCloudClientFactory.createNextcloudClient(account, context) return SetPredefinedCustomStatusMessageRemoteOperation(messageId, clearAt).execute(client).isSuccess } } private class SetUserDefinedCustomStatusTask(val message: String, val icon: String, val clearAt: Long, val account: Account?, val context: Context?) : Function0 { override fun invoke(): Boolean { val client = OwnCloudClientFactory.createNextcloudClient(account, context) return SetUserDefinedCustomStatusMessageRemoteOperation(message, icon, clearAt).execute(client).isSuccess } } private class SetStatusTask(val statusType: StatusType, val account: Account?, val context: Context?) : Function0 { override fun invoke(): Boolean { val client = OwnCloudClientFactory.createNextcloudClient(account, context) return SetStatusRemoteOperation(statusType).execute(client).isSuccess } } private class ClearStatusTask(val account: Account?, val context: Context?) : Function0 { override fun invoke(): Boolean { val client = OwnCloudClientFactory.createNextcloudClient(account, context) return ClearStatusMessageRemoteOperation().execute(client).isSuccess } } /** * Fragment creator */ companion object { @JvmStatic fun newInstance(user: User, status: Status?) = SetStatusDialogFragment().apply { arguments = Bundle().apply { putParcelable(ARG_CURRENT_USER_PARAM, user) putParcelable(ARG_CURRENT_STATUS_PARAM, status) } } } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return dialogView } override fun onClick(predefinedStatus: PredefinedStatus) { selectedPredefinedMessageId = predefinedStatus.id emoji.setText(predefinedStatus.icon) customStatusInput.text.clear() customStatusInput.text.append(predefinedStatus.message) } @VisibleForTesting fun setPredefinedStatus(predefinedStatus: ArrayList) { adapter.list = predefinedStatus predefinedStatusList.adapter?.notifyDataSetChanged() } }