WIP: refactor: profile rename #121
4 changed files with 97 additions and 82 deletions
|
@ -6,7 +6,6 @@ import android.text.Editable
|
|||
import android.widget.EditText
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import im.angry.openeuicc.common.R
|
||||
import im.angry.openeuicc.service.EuiccChannelManagerService.Companion.waitDone
|
||||
|
@ -14,7 +13,7 @@ import im.angry.openeuicc.util.*
|
|||
import kotlinx.coroutines.flow.onStart
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class ProfileDeleteFragment : DialogFragment(), EuiccChannelFragmentMarker {
|
||||
class ProfileDeleteFragment : BaseMaterialDialogFragment(), EuiccChannelFragmentMarker {
|
||||
companion object {
|
||||
const val TAG = "ProfileDeleteFragment"
|
||||
private const val FIELD_ICCID = "iccid"
|
||||
|
@ -92,11 +91,7 @@ class ProfileDeleteFragment : DialogFragment(), EuiccChannelFragmentMarker {
|
|||
ensureEuiccChannelManager()
|
||||
euiccChannelManagerService.waitForForegroundTask()
|
||||
euiccChannelManagerService.launchProfileDeleteTask(slotId, portId, iccid).onStart {
|
||||
if (parentFragment is EuiccProfilesChangedListener) {
|
||||
// Trigger a refresh in the parent fragment -- it should wait until
|
||||
// any foreground task is completed before actually doing a refresh
|
||||
(parentFragment as EuiccProfilesChangedListener).onEuiccProfilesChanged()
|
||||
}
|
||||
notifyEuiccProfilesChanged()
|
||||
|
||||
try {
|
||||
dismiss()
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
package im.angry.openeuicc.ui
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.EditText
|
||||
import android.widget.ProgressBar
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.widget.addTextChangedListener
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import im.angry.openeuicc.common.R
|
||||
|
@ -19,37 +20,62 @@ import net.typeblog.lpac_jni.LocalProfileAssistant
|
|||
class ProfileRenameFragment : BaseMaterialDialogFragment(), EuiccChannelFragmentMarker {
|
||||
companion object {
|
||||
const val TAG = "ProfileRenameFragment"
|
||||
const val FIELD_ICCID = "iccid"
|
||||
const val FIELD_CURRENT_NAME = "currentName"
|
||||
const val FIELD_EDITED_NAME = "editedName"
|
||||
|
||||
fun newInstance(slotId: Int, portId: Int, iccid: String, currentName: String): ProfileRenameFragment {
|
||||
val instance = newInstanceEuicc(ProfileRenameFragment::class.java, slotId, portId)
|
||||
instance.requireArguments().apply {
|
||||
putString("iccid", iccid)
|
||||
putString("currentName", currentName)
|
||||
fun newInstance(slotId: Int, portId: Int, iccid: String, currentName: String) =
|
||||
newInstanceEuicc(ProfileRenameFragment::class.java, slotId, portId) {
|
||||
putString(FIELD_ICCID, iccid)
|
||||
putString(FIELD_CURRENT_NAME, currentName)
|
||||
}
|
||||
return instance
|
||||
}
|
||||
}
|
||||
|
||||
private lateinit var toolbar: Toolbar
|
||||
private lateinit var profileRenameNewName: TextInputLayout
|
||||
private lateinit var editText: EditText
|
||||
private lateinit var progress: ProgressBar
|
||||
|
||||
private val iccid by lazy {
|
||||
requireArguments().getString(FIELD_ICCID)!!
|
||||
}
|
||||
|
||||
private val currentName by lazy {
|
||||
requireArguments().getString(FIELD_CURRENT_NAME)!!
|
||||
}
|
||||
|
||||
private val editedName: String
|
||||
get() = editText.text.toString().trim()
|
||||
|
||||
private var renaming = false
|
||||
set(value) {
|
||||
progress.isIndeterminate = value
|
||||
progress.visibility = if (value) View.VISIBLE else View.GONE
|
||||
field = value
|
||||
}
|
||||
|
||||
private var toast: Toast? = null
|
||||
set(value) {
|
||||
field?.cancel()
|
||||
field = value
|
||||
field?.show()
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
val view = inflater.inflate(R.layout.fragment_profile_rename, container, false)
|
||||
|
||||
toolbar = view.requireViewById(R.id.toolbar)
|
||||
profileRenameNewName = view.requireViewById(R.id.profile_rename_new_name)
|
||||
progress = view.requireViewById(R.id.progress)
|
||||
|
||||
toolbar.inflateMenu(R.menu.fragment_profile_rename)
|
||||
|
||||
return view
|
||||
): View = inflater.inflate(R.layout.fragment_profile_rename, container, false).apply {
|
||||
toolbar = requireViewById<Toolbar>(R.id.toolbar).apply {
|
||||
inflateMenu(R.menu.fragment_profile_rename)
|
||||
}
|
||||
editText = requireViewById<TextInputLayout>(R.id.profile_rename_new_name).editText!!.apply {
|
||||
addTextChangedListener {
|
||||
val isUnchanged = currentName == editedName
|
||||
dialog!!.setCancelable(isUnchanged)
|
||||
dialog!!.setCanceledOnTouchOutside(isUnchanged)
|
||||
}
|
||||
}
|
||||
progress = requireViewById(R.id.progress)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
|
@ -60,15 +86,24 @@ class ProfileRenameFragment : BaseMaterialDialogFragment(), EuiccChannelFragment
|
|||
if (!renaming) dismiss()
|
||||
}
|
||||
setOnMenuItemClickListener {
|
||||
if (!renaming) rename()
|
||||
if (!renaming) lifecycleScope.launch {
|
||||
renaming = true
|
||||
invokeRename()
|
||||
renaming = false
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
profileRenameNewName.editText!!.setText(requireArguments().getString("currentName"))
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
outState.putString(FIELD_EDITED_NAME, editedName)
|
||||
}
|
||||
|
||||
override fun onViewStateRestored(savedInstanceState: Bundle?) {
|
||||
super.onViewStateRestored(savedInstanceState)
|
||||
editText.setText(savedInstanceState?.getString(FIELD_EDITED_NAME) ?: currentName)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
|
@ -76,63 +111,41 @@ class ProfileRenameFragment : BaseMaterialDialogFragment(), EuiccChannelFragment
|
|||
setWidthPercent(95)
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
return super.onCreateDialog(savedInstanceState).also {
|
||||
it.setCanceledOnTouchOutside(false)
|
||||
}
|
||||
}
|
||||
private suspend fun invokeRename() {
|
||||
toast = null
|
||||
|
||||
private fun showErrorAndCancel(errorStrRes: Int) {
|
||||
Toast.makeText(
|
||||
requireContext(),
|
||||
errorStrRes,
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
ensureEuiccChannelManager()
|
||||
euiccChannelManagerService.waitForForegroundTask()
|
||||
|
||||
renaming = false
|
||||
progress.visibility = View.GONE
|
||||
}
|
||||
val throwable = euiccChannelManagerService
|
||||
.launchProfileRenameTask(slotId, portId, iccid, editedName)
|
||||
.waitDone()
|
||||
|
||||
private fun rename() {
|
||||
renaming = true
|
||||
progress.isIndeterminate = true
|
||||
progress.visibility = View.VISIBLE
|
||||
|
||||
lifecycleScope.launch {
|
||||
ensureEuiccChannelManager()
|
||||
euiccChannelManagerService.waitForForegroundTask()
|
||||
val res = euiccChannelManagerService.launchProfileRenameTask(
|
||||
slotId,
|
||||
portId,
|
||||
requireArguments().getString("iccid")!!,
|
||||
profileRenameNewName.editText!!.text.toString().trim()
|
||||
).waitDone()
|
||||
|
||||
when (res) {
|
||||
is LocalProfileAssistant.ProfileNameTooLongException -> {
|
||||
showErrorAndCancel(R.string.profile_rename_too_long)
|
||||
val toastResId = when (throwable) {
|
||||
is LocalProfileAssistant.ProfileNameTooLongException ->
|
||||
R.string.profile_rename_too_long
|
||||
is LocalProfileAssistant.ProfileNameIsInvalidUTF8Exception ->
|
||||
R.string.profile_rename_encoding_error
|
||||
is Throwable ->
|
||||
R.string.profile_rename_failure
|
||||
else -> {
|
||||
notifyEuiccProfilesChanged()
|
||||
try {
|
||||
dismiss()
|
||||
} catch (e: IllegalStateException) {
|
||||
// Ignored
|
||||
}
|
||||
|
||||
is LocalProfileAssistant.ProfileNameIsInvalidUTF8Exception -> {
|
||||
showErrorAndCancel(R.string.profile_rename_encoding_error)
|
||||
}
|
||||
|
||||
is Throwable -> {
|
||||
showErrorAndCancel(R.string.profile_rename_failure)
|
||||
}
|
||||
|
||||
else -> {
|
||||
if (parentFragment is EuiccProfilesChangedListener) {
|
||||
(parentFragment as EuiccProfilesChangedListener).onEuiccProfilesChanged()
|
||||
}
|
||||
|
||||
try {
|
||||
dismiss()
|
||||
} catch (e: IllegalStateException) {
|
||||
// Ignored
|
||||
}
|
||||
when {
|
||||
editedName.isEmpty() ->
|
||||
R.string.profile_rename_restore_defaults
|
||||
editedName == currentName ->
|
||||
R.string.profile_rename_unchanged
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (toastResId != null) toast = Toast
|
||||
.makeText(requireContext(), toastResId, Toast.LENGTH_LONG)
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@ interface EuiccChannelFragmentMarker: OpenEuiccContextMarker
|
|||
// in the definition of an interface, so the only way is to limit where the extension functions
|
||||
// can be applied.
|
||||
fun <T> newInstanceEuicc(clazz: Class<T>, slotId: Int, portId: Int, addArguments: Bundle.() -> Unit = {}): T where T: Fragment, T: EuiccChannelFragmentMarker {
|
||||
val instance = clazz.newInstance()
|
||||
val instance = clazz.getDeclaredConstructor().newInstance()
|
||||
instance.arguments = Bundle().apply {
|
||||
putInt("slotId", slotId)
|
||||
putInt("portId", portId)
|
||||
|
@ -37,6 +37,11 @@ val <T> T.euiccChannelManager: EuiccChannelManager where T: Fragment, T: OpenEui
|
|||
val <T> T.euiccChannelManagerService: EuiccChannelManagerService where T: Fragment, T: OpenEuiccContextMarker
|
||||
get() = (requireActivity() as BaseEuiccAccessActivity).euiccChannelManagerService
|
||||
|
||||
fun <T> T.notifyEuiccProfilesChanged() where T : Fragment, T : OpenEuiccContextMarker {
|
||||
val fragment = parentFragment
|
||||
if (fragment is EuiccProfilesChangedListener) fragment.onEuiccProfilesChanged()
|
||||
}
|
||||
|
||||
suspend fun <T, R> T.withEuiccChannel(fn: suspend (EuiccChannel) -> R): R where T : Fragment, T : EuiccChannelFragmentMarker {
|
||||
ensureEuiccChannelManager()
|
||||
return euiccChannelManager.withEuiccChannel(slotId, portId, fn)
|
||||
|
|
|
@ -96,6 +96,8 @@
|
|||
<string name="logs_saved_message">Logs have been saved to the selected path. Would you like to share the log through another app?</string>
|
||||
|
||||
<string name="profile_rename_new_name">New nickname</string>
|
||||
<string name="profile_rename_unchanged">The profile nickname is unchanged</string>
|
||||
<string name="profile_rename_restore_defaults">The profile nickname restored to defaults</string>
|
||||
<string name="profile_rename_encoding_error">Failed to encode nickname as UTF-8</string>
|
||||
<string name="profile_rename_too_long">Nickname is too long</string>
|
||||
<string name="profile_rename_failure">Unknown failure when renaming profile</string>
|
||||
|
|
Loading…
Add table
Reference in a new issue