summaryrefslogtreecommitdiffstats
path: root/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/MessageDialogFragment.kt
blob: 685df0d59bf50ae5a8f732691c236bbbabe04f02 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

package org.yuzu.yuzu_emu.fragments

import android.app.Dialog
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.text.Html
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.ViewModelProvider
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.model.MessageDialogViewModel
import org.yuzu.yuzu_emu.utils.Log

class MessageDialogFragment : DialogFragment() {
    private val messageDialogViewModel: MessageDialogViewModel by activityViewModels()

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        val titleId = requireArguments().getInt(TITLE_ID)
        val title = if (titleId != 0) {
            getString(titleId)
        } else {
            requireArguments().getString(TITLE_STRING)!!
        }

        val descriptionId = requireArguments().getInt(DESCRIPTION_ID)
        val description = if (descriptionId != 0) {
            getString(descriptionId)
        } else {
            requireArguments().getString(DESCRIPTION_STRING)!!
        }

        val positiveButtonId = requireArguments().getInt(POSITIVE_BUTTON_TITLE_ID)
        val positiveButtonString = requireArguments().getString(POSITIVE_BUTTON_TITLE_STRING)!!
        val positiveButton = if (positiveButtonId != 0) {
            getString(positiveButtonId)
        } else if (positiveButtonString.isNotEmpty()) {
            positiveButtonString
        } else if (messageDialogViewModel.positiveAction != null) {
            getString(R.string.close)
        } else {
            getString(android.R.string.ok)
        }

        val negativeButtonId = requireArguments().getInt(NEGATIVE_BUTTON_TITLE_ID)
        val negativeButtonString = requireArguments().getString(NEGATIVE_BUTTON_TITLE_STRING)!!
        val negativeButton = if (negativeButtonId != 0) {
            getString(negativeButtonId)
        } else if (negativeButtonString.isNotEmpty()) {
            negativeButtonString
        } else {
            getString(android.R.string.cancel)
        }

        val helpLinkId = requireArguments().getInt(HELP_LINK)
        val dismissible = requireArguments().getBoolean(DISMISSIBLE)
        val clearPositiveAction = requireArguments().getBoolean(CLEAR_ACTIONS)
        val showNegativeButton = requireArguments().getBoolean(SHOW_NEGATIVE_BUTTON)

        val builder = MaterialAlertDialogBuilder(requireContext())

        if (clearPositiveAction) {
            messageDialogViewModel.positiveAction = null
        }

        builder.setPositiveButton(positiveButton) { _, _ ->
            messageDialogViewModel.positiveAction?.invoke()
        }
        if (messageDialogViewModel.negativeAction != null || showNegativeButton) {
            builder.setNegativeButton(negativeButton) { _, _ ->
                messageDialogViewModel.negativeAction?.invoke()
            }
        }

        if (title.isNotEmpty()) builder.setTitle(title)
        if (description.isNotEmpty()) {
            builder.setMessage(Html.fromHtml(description, Html.FROM_HTML_MODE_LEGACY))
        }

        if (helpLinkId != 0) {
            builder.setNeutralButton(R.string.learn_more) { _, _ ->
                openLink(getString(helpLinkId))
            }
        }

        isCancelable = dismissible

