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.EditText
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.fragment.app.DialogFragment
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import im.angry.openeuicc.common.R
|
import im.angry.openeuicc.common.R
|
||||||
import im.angry.openeuicc.service.EuiccChannelManagerService.Companion.waitDone
|
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.flow.onStart
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class ProfileDeleteFragment : DialogFragment(), EuiccChannelFragmentMarker {
|
class ProfileDeleteFragment : BaseMaterialDialogFragment(), EuiccChannelFragmentMarker {
|
||||||
companion object {
|
companion object {
|
||||||
const val TAG = "ProfileDeleteFragment"
|
const val TAG = "ProfileDeleteFragment"
|
||||||
private const val FIELD_ICCID = "iccid"
|
private const val FIELD_ICCID = "iccid"
|
||||||
|
@ -92,11 +91,7 @@ class ProfileDeleteFragment : DialogFragment(), EuiccChannelFragmentMarker {
|
||||||
ensureEuiccChannelManager()
|
ensureEuiccChannelManager()
|
||||||
euiccChannelManagerService.waitForForegroundTask()
|
euiccChannelManagerService.waitForForegroundTask()
|
||||||
euiccChannelManagerService.launchProfileDeleteTask(slotId, portId, iccid).onStart {
|
euiccChannelManagerService.launchProfileDeleteTask(slotId, portId, iccid).onStart {
|
||||||
if (parentFragment is EuiccProfilesChangedListener) {
|
notifyEuiccProfilesChanged()
|
||||||
// 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()
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
dismiss()
|
dismiss()
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
package im.angry.openeuicc.ui
|
package im.angry.openeuicc.ui
|
||||||
|
|
||||||
import android.app.Dialog
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.widget.EditText
|
||||||
import android.widget.ProgressBar
|
import android.widget.ProgressBar
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
|
import androidx.core.widget.addTextChangedListener
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.google.android.material.textfield.TextInputLayout
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
import im.angry.openeuicc.common.R
|
import im.angry.openeuicc.common.R
|
||||||
|
@ -19,37 +20,62 @@ import net.typeblog.lpac_jni.LocalProfileAssistant
|
||||||
class ProfileRenameFragment : BaseMaterialDialogFragment(), EuiccChannelFragmentMarker {
|
class ProfileRenameFragment : BaseMaterialDialogFragment(), EuiccChannelFragmentMarker {
|
||||||
companion object {
|
companion object {
|
||||||
const val TAG = "ProfileRenameFragment"
|
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 {
|
fun newInstance(slotId: Int, portId: Int, iccid: String, currentName: String) =
|
||||||
val instance = newInstanceEuicc(ProfileRenameFragment::class.java, slotId, portId)
|
newInstanceEuicc(ProfileRenameFragment::class.java, slotId, portId) {
|
||||||
instance.requireArguments().apply {
|
putString(FIELD_ICCID, iccid)
|
||||||
putString("iccid", iccid)
|
putString(FIELD_CURRENT_NAME, currentName)
|
||||||
putString("currentName", currentName)
|
|
||||||
}
|
}
|
||||||
return instance
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var toolbar: Toolbar
|
private lateinit var toolbar: Toolbar
|
||||||
private lateinit var profileRenameNewName: TextInputLayout
|
private lateinit var editText: EditText
|
||||||
private lateinit var progress: ProgressBar
|
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
|
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(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View {
|
): View = inflater.inflate(R.layout.fragment_profile_rename, container, false).apply {
|
||||||
val view = inflater.inflate(R.layout.fragment_profile_rename, container, false)
|
toolbar = requireViewById<Toolbar>(R.id.toolbar).apply {
|
||||||
|
inflateMenu(R.menu.fragment_profile_rename)
|
||||||
toolbar = view.requireViewById(R.id.toolbar)
|
}
|
||||||
profileRenameNewName = view.requireViewById(R.id.profile_rename_new_name)
|
editText = requireViewById<TextInputLayout>(R.id.profile_rename_new_name).editText!!.apply {
|
||||||
progress = view.requireViewById(R.id.progress)
|
addTextChangedListener {
|
||||||
|
val isUnchanged = currentName == editedName
|
||||||
toolbar.inflateMenu(R.menu.fragment_profile_rename)
|
dialog!!.setCancelable(isUnchanged)
|
||||||
|
dialog!!.setCanceledOnTouchOutside(isUnchanged)
|
||||||
return view
|
}
|
||||||
|
}
|
||||||
|
progress = requireViewById(R.id.progress)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
@ -60,15 +86,24 @@ class ProfileRenameFragment : BaseMaterialDialogFragment(), EuiccChannelFragment
|
||||||
if (!renaming) dismiss()
|
if (!renaming) dismiss()
|
||||||
}
|
}
|
||||||
setOnMenuItemClickListener {
|
setOnMenuItemClickListener {
|
||||||
if (!renaming) rename()
|
if (!renaming) lifecycleScope.launch {
|
||||||
|
renaming = true
|
||||||
|
invokeRename()
|
||||||
|
renaming = false
|
||||||
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
super.onStart()
|
super.onSaveInstanceState(outState)
|
||||||
profileRenameNewName.editText!!.setText(requireArguments().getString("currentName"))
|
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() {
|
override fun onResume() {
|
||||||
|
@ -76,63 +111,41 @@ class ProfileRenameFragment : BaseMaterialDialogFragment(), EuiccChannelFragment
|
||||||
setWidthPercent(95)
|
setWidthPercent(95)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
private suspend fun invokeRename() {
|
||||||
return super.onCreateDialog(savedInstanceState).also {
|
toast = null
|
||||||
it.setCanceledOnTouchOutside(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showErrorAndCancel(errorStrRes: Int) {
|
ensureEuiccChannelManager()
|
||||||
Toast.makeText(
|
euiccChannelManagerService.waitForForegroundTask()
|
||||||
requireContext(),
|
|
||||||
errorStrRes,
|
|
||||||
Toast.LENGTH_LONG
|
|
||||||
).show()
|
|
||||||
|
|
||||||
renaming = false
|
val throwable = euiccChannelManagerService
|
||||||
progress.visibility = View.GONE
|
.launchProfileRenameTask(slotId, portId, iccid, editedName)
|
||||||
}
|
.waitDone()
|
||||||
|
|
||||||
private fun rename() {
|
val toastResId = when (throwable) {
|
||||||
renaming = true
|
is LocalProfileAssistant.ProfileNameTooLongException ->
|
||||||
progress.isIndeterminate = true
|
R.string.profile_rename_too_long
|
||||||
progress.visibility = View.VISIBLE
|
is LocalProfileAssistant.ProfileNameIsInvalidUTF8Exception ->
|
||||||
|
R.string.profile_rename_encoding_error
|
||||||
lifecycleScope.launch {
|
is Throwable ->
|
||||||
ensureEuiccChannelManager()
|
R.string.profile_rename_failure
|
||||||
euiccChannelManagerService.waitForForegroundTask()
|
else -> {
|
||||||
val res = euiccChannelManagerService.launchProfileRenameTask(
|
notifyEuiccProfilesChanged()
|
||||||
slotId,
|
try {
|
||||||
portId,
|
dismiss()
|
||||||
requireArguments().getString("iccid")!!,
|
} catch (e: IllegalStateException) {
|
||||||
profileRenameNewName.editText!!.text.toString().trim()
|
// Ignored
|
||||||
).waitDone()
|
|
||||||
|
|
||||||
when (res) {
|
|
||||||
is LocalProfileAssistant.ProfileNameTooLongException -> {
|
|
||||||
showErrorAndCancel(R.string.profile_rename_too_long)
|
|
||||||
}
|
}
|
||||||
|
when {
|
||||||
is LocalProfileAssistant.ProfileNameIsInvalidUTF8Exception -> {
|
editedName.isEmpty() ->
|
||||||
showErrorAndCancel(R.string.profile_rename_encoding_error)
|
R.string.profile_rename_restore_defaults
|
||||||
}
|
editedName == currentName ->
|
||||||
|
R.string.profile_rename_unchanged
|
||||||
is Throwable -> {
|
else -> null
|
||||||
showErrorAndCancel(R.string.profile_rename_failure)
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
if (parentFragment is EuiccProfilesChangedListener) {
|
|
||||||
(parentFragment as EuiccProfilesChangedListener).onEuiccProfilesChanged()
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
dismiss()
|
|
||||||
} catch (e: IllegalStateException) {
|
|
||||||
// Ignored
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
// in the definition of an interface, so the only way is to limit where the extension functions
|
||||||
// can be applied.
|
// can be applied.
|
||||||
fun <T> newInstanceEuicc(clazz: Class<T>, slotId: Int, portId: Int, addArguments: Bundle.() -> Unit = {}): T where T: Fragment, T: EuiccChannelFragmentMarker {
|
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 {
|
instance.arguments = Bundle().apply {
|
||||||
putInt("slotId", slotId)
|
putInt("slotId", slotId)
|
||||||
putInt("portId", portId)
|
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
|
val <T> T.euiccChannelManagerService: EuiccChannelManagerService where T: Fragment, T: OpenEuiccContextMarker
|
||||||
get() = (requireActivity() as BaseEuiccAccessActivity).euiccChannelManagerService
|
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 {
|
suspend fun <T, R> T.withEuiccChannel(fn: suspend (EuiccChannel) -> R): R where T : Fragment, T : EuiccChannelFragmentMarker {
|
||||||
ensureEuiccChannelManager()
|
ensureEuiccChannelManager()
|
||||||
return euiccChannelManager.withEuiccChannel(slotId, portId, fn)
|
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="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_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_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_too_long">Nickname is too long</string>
|
||||||
<string name="profile_rename_failure">Unknown failure when renaming profile</string>
|
<string name="profile_rename_failure">Unknown failure when renaming profile</string>
|
||||||
|
|
Loading…
Add table
Reference in a new issue