From 73437f81a4f0ed051953496bef482089e2b22341 Mon Sep 17 00:00:00 2001 From: Rohit Jakhar Date: Wed, 22 Nov 2023 12:11:17 +0530 Subject: [PATCH 01/14] Add Multiple Section in transaction list. Add support for share selected Transaction as text and har file type. Add support for delete selected transaction only. --- .../HttpTransactionDatabaseRepository.kt | 6 +++ .../repository/HttpTransactionRepository.kt | 3 ++ .../internal/data/room/HttpTransactionDao.kt | 6 +++ .../chucker/internal/ui/MainActivity.kt | 37 +++++++++++++---- .../chucker/internal/ui/MainViewModel.kt | 8 ++++ .../ui/transaction/TransactionAdapter.kt | 41 ++++++++++++++++--- library/src/main/res/values/strings.xml | 3 ++ 7 files changed, 91 insertions(+), 13 deletions(-) diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/repository/HttpTransactionDatabaseRepository.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/repository/HttpTransactionDatabaseRepository.kt index 6171e7a82..c97bcc144 100644 --- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/repository/HttpTransactionDatabaseRepository.kt +++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/repository/HttpTransactionDatabaseRepository.kt @@ -36,6 +36,10 @@ internal class HttpTransactionDatabaseRepository(private val database: ChuckerDa transactionDao.deleteAll() } + override suspend fun deleteSelectedTransactions(selectedTransactions: List) { + transactionDao.deleteSelected(selectedTransactions) + } + override suspend fun insertTransaction(transaction: HttpTransaction) { val id = transactionDao.insert(transaction) transaction.id = id ?: 0 @@ -55,4 +59,6 @@ internal class HttpTransactionDatabaseRepository(private val database: ChuckerDa val timestamp = minTimestamp ?: 0L return transactionDao.getTransactionsInTimeRange(timestamp) } + + override suspend fun getSelectedTransactions(selectedTransactions: List): List = transactionDao.getSelectedTransactions(selectedTransactions) } diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/repository/HttpTransactionRepository.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/repository/HttpTransactionRepository.kt index 8ab3f6cbe..1fb1abe44 100644 --- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/repository/HttpTransactionRepository.kt +++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/repository/HttpTransactionRepository.kt @@ -18,6 +18,7 @@ internal interface HttpTransactionRepository { suspend fun deleteOldTransactions(threshold: Long) suspend fun deleteAllTransactions() + suspend fun deleteSelectedTransactions(selectedTransactions: List) fun getSortedTransactionTuples(): LiveData> @@ -28,4 +29,6 @@ internal interface HttpTransactionRepository { suspend fun getAllTransactions(): List fun getTransactionsInTimeRange(minTimestamp: Long?): List + + suspend fun getSelectedTransactions(selectedTransactions: List): List } diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/room/HttpTransactionDao.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/room/HttpTransactionDao.kt index 4a81f7724..c6f389045 100644 --- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/room/HttpTransactionDao.kt +++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/room/HttpTransactionDao.kt @@ -40,6 +40,9 @@ internal interface HttpTransactionDao { @Query("DELETE FROM transactions") suspend fun deleteAll(): Int + @Query("DELETE FROM transactions WHERE id IN (:selectedTransactions)") + suspend fun deleteSelected(selectedTransactions: List) + @Query("SELECT * FROM transactions WHERE id = :id") fun getById(id: Long): LiveData @@ -49,6 +52,9 @@ internal interface HttpTransactionDao { @Query("SELECT * FROM transactions") suspend fun getAll(): List + @Query("SELECT * FROM transactions WHERE id IN (:selectedTransactions)") + suspend fun getSelectedTransactions(selectedTransactions: List): List + @Query("SELECT * FROM transactions WHERE requestDate >= :timestamp") fun getTransactionsInTimeRange(timestamp: Long): List } diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt index febc46aa8..bcbab6533 100644 --- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt +++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt @@ -8,6 +8,7 @@ import android.os.Build import android.os.Bundle import android.provider.Settings import android.text.method.LinkMovementMethod +import android.util.Log import android.view.Menu import android.view.MenuItem import android.widget.Toast @@ -46,6 +47,8 @@ internal class MainActivity : private lateinit var mainBinding: ChuckerActivityMainBinding private lateinit var transactionsAdapter: TransactionAdapter + private var isMultipleSelect: Boolean = false + private val selectedId = mutableListOf() private val applicationName: CharSequence get() = applicationInfo.loadLabel(packageManager) @@ -66,9 +69,21 @@ internal class MainActivity : super.onCreate(savedInstanceState) mainBinding = ChuckerActivityMainBinding.inflate(layoutInflater) - transactionsAdapter = TransactionAdapter(this) { transactionId -> - TransactionActivity.start(this, transactionId) - } + transactionsAdapter = + TransactionAdapter(this, longPress = { + isMultipleSelect = true + selectedId.add(it) + }, onTransactionClick = { transactionId -> + if (isMultipleSelect && selectedId.isNotEmpty()) { + if (selectedId.contains(transactionId)) selectedId.remove(transactionId) else selectedId.add( + transactionId + ) + true + } else { + TransactionActivity.start(this, transactionId) + false + } + }) with(mainBinding) { setContentView(root) @@ -109,6 +124,7 @@ internal class MainActivity : ) == PackageManager.PERMISSION_GRANTED -> { /* We have permission, all good */ } + shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS) -> { Snackbar.make( mainBinding.root, @@ -123,6 +139,7 @@ internal class MainActivity : } }.show() } + else -> { permissionRequest.launch(Manifest.permission.POST_NOTIFICATIONS) } @@ -148,15 +165,16 @@ internal class MainActivity : showDialog( getClearDialogData(), onPositiveClick = { - viewModel.clearTransactions() + if (selectedId.isNotEmpty()) viewModel.clearSelectedTransactions(selectedId) else viewModel.clearTransactions() }, onNegativeClick = null ) true } + R.id.share_text -> { showDialog( - getExportDialogData(R.string.chucker_export_text_http_confirmation), + getExportDialogData(if (selectedId.isNotEmpty()) R.string.chucker_export_text_selected_http_confirmation else R.string.chucker_export_text_http_confirmation), onPositiveClick = { exportTransactions(EXPORT_TXT_FILE_NAME) { transactions -> TransactionListDetailsSharable(transactions, encodeUrls = false) @@ -166,9 +184,10 @@ internal class MainActivity : ) true } + R.id.share_har -> { showDialog( - getExportDialogData(R.string.chucker_export_har_http_confirmation), + getExportDialogData(if (selectedId.isNotEmpty()) R.string.chucker_export_har_selected_http_confirmation else R.string.chucker_export_har_http_confirmation), onPositiveClick = { exportTransactions(EXPORT_HAR_FILE_NAME) { transactions -> TransactionDetailsHarSharable( @@ -184,6 +203,7 @@ internal class MainActivity : ) true } + else -> { super.onOptionsItemSelected(item) } @@ -203,7 +223,8 @@ internal class MainActivity : ) { val applicationContext = this.applicationContext lifecycleScope.launch { - val transactions = viewModel.getAllTransactions() + val transactions = + if (selectedId.isNotEmpty()) viewModel.getSelectedTransactions(selectedId) else viewModel.getAllTransactions() if (transactions.isEmpty()) { showToast(applicationContext.getString(R.string.chucker_export_empty_text)) return@launch @@ -229,7 +250,7 @@ internal class MainActivity : private fun getClearDialogData(): DialogData = DialogData( title = getString(R.string.chucker_clear), - message = getString(R.string.chucker_clear_http_confirmation), + message = getString(if (selectedId.isNotEmpty()) R.string.chucker_clear_selected_http_confirmation else R.string.chucker_clear_http_confirmation), positiveButtonText = getString(R.string.chucker_clear), negativeButtonText = getString(R.string.chucker_cancel) ) diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainViewModel.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainViewModel.kt index 9e8e943ee..3bc3c8ae5 100644 --- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainViewModel.kt +++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainViewModel.kt @@ -34,6 +34,8 @@ internal class MainViewModel : ViewModel() { suspend fun getAllTransactions(): List = RepositoryProvider.transaction().getAllTransactions() + suspend fun getSelectedTransactions(transactionId: List): List = RepositoryProvider.transaction().getSelectedTransactions(transactionId) + fun updateItemsFilter(searchQuery: String) { currentFilter.value = searchQuery } @@ -44,4 +46,10 @@ internal class MainViewModel : ViewModel() { } NotificationHelper.clearBuffer() } + + fun clearSelectedTransactions(selectedTransaction: List) { + viewModelScope.launch { + RepositoryProvider.transaction().deleteSelectedTransactions(selectedTransaction) + } + } } diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/transaction/TransactionAdapter.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/transaction/TransactionAdapter.kt index 9896f380e..66c21452f 100644 --- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/transaction/TransactionAdapter.kt +++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/transaction/TransactionAdapter.kt @@ -3,6 +3,8 @@ package com.chuckerteam.chucker.internal.ui.transaction import android.annotation.SuppressLint import android.content.Context import android.content.res.ColorStateList +import android.util.Log +import android.util.TypedValue import android.view.LayoutInflater import android.view.ViewGroup import androidx.appcompat.content.res.AppCompatResources @@ -16,16 +18,19 @@ import com.chuckerteam.chucker.databinding.ChuckerListItemTransactionBinding import com.chuckerteam.chucker.internal.data.entity.HttpTransaction import com.chuckerteam.chucker.internal.data.entity.HttpTransactionTuple import com.chuckerteam.chucker.internal.support.TransactionDiffCallback +import okhttp3.internal.notify import java.text.DateFormat import javax.net.ssl.HttpsURLConnection internal class TransactionAdapter internal constructor( context: Context, - private val onTransactionClick: (Long) -> Unit + private val onTransactionClick: (Long) -> Boolean, + private val longPress: (Long) -> Boolean ) : ListAdapter( TransactionDiffCallback ) { + private val selectedPos = mutableListOf() private val colorDefault: Int = ContextCompat.getColor(context, R.color.chucker_status_default) private val colorRequested: Int = ContextCompat.getColor( context, @@ -35,6 +40,9 @@ internal class TransactionAdapter internal constructor( private val color500: Int = ContextCompat.getColor(context, R.color.chucker_status_500) private val color400: Int = ContextCompat.getColor(context, R.color.chucker_status_400) private val color300: Int = ContextCompat.getColor(context, R.color.chucker_status_300) + val outValue = TypedValue() + private val defaultColor = context.theme.resolveAttribute(android.R.attr.selectableItemBackground, outValue, true) + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TransactionViewHolder { val viewBinding = ChuckerListItemTransactionBinding.inflate( @@ -57,15 +65,38 @@ internal class TransactionAdapter internal constructor( init { itemView.setOnClickListener { transactionId?.let { - onTransactionClick.invoke(it) + if (onTransactionClick.invoke(it) && selectedPos.isNotEmpty()) { + if (selectedPos.contains(adapterPosition)) { + selectedPos.remove(adapterPosition) + } else { + selectedPos.add(adapterPosition) + } + notifyItemChanged(adapterPosition) + } } } + itemView.setOnLongClickListener { + transactionId?.let { + longPress.invoke(it) + if (selectedPos.contains(adapterPosition)) { + selectedPos.remove(adapterPosition) + } else { + selectedPos.add(adapterPosition) + } + notifyItemChanged(adapterPosition) + true + } ?: kotlin.run { false } + } } @SuppressLint("SetTextI18n") fun bind(transaction: HttpTransactionTuple) { transactionId = transaction.id - + if (selectedPos.find { it == adapterPosition } != null) { + itemView.setBackgroundColor(color400) + } else { + itemView.setBackgroundResource(outValue.resourceId) + } itemBinding.apply { displayGraphQlFields(transaction.graphQlOperationName, transaction.graphQlDetected) path.text = "${transaction.method} ${transaction.getFormattedPath(encode = false)}" @@ -87,7 +118,6 @@ internal class TransactionAdapter internal constructor( code.text = "!!!" } } - setStatusColor(transaction) } @@ -128,6 +158,7 @@ private fun ChuckerListItemTransactionBinding.displayGraphQlFields( graphqlPath.isVisible = graphQLDetected if (graphQLDetected) { - graphqlPath.text = graphQlOperationName ?: root.resources.getString(R.string.chucker_graphql_operation_is_empty) + graphqlPath.text = graphQlOperationName + ?: root.resources.getString(R.string.chucker_graphql_operation_is_empty) } } diff --git a/library/src/main/res/values/strings.xml b/library/src/main/res/values/strings.xml index ad7313078..e88f7f65e 100644 --- a/library/src/main/res/values/strings.xml +++ b/library/src/main/res/values/strings.xml @@ -47,7 +47,10 @@ Transaction details All transactions Do you want to clear complete network calls history? + Do you want to clear selected network calls history? Do you want to export all network transactions as a text file? + Do you want to export selected network transactions as a text file? + Do you want to export selected network transactions as a .har file? Do you want to export all network transactions as a .har file? ================== /* Export Start */ From 6a9eb8d647b3f60322fecdae4f2d64cf1b9c17a6 Mon Sep 17 00:00:00 2001 From: Rohit Jakhar Date: Wed, 22 Nov 2023 12:57:42 +0530 Subject: [PATCH 02/14] Fix variable naming. Fix Adapter parameters. --- .../HttpTransactionDatabaseRepository.kt | 5 ++- .../repository/HttpTransactionRepository.kt | 1 + .../chucker/internal/ui/MainActivity.kt | 41 +++++++++---------- .../chucker/internal/ui/MainViewModel.kt | 2 +- .../ui/transaction/TransactionAdapter.kt | 10 ++--- 5 files changed, 31 insertions(+), 28 deletions(-) diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/repository/HttpTransactionDatabaseRepository.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/repository/HttpTransactionDatabaseRepository.kt index c97bcc144..2aaf9d114 100644 --- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/repository/HttpTransactionDatabaseRepository.kt +++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/repository/HttpTransactionDatabaseRepository.kt @@ -60,5 +60,8 @@ internal class HttpTransactionDatabaseRepository(private val database: ChuckerDa return transactionDao.getTransactionsInTimeRange(timestamp) } - override suspend fun getSelectedTransactions(selectedTransactions: List): List = transactionDao.getSelectedTransactions(selectedTransactions) + override suspend fun getSelectedTransactions(selectedTransactions: List): List { + return transactionDao.getSelectedTransactions(selectedTransactions) + } + } diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/repository/HttpTransactionRepository.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/repository/HttpTransactionRepository.kt index 1fb1abe44..de2da004d 100644 --- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/repository/HttpTransactionRepository.kt +++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/repository/HttpTransactionRepository.kt @@ -18,6 +18,7 @@ internal interface HttpTransactionRepository { suspend fun deleteOldTransactions(threshold: Long) suspend fun deleteAllTransactions() + suspend fun deleteSelectedTransactions(selectedTransactions: List) fun getSortedTransactionTuples(): LiveData> diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt index bcbab6533..fc43d6d66 100644 --- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt +++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt @@ -8,7 +8,6 @@ import android.os.Build import android.os.Bundle import android.provider.Settings import android.text.method.LinkMovementMethod -import android.util.Log import android.view.Menu import android.view.MenuItem import android.widget.Toast @@ -47,8 +46,7 @@ internal class MainActivity : private lateinit var mainBinding: ChuckerActivityMainBinding private lateinit var transactionsAdapter: TransactionAdapter - private var isMultipleSelect: Boolean = false - private val selectedId = mutableListOf() + private val selectedTransactions = mutableListOf() private val applicationName: CharSequence get() = applicationInfo.loadLabel(packageManager) @@ -70,20 +68,21 @@ internal class MainActivity : mainBinding = ChuckerActivityMainBinding.inflate(layoutInflater) transactionsAdapter = - TransactionAdapter(this, longPress = { - isMultipleSelect = true - selectedId.add(it) - }, onTransactionClick = { transactionId -> - if (isMultipleSelect && selectedId.isNotEmpty()) { - if (selectedId.contains(transactionId)) selectedId.remove(transactionId) else selectedId.add( - transactionId - ) - true - } else { - TransactionActivity.start(this, transactionId) - false + TransactionAdapter( + context = this, + longPress = { transactionId -> + selectedTransactions.add(transactionId) + }, + onTransactionClick = { transactionId -> + if (selectedTransactions.isNotEmpty()) { + if (selectedTransactions.contains(transactionId)) selectedTransactions.remove(transactionId) else selectedTransactions.add( + transactionId + ) + } else { + TransactionActivity.start(this, transactionId) + } } - }) + ) with(mainBinding) { setContentView(root) @@ -165,7 +164,7 @@ internal class MainActivity : showDialog( getClearDialogData(), onPositiveClick = { - if (selectedId.isNotEmpty()) viewModel.clearSelectedTransactions(selectedId) else viewModel.clearTransactions() + if (selectedTransactions.isNotEmpty()) viewModel.clearSelectedTransactions(selectedTransactions) else viewModel.clearTransactions() }, onNegativeClick = null ) @@ -174,7 +173,7 @@ internal class MainActivity : R.id.share_text -> { showDialog( - getExportDialogData(if (selectedId.isNotEmpty()) R.string.chucker_export_text_selected_http_confirmation else R.string.chucker_export_text_http_confirmation), + getExportDialogData(if (selectedTransactions.isNotEmpty()) R.string.chucker_export_text_selected_http_confirmation else R.string.chucker_export_text_http_confirmation), onPositiveClick = { exportTransactions(EXPORT_TXT_FILE_NAME) { transactions -> TransactionListDetailsSharable(transactions, encodeUrls = false) @@ -187,7 +186,7 @@ internal class MainActivity : R.id.share_har -> { showDialog( - getExportDialogData(if (selectedId.isNotEmpty()) R.string.chucker_export_har_selected_http_confirmation else R.string.chucker_export_har_http_confirmation), + getExportDialogData(if (selectedTransactions.isNotEmpty()) R.string.chucker_export_har_selected_http_confirmation else R.string.chucker_export_har_http_confirmation), onPositiveClick = { exportTransactions(EXPORT_HAR_FILE_NAME) { transactions -> TransactionDetailsHarSharable( @@ -224,7 +223,7 @@ internal class MainActivity : val applicationContext = this.applicationContext lifecycleScope.launch { val transactions = - if (selectedId.isNotEmpty()) viewModel.getSelectedTransactions(selectedId) else viewModel.getAllTransactions() + if (selectedTransactions.isNotEmpty()) viewModel.getSelectedTransactions(selectedTransactions) else viewModel.getAllTransactions() if (transactions.isEmpty()) { showToast(applicationContext.getString(R.string.chucker_export_empty_text)) return@launch @@ -250,7 +249,7 @@ internal class MainActivity : private fun getClearDialogData(): DialogData = DialogData( title = getString(R.string.chucker_clear), - message = getString(if (selectedId.isNotEmpty()) R.string.chucker_clear_selected_http_confirmation else R.string.chucker_clear_http_confirmation), + message = getString(if (selectedTransactions.isNotEmpty()) R.string.chucker_clear_selected_http_confirmation else R.string.chucker_clear_http_confirmation), positiveButtonText = getString(R.string.chucker_clear), negativeButtonText = getString(R.string.chucker_cancel) ) diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainViewModel.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainViewModel.kt index 3bc3c8ae5..5798f2b83 100644 --- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainViewModel.kt +++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainViewModel.kt @@ -34,7 +34,7 @@ internal class MainViewModel : ViewModel() { suspend fun getAllTransactions(): List = RepositoryProvider.transaction().getAllTransactions() - suspend fun getSelectedTransactions(transactionId: List): List = RepositoryProvider.transaction().getSelectedTransactions(transactionId) + suspend fun getSelectedTransactions(selectedTransaction: List): List = RepositoryProvider.transaction().getSelectedTransactions(selectedTransaction) fun updateItemsFilter(searchQuery: String) { currentFilter.value = searchQuery diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/transaction/TransactionAdapter.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/transaction/TransactionAdapter.kt index 66c21452f..f171c5066 100644 --- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/transaction/TransactionAdapter.kt +++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/transaction/TransactionAdapter.kt @@ -3,7 +3,6 @@ package com.chuckerteam.chucker.internal.ui.transaction import android.annotation.SuppressLint import android.content.Context import android.content.res.ColorStateList -import android.util.Log import android.util.TypedValue import android.view.LayoutInflater import android.view.ViewGroup @@ -18,14 +17,13 @@ import com.chuckerteam.chucker.databinding.ChuckerListItemTransactionBinding import com.chuckerteam.chucker.internal.data.entity.HttpTransaction import com.chuckerteam.chucker.internal.data.entity.HttpTransactionTuple import com.chuckerteam.chucker.internal.support.TransactionDiffCallback -import okhttp3.internal.notify import java.text.DateFormat import javax.net.ssl.HttpsURLConnection internal class TransactionAdapter internal constructor( context: Context, - private val onTransactionClick: (Long) -> Boolean, - private val longPress: (Long) -> Boolean + private val onTransactionClick: (Long) -> Unit, + private val longPress: (Long) -> Unit ) : ListAdapter( TransactionDiffCallback ) { @@ -65,7 +63,8 @@ internal class TransactionAdapter internal constructor( init { itemView.setOnClickListener { transactionId?.let { - if (onTransactionClick.invoke(it) && selectedPos.isNotEmpty()) { + onTransactionClick.invoke(it) + if (selectedPos.isNotEmpty()) { if (selectedPos.contains(adapterPosition)) { selectedPos.remove(adapterPosition) } else { @@ -75,6 +74,7 @@ internal class TransactionAdapter internal constructor( } } } + itemView.setOnLongClickListener { transactionId?.let { longPress.invoke(it) From abdb4c53852da859437dacc10f6c622011b764d3 Mon Sep 17 00:00:00 2001 From: Rohit Jakhar Date: Thu, 23 Nov 2023 13:52:37 +0530 Subject: [PATCH 03/14] Fix ktlint --- .../repository/HttpTransactionDatabaseRepository.kt | 1 - .../chuckerteam/chucker/internal/ui/MainActivity.kt | 10 +++++++--- .../internal/ui/transaction/TransactionAdapter.kt | 1 - 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/repository/HttpTransactionDatabaseRepository.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/repository/HttpTransactionDatabaseRepository.kt index 2aaf9d114..2ae42328f 100644 --- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/repository/HttpTransactionDatabaseRepository.kt +++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/repository/HttpTransactionDatabaseRepository.kt @@ -63,5 +63,4 @@ internal class HttpTransactionDatabaseRepository(private val database: ChuckerDa override suspend fun getSelectedTransactions(selectedTransactions: List): List { return transactionDao.getSelectedTransactions(selectedTransactions) } - } diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt index fc43d6d66..50b6ad96d 100644 --- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt +++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt @@ -75,9 +75,13 @@ internal class MainActivity : }, onTransactionClick = { transactionId -> if (selectedTransactions.isNotEmpty()) { - if (selectedTransactions.contains(transactionId)) selectedTransactions.remove(transactionId) else selectedTransactions.add( - transactionId - ) + if (selectedTransactions.contains(transactionId)) { + selectedTransactions.remove(transactionId) + } else { + selectedTransactions.add( + transactionId + ) + } } else { TransactionActivity.start(this, transactionId) } diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/transaction/TransactionAdapter.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/transaction/TransactionAdapter.kt index f171c5066..10b3242e3 100644 --- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/transaction/TransactionAdapter.kt +++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/transaction/TransactionAdapter.kt @@ -41,7 +41,6 @@ internal class TransactionAdapter internal constructor( val outValue = TypedValue() private val defaultColor = context.theme.resolveAttribute(android.R.attr.selectableItemBackground, outValue, true) - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TransactionViewHolder { val viewBinding = ChuckerListItemTransactionBinding.inflate( LayoutInflater.from(parent.context), From 0850127ea1d88801c8e4507b1bd15f283cefd261 Mon Sep 17 00:00:00 2001 From: Rohit Jakhar Date: Sun, 26 Nov 2023 10:43:01 +0530 Subject: [PATCH 04/14] Concise code. Co-authored-by: Nicola Corti --- .../kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt index 50b6ad96d..13ba9fc96 100644 --- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt +++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt @@ -75,7 +75,7 @@ internal class MainActivity : }, onTransactionClick = { transactionId -> if (selectedTransactions.isNotEmpty()) { - if (selectedTransactions.contains(transactionId)) { + if (transactionId in selectedTransactions) { selectedTransactions.remove(transactionId) } else { selectedTransactions.add( From d80d38697735dc3b0d41f231c69add86c3572fad Mon Sep 17 00:00:00 2001 From: Rohit Jakhar Date: Sun, 26 Nov 2023 10:43:51 +0530 Subject: [PATCH 05/14] Update library/src/main/res/values/strings.xml Co-authored-by: Nicola Corti --- library/src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/main/res/values/strings.xml b/library/src/main/res/values/strings.xml index e88f7f65e..20862be1e 100644 --- a/library/src/main/res/values/strings.xml +++ b/library/src/main/res/values/strings.xml @@ -47,7 +47,7 @@ Transaction details All transactions Do you want to clear complete network calls history? - Do you want to clear selected network calls history? + Do you want to clear the selected network transactions? Do you want to export all network transactions as a text file? Do you want to export selected network transactions as a text file? Do you want to export selected network transactions as a .har file? From d453d6dadf18a29f562e4177ba81a4e71c1a7c2e Mon Sep 17 00:00:00 2001 From: Rohit Jakhar Date: Sun, 26 Nov 2023 10:44:05 +0530 Subject: [PATCH 06/14] Update library/src/main/res/values/strings.xml Co-authored-by: Nicola Corti --- library/src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/main/res/values/strings.xml b/library/src/main/res/values/strings.xml index 20862be1e..2a561b06e 100644 --- a/library/src/main/res/values/strings.xml +++ b/library/src/main/res/values/strings.xml @@ -46,7 +46,7 @@ Share transactions Transaction details All transactions - Do you want to clear complete network calls history? + Do you want to clear the complete network calls history? Do you want to clear the selected network transactions? Do you want to export all network transactions as a text file? Do you want to export selected network transactions as a text file? From 7dad7ff0687889ef6f0d8010b4f3d3297635015f Mon Sep 17 00:00:00 2001 From: Rohit Jakhar Date: Wed, 29 Nov 2023 16:11:30 +0530 Subject: [PATCH 07/14] Notify adapter after deleting item from list. --- .../chucker/internal/ui/MainActivity.kt | 14 ++++++++++++-- .../internal/ui/transaction/TransactionAdapter.kt | 10 +++++++++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt index 13ba9fc96..cf9f316bd 100644 --- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt +++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt @@ -46,7 +46,7 @@ internal class MainActivity : private lateinit var mainBinding: ChuckerActivityMainBinding private lateinit var transactionsAdapter: TransactionAdapter - private val selectedTransactions = mutableListOf() + private var selectedTransactions = mutableListOf() private val applicationName: CharSequence get() = applicationInfo.loadLabel(packageManager) @@ -168,7 +168,12 @@ internal class MainActivity : showDialog( getClearDialogData(), onPositiveClick = { - if (selectedTransactions.isNotEmpty()) viewModel.clearSelectedTransactions(selectedTransactions) else viewModel.clearTransactions() + if (selectedTransactions.isNotEmpty()) { + viewModel.clearSelectedTransactions(selectedTransactions) + resetSelection() + } else { + viewModel.clearTransactions() + } }, onNegativeClick = null ) @@ -220,6 +225,11 @@ internal class MainActivity : return true } + private fun resetSelection() { + transactionsAdapter.clearSelections() + selectedTransactions = mutableListOf() + } + private fun exportTransactions( fileName: String, block: suspend (List) -> Sharable diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/transaction/TransactionAdapter.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/transaction/TransactionAdapter.kt index 10b3242e3..abe88adae 100644 --- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/transaction/TransactionAdapter.kt +++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/transaction/TransactionAdapter.kt @@ -28,7 +28,7 @@ internal class TransactionAdapter internal constructor( TransactionDiffCallback ) { - private val selectedPos = mutableListOf() + private val selectedPos = mutableListOf() private val colorDefault: Int = ContextCompat.getColor(context, R.color.chucker_status_default) private val colorRequested: Int = ContextCompat.getColor( context, @@ -41,6 +41,14 @@ internal class TransactionAdapter internal constructor( val outValue = TypedValue() private val defaultColor = context.theme.resolveAttribute(android.R.attr.selectableItemBackground, outValue, true) + fun clearSelections() { + val pos = selectedPos + selectedPos.clear() + pos.forEach { + notifyItemRemoved(it) + } + } + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TransactionViewHolder { val viewBinding = ChuckerListItemTransactionBinding.inflate( LayoutInflater.from(parent.context), From 882d6234a407fd30336508f5694ac45a981dbb08 Mon Sep 17 00:00:00 2001 From: Rohit Jakhar Date: Wed, 29 Nov 2023 17:22:46 +0530 Subject: [PATCH 08/14] move selected item code inside viewmodel. --- .../chucker/internal/ui/MainActivity.kt | 33 ++++++----------- .../chucker/internal/ui/MainViewModel.kt | 37 +++++++++++++++---- 2 files changed, 40 insertions(+), 30 deletions(-) diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt index cf9f316bd..1ffc9dbc0 100644 --- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt +++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt @@ -46,7 +46,6 @@ internal class MainActivity : private lateinit var mainBinding: ChuckerActivityMainBinding private lateinit var transactionsAdapter: TransactionAdapter - private var selectedTransactions = mutableListOf() private val applicationName: CharSequence get() = applicationInfo.loadLabel(packageManager) @@ -71,19 +70,15 @@ internal class MainActivity : TransactionAdapter( context = this, longPress = { transactionId -> - selectedTransactions.add(transactionId) + viewModel.selectItem(transactionId) }, onTransactionClick = { transactionId -> - if (selectedTransactions.isNotEmpty()) { - if (transactionId in selectedTransactions) { - selectedTransactions.remove(transactionId) + viewModel.isItemSelected.observe(this) { + if (it) { + viewModel.selectItem(transactionId) } else { - selectedTransactions.add( - transactionId - ) + TransactionActivity.start(this, transactionId) } - } else { - TransactionActivity.start(this, transactionId) } } ) @@ -168,12 +163,8 @@ internal class MainActivity : showDialog( getClearDialogData(), onPositiveClick = { - if (selectedTransactions.isNotEmpty()) { - viewModel.clearSelectedTransactions(selectedTransactions) - resetSelection() - } else { - viewModel.clearTransactions() - } + viewModel.clearTransactions() + resetSelection() }, onNegativeClick = null ) @@ -182,7 +173,7 @@ internal class MainActivity : R.id.share_text -> { showDialog( - getExportDialogData(if (selectedTransactions.isNotEmpty()) R.string.chucker_export_text_selected_http_confirmation else R.string.chucker_export_text_http_confirmation), + getExportDialogData(if (viewModel.isItemSelected.value == true) R.string.chucker_export_text_selected_http_confirmation else R.string.chucker_export_text_http_confirmation), onPositiveClick = { exportTransactions(EXPORT_TXT_FILE_NAME) { transactions -> TransactionListDetailsSharable(transactions, encodeUrls = false) @@ -195,7 +186,7 @@ internal class MainActivity : R.id.share_har -> { showDialog( - getExportDialogData(if (selectedTransactions.isNotEmpty()) R.string.chucker_export_har_selected_http_confirmation else R.string.chucker_export_har_http_confirmation), + getExportDialogData(if (viewModel.isItemSelected.value == true) R.string.chucker_export_har_selected_http_confirmation else R.string.chucker_export_har_http_confirmation), onPositiveClick = { exportTransactions(EXPORT_HAR_FILE_NAME) { transactions -> TransactionDetailsHarSharable( @@ -227,7 +218,6 @@ internal class MainActivity : private fun resetSelection() { transactionsAdapter.clearSelections() - selectedTransactions = mutableListOf() } private fun exportTransactions( @@ -236,8 +226,7 @@ internal class MainActivity : ) { val applicationContext = this.applicationContext lifecycleScope.launch { - val transactions = - if (selectedTransactions.isNotEmpty()) viewModel.getSelectedTransactions(selectedTransactions) else viewModel.getAllTransactions() + val transactions = viewModel.getAllTransactions() if (transactions.isEmpty()) { showToast(applicationContext.getString(R.string.chucker_export_empty_text)) return@launch @@ -263,7 +252,7 @@ internal class MainActivity : private fun getClearDialogData(): DialogData = DialogData( title = getString(R.string.chucker_clear), - message = getString(if (selectedTransactions.isNotEmpty()) R.string.chucker_clear_selected_http_confirmation else R.string.chucker_clear_http_confirmation), + message = getString(if (viewModel.isItemSelected.value == true) R.string.chucker_clear_selected_http_confirmation else R.string.chucker_clear_http_confirmation), positiveButtonText = getString(R.string.chucker_clear), negativeButtonText = getString(R.string.chucker_cancel) ) diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainViewModel.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainViewModel.kt index 5798f2b83..4408de4bf 100644 --- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainViewModel.kt +++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainViewModel.kt @@ -4,6 +4,7 @@ import android.text.TextUtils import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel +import androidx.lifecycle.liveData import androidx.lifecycle.switchMap import androidx.lifecycle.viewModelScope import com.chuckerteam.chucker.internal.data.entity.HttpTransaction @@ -15,6 +16,13 @@ import kotlinx.coroutines.launch internal class MainViewModel : ViewModel() { private val currentFilter = MutableLiveData("") + private val selectedItemId: MutableLiveData> = MutableLiveData>(mutableListOf()) + + val isItemSelected = selectedItemId.switchMap { + liveData { + emit(selectedItemId.value.isNullOrEmpty().not()) + } + } val transactions: LiveData> = currentFilter.switchMap { searchQuery -> with(RepositoryProvider.transaction()) { @@ -32,9 +40,23 @@ internal class MainViewModel : ViewModel() { } } - suspend fun getAllTransactions(): List = RepositoryProvider.transaction().getAllTransactions() + fun selectItem(itemId: Long) { + viewModelScope.launch { + if (selectedItemId.value?.contains(itemId) == true) { + selectedItemId.value?.remove(itemId) + } else { + selectedItemId.value?.add(itemId) + } + } + } - suspend fun getSelectedTransactions(selectedTransaction: List): List = RepositoryProvider.transaction().getSelectedTransactions(selectedTransaction) + suspend fun getAllTransactions(): List { + return if (isItemSelected.value == true) { + RepositoryProvider.transaction().getSelectedTransactions(selectedItemId.value!!) + } else { + RepositoryProvider.transaction().getAllTransactions() + } + } fun updateItemsFilter(searchQuery: String) { currentFilter.value = searchQuery @@ -42,14 +64,13 @@ internal class MainViewModel : ViewModel() { fun clearTransactions() { viewModelScope.launch { - RepositoryProvider.transaction().deleteAllTransactions() + if (isItemSelected.value == true) { + RepositoryProvider.transaction().deleteSelectedTransactions(selectedItemId.value!!) + } else { + RepositoryProvider.transaction().deleteAllTransactions() + } } NotificationHelper.clearBuffer() } - fun clearSelectedTransactions(selectedTransaction: List) { - viewModelScope.launch { - RepositoryProvider.transaction().deleteSelectedTransactions(selectedTransaction) - } - } } From 9e4107316046bb7632275f770af009df14768545 Mon Sep 17 00:00:00 2001 From: Rohit Jakhar Date: Wed, 29 Nov 2023 23:07:17 +0530 Subject: [PATCH 09/14] fix reselecting. click after clear selection issue. --- .../chucker/internal/ui/MainActivity.kt | 14 ++++++++------ .../chucker/internal/ui/MainViewModel.kt | 13 ++++++++----- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt index 1ffc9dbc0..fe2660587 100644 --- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt +++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt @@ -46,6 +46,7 @@ internal class MainActivity : private lateinit var mainBinding: ChuckerActivityMainBinding private lateinit var transactionsAdapter: TransactionAdapter + private var isMultipleSelected = false private val applicationName: CharSequence get() = applicationInfo.loadLabel(packageManager) @@ -73,12 +74,10 @@ internal class MainActivity : viewModel.selectItem(transactionId) }, onTransactionClick = { transactionId -> - viewModel.isItemSelected.observe(this) { - if (it) { - viewModel.selectItem(transactionId) - } else { - TransactionActivity.start(this, transactionId) - } + if (isMultipleSelected) { + viewModel.selectItem(transactionId) + } else { + TransactionActivity.start(this, transactionId) } } ) @@ -111,6 +110,9 @@ internal class MainActivity : if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { handleNotificationsPermission() } + viewModel.isItemSelected.observe(this) { + isMultipleSelected = it + } } @RequiresApi(Build.VERSION_CODES.TIRAMISU) diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainViewModel.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainViewModel.kt index 4408de4bf..af1643173 100644 --- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainViewModel.kt +++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainViewModel.kt @@ -1,9 +1,11 @@ package com.chuckerteam.chucker.internal.ui import android.text.TextUtils +import android.util.Log import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel +import androidx.lifecycle.distinctUntilChanged import androidx.lifecycle.liveData import androidx.lifecycle.switchMap import androidx.lifecycle.viewModelScope @@ -11,6 +13,7 @@ import com.chuckerteam.chucker.internal.data.entity.HttpTransaction import com.chuckerteam.chucker.internal.data.entity.HttpTransactionTuple import com.chuckerteam.chucker.internal.data.repository.RepositoryProvider import com.chuckerteam.chucker.internal.support.NotificationHelper +import com.chuckerteam.chucker.internal.support.distinctUntilChanged import kotlinx.coroutines.launch internal class MainViewModel : ViewModel() { @@ -18,11 +21,8 @@ internal class MainViewModel : ViewModel() { private val currentFilter = MutableLiveData("") private val selectedItemId: MutableLiveData> = MutableLiveData>(mutableListOf()) - val isItemSelected = selectedItemId.switchMap { - liveData { - emit(selectedItemId.value.isNullOrEmpty().not()) - } - } + private var _isItemSelected = MutableLiveData(false) + val isItemSelected = _isItemSelected.distinctUntilChanged() val transactions: LiveData> = currentFilter.switchMap { searchQuery -> with(RepositoryProvider.transaction()) { @@ -44,8 +44,10 @@ internal class MainViewModel : ViewModel() { viewModelScope.launch { if (selectedItemId.value?.contains(itemId) == true) { selectedItemId.value?.remove(itemId) + _isItemSelected.value = selectedItemId.value.isNullOrEmpty().not() == true } else { selectedItemId.value?.add(itemId) + _isItemSelected.value = true } } } @@ -65,6 +67,7 @@ internal class MainViewModel : ViewModel() { fun clearTransactions() { viewModelScope.launch { if (isItemSelected.value == true) { + _isItemSelected.value = false RepositoryProvider.transaction().deleteSelectedTransactions(selectedItemId.value!!) } else { RepositoryProvider.transaction().deleteAllTransactions() From 4a8ecddbb2cc108f0bded53d0178912c66d3378b Mon Sep 17 00:00:00 2001 From: Rohit Jakhar Date: Wed, 10 Jan 2024 19:04:24 +0530 Subject: [PATCH 10/14] Fix deket --- .../repository/HttpTransactionRepository.kt | 1 + .../internal/data/room/HttpTransactionDao.kt | 1 + .../chucker/internal/ui/MainActivity.kt | 30 +++++++++++++++---- .../chucker/internal/ui/MainViewModel.kt | 7 ++--- .../ui/transaction/TransactionAdapter.kt | 17 +++++++---- 5 files changed, 41 insertions(+), 15 deletions(-) diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/repository/HttpTransactionRepository.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/repository/HttpTransactionRepository.kt index 31d5195c7..8bc85f907 100644 --- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/repository/HttpTransactionRepository.kt +++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/repository/HttpTransactionRepository.kt @@ -9,6 +9,7 @@ import com.chuckerteam.chucker.internal.data.entity.HttpTransactionTuple * with [HttpTransaction] and [HttpTransactionTuple]. Please use [HttpTransactionDatabaseRepository] that * uses Room and SqLite to run those operations. */ +@Suppress("TooManyFunctions") internal interface HttpTransactionRepository { suspend fun insertTransaction(transaction: HttpTransaction) diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/room/HttpTransactionDao.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/room/HttpTransactionDao.kt index bc36de6e4..c1e824674 100644 --- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/room/HttpTransactionDao.kt +++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/room/HttpTransactionDao.kt @@ -9,6 +9,7 @@ import androidx.room.Update import com.chuckerteam.chucker.internal.data.entity.HttpTransaction import com.chuckerteam.chucker.internal.data.entity.HttpTransactionTuple +@Suppress("TooManyFunctions") @Dao internal interface HttpTransactionDao { @Query( diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt index c33473570..79973b632 100644 --- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt +++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt @@ -79,7 +79,7 @@ internal class MainActivity : } else { TransactionActivity.start(this, transactionId) } - } + }, ) with(mainBinding) { @@ -172,7 +172,13 @@ internal class MainActivity : } R.id.share_text -> { showDialog( - getExportDialogData(if (viewModel.isItemSelected.value == true) R.string.chucker_export_text_selected_http_confirmation else R.string.chucker_export_text_http_confirmation), + getExportDialogData( + if (viewModel.isItemSelected.value == true) { + R.string.chucker_export_text_selected_http_confirmation + } else { + R.string.chucker_export_text_http_confirmation + } + ), onPositiveClick = { exportTransactions(EXPORT_TXT_FILE_NAME) { transactions -> TransactionListDetailsSharable(transactions, encodeUrls = false) @@ -184,7 +190,13 @@ internal class MainActivity : } R.id.share_har -> { showDialog( - getExportDialogData(if (viewModel.isItemSelected.value == true) R.string.chucker_export_har_selected_http_confirmation else R.string.chucker_export_har_http_confirmation), + getExportDialogData( + if (viewModel.isItemSelected.value == true) { + R.string.chucker_export_har_selected_http_confirmation + } else { + R.string.chucker_export_har_http_confirmation + } + ), onPositiveClick = { exportTransactions(EXPORT_HAR_FILE_NAME) { transactions -> TransactionDetailsHarSharable( @@ -243,14 +255,22 @@ internal class MainActivity : if (shareIntent != null) { startActivity(shareIntent) } else { - showToast(applicationContext.getString(R.string.chucker_export_no_file)) + showToast( + applicationContext.getString( + R.string.chucker_export_no_file + ) + ) } } } private fun getClearDialogData(): DialogData = DialogData( title = getString(R.string.chucker_clear), - message = getString(if (viewModel.isItemSelected.value == true) R.string.chucker_clear_selected_http_confirmation else R.string.chucker_clear_http_confirmation), + message = getString( + if (viewModel.isItemSelected.value == true) + R.string.chucker_clear_selected_http_confirmation + else + R.string.chucker_clear_http_confirmation), positiveButtonText = getString(R.string.chucker_clear), negativeButtonText = getString(R.string.chucker_cancel) ) diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainViewModel.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainViewModel.kt index 234900893..f961c0b53 100644 --- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainViewModel.kt +++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainViewModel.kt @@ -1,24 +1,22 @@ package com.chuckerteam.chucker.internal.ui import android.text.TextUtils -import android.util.Log import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.distinctUntilChanged -import androidx.lifecycle.liveData import androidx.lifecycle.switchMap import androidx.lifecycle.viewModelScope import com.chuckerteam.chucker.internal.data.entity.HttpTransaction import com.chuckerteam.chucker.internal.data.entity.HttpTransactionTuple import com.chuckerteam.chucker.internal.data.repository.RepositoryProvider import com.chuckerteam.chucker.internal.support.NotificationHelper -import com.chuckerteam.chucker.internal.support.distinctUntilChanged import kotlinx.coroutines.launch internal class MainViewModel : ViewModel() { private val currentFilter = MutableLiveData("") - private val selectedItemId: MutableLiveData> = MutableLiveData>(mutableListOf()) + private val selectedItemId: MutableLiveData> = + MutableLiveData>(mutableListOf()) private var _isItemSelected = MutableLiveData(false) val isItemSelected = _isItemSelected.distinctUntilChanged() @@ -75,5 +73,4 @@ internal class MainViewModel : ViewModel() { } NotificationHelper.clearBuffer() } - } diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/transaction/TransactionAdapter.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/transaction/TransactionAdapter.kt index 3dc6d05c2..65bd49aae 100644 --- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/transaction/TransactionAdapter.kt +++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/transaction/TransactionAdapter.kt @@ -23,11 +23,12 @@ import javax.net.ssl.HttpsURLConnection internal class TransactionAdapter internal constructor( context: Context, private val onTransactionClick: (Long) -> Unit, - private val longPress: (Long) -> Unit -) : ListAdapter( + private val longPress: (Long) -> Unit, +) : ListAdapter< + HttpTransactionTuple, + TransactionAdapter.TransactionViewHolder>( TransactionDiffCallback -) { - + ) { private val selectedPos = mutableListOf() private val colorDefault: Int = ContextCompat.getColor(context, R.color.chucker_status_default) private val colorRequested: Int = @@ -40,7 +41,13 @@ internal class TransactionAdapter internal constructor( private val color400: Int = ContextCompat.getColor(context, R.color.chucker_status_400) private val color300: Int = ContextCompat.getColor(context, R.color.chucker_status_300) val outValue = TypedValue() - private val defaultColor = context.theme.resolveAttribute(android.R.attr.selectableItemBackground, outValue, true) + @Suppress("UnusedPrivateProperty") + private val defaultColor = + context.theme.resolveAttribute( + android.R.attr.selectableItemBackground, + outValue, + true, + ) fun clearSelections() { val pos = selectedPos From 5ce5445799d7108fe3a850ae496a2c97a6d1d438 Mon Sep 17 00:00:00 2001 From: Rohit Jakhar Date: Thu, 1 Feb 2024 15:05:48 +0530 Subject: [PATCH 11/14] KotlinLint Format Review Changes. --- .../chucker/internal/ui/MainActivity.kt | 32 +++++++++++-------- .../ui/transaction/TransactionAdapter.kt | 21 ++++++------ library/src/main/res/values-night/colors.xml | 2 ++ library/src/main/res/values/colors.xml | 2 ++ 4 files changed, 34 insertions(+), 23 deletions(-) diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt index 79973b632..8aa96a428 100644 --- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt +++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt @@ -177,7 +177,7 @@ internal class MainActivity : R.string.chucker_export_text_selected_http_confirmation } else { R.string.chucker_export_text_http_confirmation - } + }, ), onPositiveClick = { exportTransactions(EXPORT_TXT_FILE_NAME) { transactions -> @@ -195,7 +195,7 @@ internal class MainActivity : R.string.chucker_export_har_selected_http_confirmation } else { R.string.chucker_export_har_http_confirmation - } + }, ), onPositiveClick = { exportTransactions(EXPORT_HAR_FILE_NAME) { transactions -> @@ -257,23 +257,27 @@ internal class MainActivity : } else { showToast( applicationContext.getString( - R.string.chucker_export_no_file - ) + R.string.chucker_export_no_file, + ), ) } } } - private fun getClearDialogData(): DialogData = DialogData( - title = getString(R.string.chucker_clear), - message = getString( - if (viewModel.isItemSelected.value == true) - R.string.chucker_clear_selected_http_confirmation - else - R.string.chucker_clear_http_confirmation), - positiveButtonText = getString(R.string.chucker_clear), - negativeButtonText = getString(R.string.chucker_cancel) - ) + private fun getClearDialogData(): DialogData = + DialogData( + title = getString(R.string.chucker_clear), + message = + getString( + if (viewModel.isItemSelected.value == true) { + R.string.chucker_clear_selected_http_confirmation + } else { + R.string.chucker_clear_http_confirmation + }, + ), + positiveButtonText = getString(R.string.chucker_clear), + negativeButtonText = getString(R.string.chucker_cancel), + ) private fun getExportDialogData( @StringRes dialogMessage: Int, diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/transaction/TransactionAdapter.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/transaction/TransactionAdapter.kt index 65bd49aae..6c1572c93 100644 --- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/transaction/TransactionAdapter.kt +++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/transaction/TransactionAdapter.kt @@ -25,9 +25,10 @@ internal class TransactionAdapter internal constructor( private val onTransactionClick: (Long) -> Unit, private val longPress: (Long) -> Unit, ) : ListAdapter< - HttpTransactionTuple, - TransactionAdapter.TransactionViewHolder>( - TransactionDiffCallback + HttpTransactionTuple, + TransactionAdapter.TransactionViewHolder, + >( + TransactionDiffCallback, ) { private val selectedPos = mutableListOf() private val colorDefault: Int = ContextCompat.getColor(context, R.color.chucker_status_default) @@ -40,14 +41,16 @@ internal class TransactionAdapter internal constructor( private val color500: Int = ContextCompat.getColor(context, R.color.chucker_status_500) private val color400: Int = ContextCompat.getColor(context, R.color.chucker_status_400) private val color300: Int = ContextCompat.getColor(context, R.color.chucker_status_300) + private val chuckerStatusHighlighted: Int = ContextCompat.getColor(context, R.color.chucker_status_highlighted) val outValue = TypedValue() + @Suppress("UnusedPrivateProperty") private val defaultColor = context.theme.resolveAttribute( - android.R.attr.selectableItemBackground, - outValue, - true, - ) + android.R.attr.selectableItemBackground, + outValue, + true, + ) fun clearSelections() { val pos = selectedPos @@ -105,7 +108,7 @@ internal class TransactionAdapter internal constructor( } notifyItemChanged(adapterPosition) true - } ?: kotlin.run { false } + } ?: false } } @@ -113,7 +116,7 @@ internal class TransactionAdapter internal constructor( fun bind(transaction: HttpTransactionTuple) { transactionId = transaction.id if (selectedPos.find { it == adapterPosition } != null) { - itemView.setBackgroundColor(color400) + itemView.setBackgroundColor(chuckerStatusHighlighted) } else { itemView.setBackgroundResource(outValue.resourceId) } diff --git a/library/src/main/res/values-night/colors.xml b/library/src/main/res/values-night/colors.xml index 19ce959f8..d07568932 100644 --- a/library/src/main/res/values-night/colors.xml +++ b/library/src/main/res/values-night/colors.xml @@ -22,6 +22,8 @@ #ffe082 #ef5350 + #FF9800 + #75bec4 #9e7162 #669f50 diff --git a/library/src/main/res/values/colors.xml b/library/src/main/res/values/colors.xml index 0a4bfa924..be29604cc 100644 --- a/library/src/main/res/values/colors.xml +++ b/library/src/main/res/values/colors.xml @@ -22,6 +22,8 @@ #ffffff00 #ffff0000 + #FF9800 + #F8FAFC #D2DADF #182531 From 05427fec2590c01f9016467bcad0184fe836fdc7 Mon Sep 17 00:00:00 2001 From: Rohit Jakhar Date: Thu, 1 Feb 2024 17:10:36 +0530 Subject: [PATCH 12/14] Fix: Persistent user selection --- .../chuckerteam/chucker/internal/ui/MainActivity.kt | 10 ++++++++++ .../internal/ui/transaction/TransactionAdapter.kt | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt index 8aa96a428..9b95016c1 100644 --- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt +++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt @@ -218,6 +218,16 @@ internal class MainActivity : } } + override fun onSaveInstanceState(outState: Bundle) { + outState.putIntArray("selectedItems", (transactionsAdapter.getSelectedItem().toIntArray())); + super.onSaveInstanceState(outState) + } + override fun onRestoreInstanceState(savedInstanceState: Bundle) { + super.onRestoreInstanceState(savedInstanceState) + val itemList = savedInstanceState.getIntArray("selectedItems") + transactionsAdapter.setSelectedItem(itemList?.toList() ?: emptyList()) + } + override fun onQueryTextSubmit(query: String): Boolean = true override fun onQueryTextChange(newText: String): Boolean { diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/transaction/TransactionAdapter.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/transaction/TransactionAdapter.kt index 6c1572c93..85287797f 100644 --- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/transaction/TransactionAdapter.kt +++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/transaction/TransactionAdapter.kt @@ -52,6 +52,14 @@ internal class TransactionAdapter internal constructor( true, ) + fun getSelectedItem(): List { + return selectedPos + } + + fun setSelectedItem(selectedItem: List) { + selectedPos.addAll(selectedItem) + } + fun clearSelections() { val pos = selectedPos selectedPos.clear() From c1074098e4ebfff20dcac43e86359d41c5a43806 Mon Sep 17 00:00:00 2001 From: Rohit Jakhar Date: Thu, 6 Jun 2024 19:59:56 +0530 Subject: [PATCH 13/14] Update code. --- .../chucker/internal/ui/MainActivity.kt | 83 ++++++++++--------- 1 file changed, 46 insertions(+), 37 deletions(-) diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt index a0fd77afa..46d0e8dfd 100644 --- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt +++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt @@ -193,46 +193,12 @@ internal class MainActivity : } R.id.share_text -> { - showDialog( - getExportDialogData( - if (viewModel.isItemSelected.value == true) { - R.string.chucker_export_text_selected_http_confirmation - } else { - R.string.chucker_export_text_http_confirmation - }, - ), - onPositiveClick = { - exportTransactions(EXPORT_TXT_FILE_NAME) { transactions -> - TransactionListDetailsSharable(transactions, encodeUrls = false) - } - }, - onNegativeClick = null, - ) + showShareTextDialog() true } R.id.share_har -> { - showDialog( - getExportDialogData( - if (viewModel.isItemSelected.value == true) { - R.string.chucker_export_har_selected_http_confirmation - } else { - R.string.chucker_export_har_http_confirmation - }, - ), - onPositiveClick = { - exportTransactions(EXPORT_HAR_FILE_NAME) { transactions -> - TransactionDetailsHarSharable( - HarUtils.harStringFromTransactions( - transactions, - getString(R.string.chucker_name), - getString(R.string.chucker_version), - ), - ) - } - }, - onNegativeClick = null, - ) + showShareHarDialog() true } @@ -252,10 +218,53 @@ internal class MainActivity : } } + private fun showShareHarDialog() { + showDialog( + getExportDialogData( + if (viewModel.isItemSelected.value == true) { + R.string.chucker_export_har_selected_http_confirmation + } else { + R.string.chucker_export_har_http_confirmation + }, + ), + onPositiveClick = { + exportTransactions(EXPORT_HAR_FILE_NAME) { transactions -> + TransactionDetailsHarSharable( + HarUtils.harStringFromTransactions( + transactions, + getString(R.string.chucker_name), + getString(R.string.chucker_version), + ), + ) + } + }, + onNegativeClick = null, + ) + } + + private fun showShareTextDialog() { + showDialog( + getExportDialogData( + if (viewModel.isItemSelected.value == true) { + R.string.chucker_export_text_selected_http_confirmation + } else { + R.string.chucker_export_text_http_confirmation + }, + ), + onPositiveClick = { + exportTransactions(EXPORT_TXT_FILE_NAME) { transactions -> + TransactionListDetailsSharable(transactions, encodeUrls = false) + } + }, + onNegativeClick = null, + ) + } + override fun onSaveInstanceState(outState: Bundle) { - outState.putIntArray("selectedItems", (transactionsAdapter.getSelectedItem().toIntArray())); + outState.putIntArray("selectedItems", (transactionsAdapter.getSelectedItem().toIntArray())) super.onSaveInstanceState(outState) } + override fun onRestoreInstanceState(savedInstanceState: Bundle) { super.onRestoreInstanceState(savedInstanceState) val itemList = savedInstanceState.getIntArray("selectedItems") From 137d8c764cb4eee8f60fae6a1315b59e3cde8b97 Mon Sep 17 00:00:00 2001 From: Rohit Jakhar Date: Tue, 11 Jun 2024 20:34:26 +0530 Subject: [PATCH 14/14] Suppress MainActivity with TooManyFunction. --- .../kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt index 46d0e8dfd..e32188afa 100644 --- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt +++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/MainActivity.kt @@ -46,6 +46,7 @@ import okio.Source import okio.buffer import okio.source +@Suppress("TooManyFunctions") internal class MainActivity : BaseChuckerActivity(), SearchView.OnQueryTextListener {