        return builder.show()
    }

    private fun openLink(link: String) {
        val intent = Intent(Intent.ACTION_VIEW, Uri.parse(link))
        startActivity(intent)
    }

    companion object {
        const val TAG = "MessageDialogFragment"

        private const val TITLE_ID = "Title"
        private const val TITLE_STRING = "TitleString"
        private const val DESCRIPTION_ID = "DescriptionId"
        private const val DESCRIPTION_STRING = "DescriptionString"
        private const val HELP_LINK = "Link"
        private const val DISMISSIBLE = "Dismissible"
        private const val CLEAR_ACTIONS = "ClearActions"
        private const val POSITIVE_BUTTON_TITLE_ID = "PositiveButtonTitleId"
        private const val POSITIVE_BUTTON_TITLE_STRING = "PositiveButtonTitleString"
        private const val SHOW_NEGATIVE_BUTTON = "ShowNegativeButton"
        private const val NEGATIVE_BUTTON_TITLE_ID = "NegativeButtonTitleId"
        private const val NEGATIVE_BUTTON_TITLE_STRING = "NegativeButtonTitleString"

        /**
         * Creates a new [MessageDialogFragment] instance.
         * @param activity Activity that will hold a [MessageDialogViewModel] instance if using
         * [positiveAction] or [negativeAction].
         * @param titleId String resource ID that will be used for the title. [titleString] used if 0.
         * @param titleString String that will be used for the title. No title is set if empty.
         * @param descriptionId String resource ID that will be used for the description.
         * [descriptionString] used if 0.
         * @param descriptionString String that will be used for the description.
         * No description is set if empty.
         * @param helpLinkId String resource ID that contains a help link. Will be added as a neutral
         * button with the title R.string.help.
         * @param dismissible Whether the dialog is dismissible or not. Typically used to ensure that
         * the user clicks on one of the dialog buttons before closing.
         * @param positiveButtonTitleId String resource ID that will be used for the positive button.
         * [positiveButtonTitleString] used if 0.
         * @param positiveButtonTitleString String that will be used for the positive button.
         * android.R.string.ok used if empty. android.R.string.close will be used if [positiveAction]
         * is not null.
         * @param positiveAction Lambda to run when the positive button is clicked.
         * @param showNegativeButton Normally the negative button isn't shown if there is no
         * [negativeAction] set. This can override that behavior to always show a button.
         * @param negativeButtonTitleId String resource ID that will be used for the negative button.
         * [negativeButtonTitleString] used if 0.
         * @param negativeButtonTitleString String that will be used for the negative button.
         * android.R.string.cancel used if empty.
         * @param negativeAction Lambda to run when the negative button is clicked
         */
        fun newInstance(
            activity: FragmentActivity? = null,
            titleId: Int = 0,
            titleString: String = "",
            descriptionId: Int = 0,
            descriptionString: String = "",
            helpLinkId: Int = 0,
            dismissible: Boolean = true,
            positiveButtonTitleId: Int = 0,
            positiveButtonTitleString: String = "",
            positiveAction: (() -> Unit)? = null,
            showNegativeButton: Boolean = false,
            negativeButtonTitleId: Int = 0,
            negativeButtonTitleString: String = "",
            negativeAction: (() -> Unit)? = null
        ): MessageDialogFragment {
            var clearActions = false
            if (activity != null) {
                ViewModelProvider(activity)[MessageDialogViewModel::class.java].apply {
                    clear()
                    this.positiveAction = positiveAction
                    this.negativeAction = negativeAction
                }
            } else {
                clearActions = true
            }

            if (activity == null && (positiveAction == null || negativeAction == null)) {
                Log.warning("[$TAG] Tried to set action with no activity!")
            }

            val dialog = MessageDialogFragment()
            val bundle = Bundle().apply {
                putInt(TITLE_ID, titleId)
                putString(TITLE_STRING, titleString)
                putInt(DESCRIPTION_ID, descriptionId)
                putString(DESCRIPTION_STRING, descriptionString)
                putInt(HELP_LINK, helpLinkId)
                putBoolean(DISMISSIBLE, dismissible)
                putBoolean(CLEAR_ACTIONS, clearActions)
                putInt(POSITIVE_BUTTON_TITLE_ID, positiveButtonTitleId)
                putString(POSITIVE_BUTTON_TITLE_STRING, positiveButtonTitleString)
                putBoolean(SHOW_NEGATIVE_BUTTON, showNegativeButton)
                putInt(NEGATIVE_BUTTON_TITLE_ID, negativeButtonTitleId)
                putString(NEGATIVE_BUTTON_TITLE_STRING, negativeButtonTitleString)
            }
            dialog.arguments = bundle
            return dialog
        }
    }
}