Compare commits
2 commits
83fc7ac7ab
...
afbe3598a3
Author | SHA1 | Date | |
---|---|---|---|
Peter Cai | afbe3598a3 | ||
Peter Cai | e7a50a0a43 |
|
@ -6,10 +6,6 @@ plugins {
|
||||||
android {
|
android {
|
||||||
compileSdk 31
|
compileSdk 31
|
||||||
|
|
||||||
buildFeatures {
|
|
||||||
viewBinding true
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "im.angry.openeuicc"
|
applicationId "im.angry.openeuicc"
|
||||||
minSdk 30
|
minSdk 30
|
||||||
|
|
|
@ -8,17 +8,19 @@ import android.view.LayoutInflater
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.widget.ImageButton
|
||||||
import android.widget.PopupMenu
|
import android.widget.PopupMenu
|
||||||
|
import android.widget.TextView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
|
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
import com.truphone.lpa.LocalProfileInfo
|
import com.truphone.lpa.LocalProfileInfo
|
||||||
import com.truphone.lpad.progress.Progress
|
import com.truphone.lpad.progress.Progress
|
||||||
import im.angry.openeuicc.R
|
import im.angry.openeuicc.R
|
||||||
import im.angry.openeuicc.databinding.EuiccProfileBinding
|
|
||||||
import im.angry.openeuicc.databinding.FragmentEuiccBinding
|
|
||||||
import im.angry.openeuicc.util.*
|
import im.angry.openeuicc.util.*
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
@ -33,8 +35,9 @@ class EuiccManagementFragment : Fragment(), EuiccFragmentMarker, EuiccProfilesCh
|
||||||
newInstanceEuicc(EuiccManagementFragment::class.java, slotId)
|
newInstanceEuicc(EuiccManagementFragment::class.java, slotId)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var _binding: FragmentEuiccBinding? = null
|
private lateinit var swipeRefresh: SwipeRefreshLayout
|
||||||
private val binding get() = _binding!!
|
private lateinit var fab: FloatingActionButton
|
||||||
|
private lateinit var profileList: RecyclerView
|
||||||
|
|
||||||
private val adapter = EuiccProfileAdapter(listOf())
|
private val adapter = EuiccProfileAdapter(listOf())
|
||||||
|
|
||||||
|
@ -43,18 +46,23 @@ class EuiccManagementFragment : Fragment(), EuiccFragmentMarker, EuiccProfilesCh
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View {
|
): View {
|
||||||
_binding = FragmentEuiccBinding.inflate(inflater, container, false)
|
val view = inflater.inflate(R.layout.fragment_euicc, container, false)
|
||||||
return binding.root
|
|
||||||
|
swipeRefresh = view.findViewById(R.id.swipe_refresh)
|
||||||
|
fab = view.findViewById(R.id.fab)
|
||||||
|
profileList = view.findViewById(R.id.profile_list)
|
||||||
|
|
||||||
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
binding.swipeRefresh.setOnRefreshListener { refresh() }
|
swipeRefresh.setOnRefreshListener { refresh() }
|
||||||
binding.profileList.adapter = adapter
|
profileList.adapter = adapter
|
||||||
binding.profileList.layoutManager =
|
profileList.layoutManager =
|
||||||
LinearLayoutManager(view.context, LinearLayoutManager.VERTICAL, false)
|
LinearLayoutManager(view.context, LinearLayoutManager.VERTICAL, false)
|
||||||
|
|
||||||
binding.fab.setOnClickListener {
|
fab.setOnClickListener {
|
||||||
ProfileDownloadFragment.newInstance(slotId)
|
ProfileDownloadFragment.newInstance(slotId)
|
||||||
.show(childFragmentManager, ProfileDownloadFragment.TAG)
|
.show(childFragmentManager, ProfileDownloadFragment.TAG)
|
||||||
}
|
}
|
||||||
|
@ -71,7 +79,7 @@ class EuiccManagementFragment : Fragment(), EuiccFragmentMarker, EuiccProfilesCh
|
||||||
|
|
||||||
@SuppressLint("NotifyDataSetChanged")
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
private fun refresh() {
|
private fun refresh() {
|
||||||
binding.swipeRefresh.isRefreshing = true
|
swipeRefresh.isRefreshing = true
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
val profiles = withContext(Dispatchers.IO) {
|
val profiles = withContext(Dispatchers.IO) {
|
||||||
|
@ -82,15 +90,15 @@ class EuiccManagementFragment : Fragment(), EuiccFragmentMarker, EuiccProfilesCh
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
adapter.profiles = profiles.operational
|
adapter.profiles = profiles.operational
|
||||||
adapter.notifyDataSetChanged()
|
adapter.notifyDataSetChanged()
|
||||||
binding.swipeRefresh.isRefreshing = false
|
swipeRefresh.isRefreshing = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun enableOrDisableProfile(iccid: String, enable: Boolean) {
|
private fun enableOrDisableProfile(iccid: String, enable: Boolean) {
|
||||||
binding.swipeRefresh.isRefreshing = true
|
swipeRefresh.isRefreshing = true
|
||||||
binding.swipeRefresh.isEnabled = false
|
swipeRefresh.isEnabled = false
|
||||||
binding.fab.isEnabled = false
|
fab.isEnabled = false
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
try {
|
try {
|
||||||
|
@ -106,8 +114,8 @@ class EuiccManagementFragment : Fragment(), EuiccFragmentMarker, EuiccProfilesCh
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.d(TAG, "Failed to enable / disable profile $iccid")
|
Log.d(TAG, "Failed to enable / disable profile $iccid")
|
||||||
Log.d(TAG, Log.getStackTraceString(e))
|
Log.d(TAG, Log.getStackTraceString(e))
|
||||||
binding.fab.isEnabled = true
|
fab.isEnabled = true
|
||||||
binding.swipeRefresh.isEnabled = true
|
swipeRefresh.isEnabled = true
|
||||||
Toast.makeText(context, R.string.toast_profile_enable_failed, Toast.LENGTH_LONG).show()
|
Toast.makeText(context, R.string.toast_profile_enable_failed, Toast.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,42 +131,48 @@ class EuiccManagementFragment : Fragment(), EuiccFragmentMarker, EuiccProfilesCh
|
||||||
channel.lpa.disableProfile(iccid, Progress())
|
channel.lpa.disableProfile(iccid, Progress())
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class ViewHolder(private val binding: EuiccProfileBinding) : RecyclerView.ViewHolder(binding.root) {
|
inner class ViewHolder(private val root: View) : RecyclerView.ViewHolder(root) {
|
||||||
|
private val iccid: TextView = root.findViewById(R.id.iccid)
|
||||||
|
private val name: TextView = root.findViewById(R.id.name)
|
||||||
|
private val state: TextView = root.findViewById(R.id.state)
|
||||||
|
private val provider: TextView = root.findViewById(R.id.provider)
|
||||||
|
private val profileMenu: ImageButton = root.findViewById(R.id.profile_menu)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
binding.iccid.setOnClickListener {
|
iccid.setOnClickListener {
|
||||||
if (binding.iccid.transformationMethod == null) {
|
if (iccid.transformationMethod == null) {
|
||||||
binding.iccid.transformationMethod = PasswordTransformationMethod.getInstance()
|
iccid.transformationMethod = PasswordTransformationMethod.getInstance()
|
||||||
} else {
|
} else {
|
||||||
binding.iccid.transformationMethod = null
|
iccid.transformationMethod = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.profileMenu.setOnClickListener { showOptionsMenu() }
|
profileMenu.setOnClickListener { showOptionsMenu() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var profile: LocalProfileInfo
|
private lateinit var profile: LocalProfileInfo
|
||||||
|
|
||||||
fun setProfile(profile: LocalProfileInfo) {
|
fun setProfile(profile: LocalProfileInfo) {
|
||||||
this.profile = profile
|
this.profile = profile
|
||||||
binding.name.text = profile.displayName
|
name.text = profile.displayName
|
||||||
|
|
||||||
binding.state.setText(
|
state.setText(
|
||||||
if (isEnabled()) {
|
if (isEnabled()) {
|
||||||
R.string.enabled
|
R.string.enabled
|
||||||
} else {
|
} else {
|
||||||
R.string.disabled
|
R.string.disabled
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
binding.provider.text = profile.providerName
|
provider.text = profile.providerName
|
||||||
binding.iccid.text = profile.iccid
|
iccid.text = profile.iccid
|
||||||
binding.iccid.transformationMethod = PasswordTransformationMethod.getInstance()
|
iccid.transformationMethod = PasswordTransformationMethod.getInstance()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isEnabled(): Boolean =
|
private fun isEnabled(): Boolean =
|
||||||
profile.state == LocalProfileInfo.State.Enabled
|
profile.state == LocalProfileInfo.State.Enabled
|
||||||
|
|
||||||
private fun showOptionsMenu() {
|
private fun showOptionsMenu() {
|
||||||
PopupMenu(binding.root.context, binding.profileMenu).apply {
|
PopupMenu(root.context, profileMenu).apply {
|
||||||
setOnMenuItemClickListener(::onMenuItemClicked)
|
setOnMenuItemClickListener(::onMenuItemClicked)
|
||||||
inflate(R.menu.profile_options)
|
inflate(R.menu.profile_options)
|
||||||
if (isEnabled()) {
|
if (isEnabled()) {
|
||||||
|
@ -197,9 +211,8 @@ class EuiccManagementFragment : Fragment(), EuiccFragmentMarker, EuiccProfilesCh
|
||||||
|
|
||||||
inner class EuiccProfileAdapter(var profiles: List<LocalProfileInfo>) : RecyclerView.Adapter<ViewHolder>() {
|
inner class EuiccProfileAdapter(var profiles: List<LocalProfileInfo>) : RecyclerView.Adapter<ViewHolder>() {
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
val binding =
|
val view = LayoutInflater.from(parent.context).inflate(R.layout.euicc_profile, parent, false)
|
||||||
EuiccProfileBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
return ViewHolder(view)
|
||||||
return ViewHolder(binding)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
|
|
|
@ -7,11 +7,13 @@ import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.Window
|
import android.view.Window
|
||||||
|
import android.widget.ProgressBar
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.appcompat.widget.Toolbar
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
import im.angry.openeuicc.R
|
import im.angry.openeuicc.R
|
||||||
import im.angry.openeuicc.databinding.FragmentProfileRenameBinding
|
|
||||||
import im.angry.openeuicc.util.setWidthPercent
|
import im.angry.openeuicc.util.setWidthPercent
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
@ -33,8 +35,9 @@ class ProfileRenameFragment : DialogFragment(), EuiccFragmentMarker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var _binding: FragmentProfileRenameBinding? = null
|
private lateinit var toolbar: Toolbar
|
||||||
private val binding get() = _binding!!
|
private lateinit var profileRenameNewName: TextInputLayout
|
||||||
|
private lateinit var progress: ProgressBar
|
||||||
|
|
||||||
private var renaming = false
|
private var renaming = false
|
||||||
|
|
||||||
|
@ -43,14 +46,18 @@ class ProfileRenameFragment : DialogFragment(), EuiccFragmentMarker {
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View {
|
): View {
|
||||||
_binding = FragmentProfileRenameBinding.inflate(inflater, container, false)
|
val view = inflater.inflate(R.layout.fragment_profile_rename, container, false)
|
||||||
binding.toolbar.inflateMenu(R.menu.fragment_profile_rename)
|
|
||||||
return binding.root
|
toolbar = view.findViewById(R.id.toolbar)
|
||||||
|
profileRenameNewName = view.findViewById(R.id.profile_rename_new_name)
|
||||||
|
progress = view.findViewById(R.id.progress)
|
||||||
|
|
||||||
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
binding.toolbar.apply {
|
toolbar.apply {
|
||||||
setTitle(R.string.rename)
|
setTitle(R.string.rename)
|
||||||
setNavigationOnClickListener {
|
setNavigationOnClickListener {
|
||||||
if (!renaming) dismiss()
|
if (!renaming) dismiss()
|
||||||
|
@ -64,7 +71,7 @@ class ProfileRenameFragment : DialogFragment(), EuiccFragmentMarker {
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
binding.profileRenameNewName.editText!!.setText(requireArguments().getString("currentName"))
|
profileRenameNewName.editText!!.setText(requireArguments().getString("currentName"))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
|
@ -80,15 +87,15 @@ class ProfileRenameFragment : DialogFragment(), EuiccFragmentMarker {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun rename() {
|
private fun rename() {
|
||||||
val name = binding.profileRenameNewName.editText!!.text.toString().trim()
|
val name = profileRenameNewName.editText!!.text.toString().trim()
|
||||||
if (name.length >= 64) {
|
if (name.length >= 64) {
|
||||||
Toast.makeText(context, R.string.toast_profile_name_too_long, Toast.LENGTH_LONG).show()
|
Toast.makeText(context, R.string.toast_profile_name_too_long, Toast.LENGTH_LONG).show()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
renaming = true
|
renaming = true
|
||||||
binding.progress.isIndeterminate = true
|
progress.isIndeterminate = true
|
||||||
binding.progress.visibility = View.VISIBLE
|
progress.visibility = View.VISIBLE
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
try {
|
try {
|
||||||
|
|
Loading…
Reference in a new issue