Skip to content

Commit 3fd8461

Browse files
committed
Transactions pages - skeleton ready - optimization and styling required
1 parent e385591 commit 3fd8461

File tree

6 files changed

+239
-294
lines changed

6 files changed

+239
-294
lines changed

app/src/main/java/com/example/spendwise/MainActivity.kt

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
package com.example.spendwise
22

3+
import android.Manifest
4+
import android.content.pm.PackageManager
35
import android.os.Bundle
46
import android.widget.Toast
57
import androidx.activity.enableEdgeToEdge
68
import androidx.appcompat.app.AppCompatActivity
9+
import androidx.core.app.ActivityCompat
10+
import androidx.core.content.ContextCompat
711
import androidx.fragment.app.Fragment
812
import com.example.spendwise.databinding.ActivityMainBinding
913

1014

1115
class MainActivity : AppCompatActivity() {
1216

13-
// private val SMS_PERMISSION_CODE = 101
17+
private val SMS_PERMISSION_CODE = 101
1418
private lateinit var binding : ActivityMainBinding
1519

1620
override fun onCreate(savedInstanceState: Bundle?) {
@@ -19,6 +23,15 @@ class MainActivity : AppCompatActivity() {
1923
binding = ActivityMainBinding.inflate(layoutInflater)
2024
// setContentView(R.layout.activity_main)
2125
setContentView(binding.root)
26+
// Check SMS permission when the activity starts
27+
if (checkSmsPermission()) {
28+
// Permission is granted
29+
Toast.makeText(this, "Permission Granted", Toast.LENGTH_SHORT).show()
30+
// Proceed with functionality that requires SMS permission (if needed)
31+
} else {
32+
// Permission is not granted, request it
33+
requestSmsPermission()
34+
}
2235
replaceFragment(Home())
2336

2437
binding.bottomNavigationView2.setOnItemSelectedListener {
@@ -77,22 +90,24 @@ class MainActivity : AppCompatActivity() {
7790
fragmentTransaction.commit()
7891
}
7992

80-
//
81-
//private fun checkSmsPermission(): Boolean {
82-
//
83-
// return ContextCompat.checkSelfPermission(
84-
// this,
85-
// Manifest.permission.READ_SMS
86-
// ) == PackageManager.PERMISSION_GRANTED
87-
//}
88-
//
89-
//private fun requestSmsPermission() {
90-
// ActivityCompat.requestPermissions(
91-
// this,
92-
// arrayOf(Manifest.permission.READ_SMS),
93-
// SMS_PERMISSION_CODE
94-
// )
95-
//}
93+
94+
// Check if SMS permission is granted
95+
private fun checkSmsPermission(): Boolean {
96+
return ContextCompat.checkSelfPermission(
97+
this,
98+
Manifest.permission.READ_SMS
99+
) == PackageManager.PERMISSION_GRANTED
100+
}
101+
102+
// Request SMS permission
103+
private fun requestSmsPermission() {
104+
ActivityCompat.requestPermissions(
105+
this,
106+
arrayOf(Manifest.permission.READ_SMS),
107+
SMS_PERMISSION_CODE
108+
)
109+
}
110+
96111
//
97112
//override fun onRequestPermissionsResult(
98113
// requestCode: Int,

app/src/main/java/com/example/spendwise/Messages.kt

Lines changed: 81 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -15,32 +15,14 @@ import android.widget.Toast
1515
import androidx.core.app.ActivityCompat
1616
import androidx.core.content.ContextCompat
1717
import androidx.fragment.app.Fragment
18+
import com.example.spendwise.adapter.TransactionAdapter
19+
import com.example.spendwise.model.TransactionData
1820

19-
// TODO: Rename parameter arguments, choose names that match
20-
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
21-
//private const val ARG_PARAM1 = "param1"
22-
//private const val ARG_PARAM2 = "param2"
2321

24-
/**
25-
* A simple [Fragment] subclass.
26-
* Use the [Messages.newInstance] factory method to
27-
* create an instance of this fragment.
28-
*/
2922
class Messages : Fragment() {
3023

3124
private val SMS_PERMISSION_CODE = 101
3225

33-
// TODO: Rename and change types of parameters
34-
// private var param1: String? = null
35-
// private var param2: String? = null
36-
37-
// override fun onCreate(savedInstanceState: Bundle?) {
38-
// super.onCreate(savedInstanceState)
39-
// arguments?.let {
40-
// param1 = it.getString(ARG_PARAM1)
41-
// param2 = it.getString(ARG_PARAM2)
42-
// }
43-
// }
4426

4527
override fun onCreateView(
4628
inflater: LayoutInflater, container: ViewGroup?,
@@ -135,11 +117,76 @@ class Messages : Fragment() {
135117
val adapter = SmsAdapter(requireContext(), R.layout.list_item_sms, smsList)
136118
listView.adapter = adapter
137119
}
120+
private fun displaySms2(listView: ListView, showBankMessages: Boolean) {
121+
val transactions = mutableListOf<TransactionData>()
122+
123+
val cursor: Cursor? = requireContext().contentResolver.query(
124+
Telephony.Sms.CONTENT_URI,
125+
null,
126+
Telephony.Sms.TYPE + " = ?",
127+
arrayOf(Telephony.Sms.MESSAGE_TYPE_INBOX.toString()),
128+
Telephony.Sms.DATE + " DESC"
129+
)
130+
131+
cursor?.let {
132+
val addressColumn = it.getColumnIndex(Telephony.Sms.ADDRESS)
133+
val bodyColumn = it.getColumnIndex(Telephony.Sms.BODY)
134+
val dateColumn = it.getColumnIndex(Telephony.Sms.DATE)
135+
136+
while (it.moveToNext()) {
137+
val sender = it.getString(addressColumn)
138+
val message = it.getString(bodyColumn)
139+
val dateMillis = it.getLong(dateColumn)
140+
val date = DateFormat.format("dd-MM-yyyy", dateMillis).toString()
141+
val time = DateFormat.format("hh:mm a", dateMillis).toString()
142+
143+
if (!showBankMessages || isBankMessage(sender, message)) {
144+
val transaction = parseTransaction(sender, message, date, time)
145+
if (transaction != null) {
146+
transactions.add(transaction)
147+
}
148+
}
149+
}
150+
it.close()
151+
}
152+
153+
// val adapter = TransactionAdapter(requireContext(), R.layout.list_item_sms, transactions)
154+
// val adapter = TransactionAdapter(requireContext(), transactions)
155+
val adapter = TransactionAdapter(requireContext(), transactions)
156+
listView.adapter = adapter
157+
}
158+
159+
// private
160+
fun parseTransaction(sender: String, message: String, date: String, time: String): TransactionData? {
161+
// Attempt to extract amount and determine if it's a credit or debit
162+
val amountRegex = Regex("\\b(?:Rs\\.?|INR)?\\s?(\\d+(?:\\.\\d{1,2})?)\\b", RegexOption.IGNORE_CASE)
163+
val creditKeywords = listOf("credited", "credit", "deposit")
164+
val debitKeywords = listOf("debited", "debit", "withdrawal")
165+
166+
val amountMatch = amountRegex.find(message)
167+
val isCredit = creditKeywords.any { message.contains(it, ignoreCase = true) }
168+
val isDebit = debitKeywords.any { message.contains(it, ignoreCase = true) }
169+
170+
return if (amountMatch != null && (isCredit || isDebit)) {
171+
val amount = amountMatch.groupValues[1]
172+
TransactionData(
173+
sender = sender,
174+
messageBody = message,
175+
amount = amount,
176+
date = date,
177+
time = time,
178+
isCredit = isCredit
179+
)
180+
} else {
181+
null
182+
}
183+
}
184+
138185
private fun isBankMessage(sender: String, message: String): Boolean {
139186
// Common patterns for bank sender IDs
140187
val bankPatterns = listOf(
141188
Regex("^[A-Za-z]{2,}-\\d{2,}$"), // Example: "AX-12345"
142-
Regex("^[A-Za-z]{3,}$"), // Example: "ICICI", "SBI"
189+
Regex("^[A-Za-z]{3,}$"), // Example: "ICICI", "SBI"
143190
Regex("^[A-Za-z]{2,}\\d{1,}$"), // Example: "ICICI1", "HDFC123"
144191
Regex("^[A-Za-z]+\\d+$") // Example: "Bank123", "MyBank456"
145192
)
@@ -150,95 +197,31 @@ class Messages : Fragment() {
150197
"CITIBANK", "BOB", "KOTAKBANK", "YESBANK", "IDFCFIRST"
151198
)
152199

153-
// Keywords indicating financial transactions
154-
val transactionKeywords = listOf("credited", "debited", "withdrawn", "deposited", "transferred")
155-
156-
// Regex pattern to detect numeric amounts (e.g., "Rs. 5000", "$300", "INR 2500")
157-
val amountPattern = Regex("\\b(?:Rs\\.?|INR|\\$)?\\s?\\d{1,}(?:,\\d{3})*(?:\\.\\d{1,2})?\\b")
200+
// Keywords commonly found in bank messages
201+
val bankKeywords = listOf(
202+
"transaction", "debit", "credit", "account", "balance",
203+
"payment", "bank", "debited", "credited",
204+
)
158205

159206
// Check if sender contains only numbers (not a bank message)
160-
if (sender.matches(Regex("^\\d+$"))) {
161-
return false
162-
}
207+
// if (sender.matches(Regex("^\\d+$"))) {
208+
// return false
209+
// }
163210

164211
// Check if sender matches any pattern
165212
val matchesPattern = bankPatterns.any { pattern -> sender.matches(pattern) }
166213

167214
// Check if sender is in the known banks list (ignoring case)
168215
val isKnownBank = knownBanks.any { bank -> sender.equals(bank, ignoreCase = true) }
169216

170-
// Check if message contains transaction-related keywords
171-
val containsTransactionKeywords = transactionKeywords.any { keyword ->
217+
// Check if message contains any bank-related keywords
218+
val containsBankKeywords = bankKeywords.any { keyword ->
172219
message.contains(keyword, ignoreCase = true)
173220
}
174221

175-
// Check if message contains a numeric amount
176-
val containsAmount = amountPattern.containsMatchIn(message)
177-
178-
// Return true if sender is valid and message indicates a financial transaction
179-
return (matchesPattern || isKnownBank) && containsTransactionKeywords && containsAmount
222+
// Return true if either sender or message matches bank criteria
223+
return matchesPattern || isKnownBank || containsBankKeywords
180224
}
181225

182-
//
183-
// private fun isBankMessage(sender: String, message: String): Boolean {
184-
// // Common patterns for bank sender IDs
185-
// val bankPatterns = listOf(
186-
// Regex("^[A-Za-z]{2,}-\\d{2,}$"), // Example: "AX-12345"
187-
// Regex("^[A-Za-z]{3,}$"), // Example: "ICICI", "SBI"
188-
// Regex("^[A-Za-z]{2,}\\d{1,}$"), // Example: "ICICI1", "HDFC123"
189-
// Regex("^[A-Za-z]+\\d+$") // Example: "Bank123", "MyBank456"
190-
// )
191-
//
192-
// // Custom sender names (specific to region or known banks)
193-
// val knownBanks = listOf(
194-
// "ICICIBANK", "SBIBANK", "HDFCBANK", "AXISBANK", "PNB",
195-
// "CITIBANK", "BOB", "KOTAKBANK", "YESBANK", "IDFCFIRST"
196-
// )
197-
//
198-
// // Keywords commonly found in bank messages
199-
// val bankKeywords = listOf(
200-
// "transaction", "debit", "credit", "account", "balance",
201-
// "payment", "statement", "otp", "loan", "bank"
202-
// )
203-
//
204-
// // Check if sender contains only numbers (not a bank message)
205-
// if (sender.matches(Regex("^\\d+$"))) {
206-
// return false
207-
// }
208-
//
209-
// // Check if sender matches any pattern
210-
// val matchesPattern = bankPatterns.any { pattern -> sender.matches(pattern) }
211-
//
212-
// // Check if sender is in the known banks list (ignoring case)
213-
// val isKnownBank = knownBanks.any { bank -> sender.equals(bank, ignoreCase = true) }
214-
//
215-
// // Check if message contains any bank-related keywords
216-
// val containsBankKeywords = bankKeywords.any { keyword ->
217-
// message.contains(keyword, ignoreCase = true)
218-
// }
219-
//
220-
// // Return true if either sender or message matches bank criteria
221-
// return matchesPattern || isKnownBank || containsBankKeywords
222-
// }
223-
224-
225-
// companion object {
226-
// /**
227-
// * Use this factory method to create a new instance of
228-
// * this fragment using the provided parameters.
229-
// *
230-
// * @param param1 Parameter 1.
231-
// * @param param2 Parameter 2.
232-
// * @return A new instance of fragment Messages.
233-
// */
234-
// // TODO: Rename and change types and number of parameters
235-
// @JvmStatic
236-
// fun newInstance(param1: String, param2: String) =
237-
// Messages().apply {
238-
// arguments = Bundle().apply {
239-
// putString(ARG_PARAM1, param1)
240-
// putString(ARG_PARAM2, param2)
241-
// }
242-
// }
243-
// }
226+
244227
}

0 commit comments

Comments
 (0)