Compare commits

..

No commits in common. "afbe3598a355421f3e2fccd04ffe5fc2589c4c35" and "83fc7ac7ab58a6e019f8829146521b20a40280c3" have entirely different histories.

3 changed files with 47 additions and 63 deletions

View file

@ -6,6 +6,10 @@ plugins {
android { android {
compileSdk 31 compileSdk 31
buildFeatures {
viewBinding true
}
defaultConfig { defaultConfig {
applicationId "im.angry.openeuicc" applicationId "im.angry.openeuicc"
minSdk 30 minSdk 30

View file

@ -8,19 +8,17 @@ 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
@ -35,9 +33,8 @@ class EuiccManagementFragment : Fragment(), EuiccFragmentMarker, EuiccProfilesCh
newInstanceEuicc(EuiccManagementFragment::class.java, slotId) newInstanceEuicc(EuiccManagementFragment::class.java, slotId)
} }
private lateinit var swipeRefresh: SwipeRefreshLayout private var _binding: FragmentEuiccBinding? = null
private lateinit var fab: FloatingActionButton private val binding get() = _binding!!
private lateinit var profileList: RecyclerView
private val adapter = EuiccProfileAdapter(listOf()) private val adapter = EuiccProfileAdapter(listOf())
@ -46,23 +43,18 @@ class EuiccManagementFragment : Fragment(), EuiccFragmentMarker, EuiccProfilesCh
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View { ): View {
val view = inflater.inflate(R.layout.fragment_euicc, container, false) _binding = FragmentEuiccBinding.inflate(inflater, 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)
swipeRefresh.setOnRefreshListener { refresh() } binding.swipeRefresh.setOnRefreshListener { refresh() }
profileList.adapter = adapter binding.profileList.adapter = adapter
profileList.layoutManager = binding.profileList.layoutManager =
LinearLayoutManager(view.context, LinearLayoutManager.VERTICAL, false) LinearLayoutManager(view.context, LinearLayoutManager.VERTICAL, false)
fab.setOnClickListener { binding.fab.setOnClickListener {
ProfileDownloadFragment.newInstance(slotId) ProfileDownloadFragment.newInstance(slotId)
.show(childFragmentManager, ProfileDownloadFragment.TAG) .show(childFragmentManager, ProfileDownloadFragment.TAG)
} }
@ -79,7 +71,7 @@ class EuiccManagementFragment : Fragment(), EuiccFragmentMarker, EuiccProfilesCh
@SuppressLint("NotifyDataSetChanged") @SuppressLint("NotifyDataSetChanged")
private fun refresh() { private fun refresh() {
swipeRefresh.isRefreshing = true binding.swipeRefresh.isRefreshing = true
lifecycleScope.launch { lifecycleScope.launch {
val profiles = withContext(Dispatchers.IO) { val profiles = withContext(Dispatchers.IO) {
@ -90,15 +82,15 @@ class EuiccManagementFragment : Fragment(), EuiccFragmentMarker, EuiccProfilesCh
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
adapter.profiles = profiles.operational adapter.profiles = profiles.operational
adapter.notifyDataSetChanged() adapter.notifyDataSetChanged()
swipeRefresh.isRefreshing = false binding.swipeRefresh.isRefreshing = false
} }
} }
} }
private fun enableOrDisableProfile(iccid: String, enable: Boolean) { private fun enableOrDisableProfile(iccid: String, enable: Boolean) {
swipeRefresh.isRefreshing = true binding.swipeRefresh.isRefreshing = true
swipeRefresh.isEnabled = false binding.swipeRefresh.isEnabled = false
fab.isEnabled = false binding.fab.isEnabled = false
lifecycleScope.launch { lifecycleScope.launch {
try { try {
@ -114,8 +106,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))
fab.isEnabled = true binding.fab.isEnabled = true
swipeRefresh.isEnabled = true binding.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()
} }
} }
@ -131,48 +123,42 @@ class EuiccManagementFragment : Fragment(), EuiccFragmentMarker, EuiccProfilesCh
channel.lpa.disableProfile(iccid, Progress()) channel.lpa.disableProfile(iccid, Progress())
} }
inner class ViewHolder(private val root: View) : RecyclerView.ViewHolder(root) { inner class ViewHolder(private val binding: EuiccProfileBinding) : RecyclerView.ViewHolder(binding.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 {
iccid.setOnClickListener { binding.iccid.setOnClickListener {
if (iccid.transformationMethod == null) { if (binding.iccid.transformationMethod == null) {
iccid.transformationMethod = PasswordTransformationMethod.getInstance() binding.iccid.transformationMethod = PasswordTransformationMethod.getInstance()
} else { } else {
iccid.transformationMethod = null binding.iccid.transformationMethod = null
} }
} }
profileMenu.setOnClickListener { showOptionsMenu() } binding.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
name.text = profile.displayName binding.name.text = profile.displayName
state.setText( binding.state.setText(
if (isEnabled()) { if (isEnabled()) {
R.string.enabled R.string.enabled
} else { } else {
R.string.disabled R.string.disabled
} }
) )
provider.text = profile.providerName binding.provider.text = profile.providerName
iccid.text = profile.iccid binding.iccid.text = profile.iccid
iccid.transformationMethod = PasswordTransformationMethod.getInstance() binding.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(root.context, profileMenu).apply { PopupMenu(binding.root.context, binding.profileMenu).apply {
setOnMenuItemClickListener(::onMenuItemClicked) setOnMenuItemClickListener(::onMenuItemClicked)
inflate(R.menu.profile_options) inflate(R.menu.profile_options)
if (isEnabled()) { if (isEnabled()) {
@ -211,8 +197,9 @@ 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 view = LayoutInflater.from(parent.context).inflate(R.layout.euicc_profile, parent, false) val binding =
return ViewHolder(view) EuiccProfileBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(binding)
} }
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun onBindViewHolder(holder: ViewHolder, position: Int) {

View file

@ -7,13 +7,11 @@ 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
@ -35,9 +33,8 @@ class ProfileRenameFragment : DialogFragment(), EuiccFragmentMarker {
} }
} }
private lateinit var toolbar: Toolbar private var _binding: FragmentProfileRenameBinding? = null
private lateinit var profileRenameNewName: TextInputLayout private val binding get() = _binding!!
private lateinit var progress: ProgressBar
private var renaming = false private var renaming = false
@ -46,18 +43,14 @@ class ProfileRenameFragment : DialogFragment(), EuiccFragmentMarker {
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View { ): View {
val view = inflater.inflate(R.layout.fragment_profile_rename, container, false) _binding = FragmentProfileRenameBinding.inflate(inflater, container, false)
binding.toolbar.inflateMenu(R.menu.fragment_profile_rename)
toolbar = view.findViewById(R.id.toolbar) return binding.root
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)
toolbar.apply { binding.toolbar.apply {
setTitle(R.string.rename) setTitle(R.string.rename)
setNavigationOnClickListener { setNavigationOnClickListener {
if (!renaming) dismiss() if (!renaming) dismiss()
@ -71,7 +64,7 @@ class ProfileRenameFragment : DialogFragment(), EuiccFragmentMarker {
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
profileRenameNewName.editText!!.setText(requireArguments().getString("currentName")) binding.profileRenameNewName.editText!!.setText(requireArguments().getString("currentName"))
} }
override fun onResume() { override fun onResume() {
@ -87,15 +80,15 @@ class ProfileRenameFragment : DialogFragment(), EuiccFragmentMarker {
} }
private fun rename() { private fun rename() {
val name = profileRenameNewName.editText!!.text.toString().trim() val name = binding.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
progress.isIndeterminate = true binding.progress.isIndeterminate = true
progress.visibility = View.VISIBLE binding.progress.visibility = View.VISIBLE
lifecycleScope.launch { lifecycleScope.launch {
try { try {