| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- package im.angry.openeuicc.ui
- import android.annotation.SuppressLint
- import android.os.Bundle
- import android.text.Html
- import android.view.ContextMenu
- import android.view.LayoutInflater
- import android.view.Menu
- import android.view.MenuItem
- import android.view.MenuItem.OnMenuItemClickListener
- import android.view.View
- import android.view.ViewGroup
- import android.widget.TextView
- import androidx.appcompat.app.AlertDialog
- import androidx.appcompat.app.AppCompatActivity
- import androidx.core.view.forEach
- import androidx.lifecycle.lifecycleScope
- import androidx.recyclerview.widget.DividerItemDecoration
- import androidx.recyclerview.widget.LinearLayoutManager
- import androidx.recyclerview.widget.RecyclerView
- import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
- import im.angry.openeuicc.OpenEuiccApplication
- import im.angry.openeuicc.common.R
- import im.angry.openeuicc.core.EuiccChannel
- import im.angry.openeuicc.util.displayName
- import kotlinx.coroutines.Dispatchers
- import kotlinx.coroutines.launch
- import kotlinx.coroutines.withContext
- import net.typeblog.lpac_jni.LocalProfileNotification
- class NotificationsActivity: AppCompatActivity() {
- private lateinit var swipeRefresh: SwipeRefreshLayout
- private lateinit var notificationList: RecyclerView
- private val notificationAdapter = NotificationAdapter()
- private lateinit var euiccChannel: EuiccChannel
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_notifications)
- supportActionBar!!.setDisplayHomeAsUpEnabled(true)
- euiccChannel = (application as OpenEuiccApplication).euiccChannelManager
- .findEuiccChannelBySlotBlocking(intent.getIntExtra("logicalSlotId", 0))!!
- swipeRefresh = findViewById(R.id.swipe_refresh)
- notificationList = findViewById(R.id.recycler_view)
- notificationList.layoutManager =
- LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
- notificationList.addItemDecoration(DividerItemDecoration(this, LinearLayoutManager.VERTICAL))
- notificationList.adapter = notificationAdapter
- registerForContextMenu(notificationList)
- swipeRefresh.setOnRefreshListener {
- refresh()
- }
- refresh()
- }
- override fun onCreateOptionsMenu(menu: Menu?): Boolean {
- super.onCreateOptionsMenu(menu)
- menuInflater.inflate(R.menu.activity_notifications, menu)
- return true
- }
- override fun onOptionsItemSelected(item: MenuItem): Boolean =
- when (item.itemId) {
- android.R.id.home -> {
- finish()
- true
- }
- R.id.help -> {
- AlertDialog.Builder(this, R.style.AlertDialogTheme).apply {
- setMessage(R.string.profile_notifications_help)
- setPositiveButton(android.R.string.ok) { dialog, _ ->
- dialog.dismiss()
- }
- show()
- }
- true
- }
- else -> super.onOptionsItemSelected(item)
- }
- private fun launchTask(task: suspend () -> Unit) {
- swipeRefresh.isRefreshing = true
- lifecycleScope.launch {
- task()
- swipeRefresh.isRefreshing = false
- }
- }
- private fun refresh() {
- launchTask {
- val profiles = withContext(Dispatchers.IO) {
- euiccChannel.lpa.profiles
- }
- notificationAdapter.notifications =
- withContext(Dispatchers.IO) {
- euiccChannel.lpa.notifications.map {
- val profile = profiles.find { p -> p.iccid == it.iccid }
- LocalProfileNotificationWrapper(it, profile?.displayName ?: "???")
- }
- }
- }
- }
- data class LocalProfileNotificationWrapper(
- val inner: LocalProfileNotification,
- val profileName: String
- )
- @SuppressLint("ClickableViewAccessibility")
- inner class NotificationViewHolder(private val root: View):
- RecyclerView.ViewHolder(root), View.OnCreateContextMenuListener, OnMenuItemClickListener {
- private val address: TextView = root.findViewById(R.id.notification_address)
- private val profileName: TextView = root.findViewById(R.id.notification_profile_name)
- private lateinit var notification: LocalProfileNotificationWrapper
- private var lastTouchX = 0f
- private var lastTouchY = 0f
- init {
- root.isClickable = true
- root.setOnCreateContextMenuListener(this)
- root.setOnTouchListener { _, event ->
- lastTouchX = event.x
- lastTouchY = event.y
- false
- }
- root.setOnLongClickListener {
- root.showContextMenu(lastTouchX, lastTouchY)
- true
- }
- }
- private fun operationToLocalizedText(operation: LocalProfileNotification.Operation) =
- root.context.getText(
- when (operation) {
- LocalProfileNotification.Operation.Install -> R.string.profile_notification_operation_download
- LocalProfileNotification.Operation.Delete -> R.string.profile_notification_operation_delete
- LocalProfileNotification.Operation.Enable -> R.string.profile_notification_operation_enable
- LocalProfileNotification.Operation.Disable -> R.string.profile_notification_operation_disable
- })
- fun updateNotification(value: LocalProfileNotificationWrapper) {
- notification = value
- address.text = value.inner.notificationAddress
- profileName.text = Html.fromHtml(
- root.context.getString(R.string.profile_notification_name_format,
- operationToLocalizedText(value.inner.profileManagementOperation),
- value.profileName, value.inner.iccid),
- Html.FROM_HTML_MODE_COMPACT)
- }
- override fun onCreateContextMenu(
- menu: ContextMenu?,
- v: View?,
- menuInfo: ContextMenu.ContextMenuInfo?
- ) {
- menuInflater.inflate(R.menu.notification_options, menu)
- menu!!.forEach {
- it.setOnMenuItemClickListener(this)
- }
- }
- override fun onMenuItemClick(item: MenuItem): Boolean =
- when (item.itemId) {
- R.id.notification_process -> {
- launchTask {
- withContext(Dispatchers.IO) {
- euiccChannel.lpa.handleNotification(notification.inner.seqNumber)
- }
- }
- refresh()
- true
- }
- R.id.notification_delete -> {
- launchTask {
- withContext(Dispatchers.IO) {
- euiccChannel.lpa.deleteNotification(notification.inner.seqNumber)
- }
- }
- refresh()
- true
- }
- else -> false
- }
- }
- inner class NotificationAdapter: RecyclerView.Adapter<NotificationViewHolder>() {
- var notifications: List<LocalProfileNotificationWrapper> = listOf()
- @SuppressLint("NotifyDataSetChanged")
- set(value) {
- field = value
- notifyDataSetChanged()
- }
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NotificationViewHolder {
- val root = LayoutInflater.from(parent.context)
- .inflate(R.layout.notification_item, parent, false)
- return NotificationViewHolder(root)
- }
- override fun getItemCount(): Int = notifications.size
- override fun onBindViewHolder(holder: NotificationViewHolder, position: Int) =
- holder.updateNotification(notifications[position])
- }
- }
|