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