package com.dmc.callcrm.ui import android.os.Bundle import android.provider.CallLog import android.view.Gravity import android.view.View import android.view.ViewGroup import android.widget.LinearLayout import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import com.dmc.callcrm.R import com.dmc.callcrm.data.CallStats import com.dmc.callcrm.data.Prefs import java.text.SimpleDateFormat import java.util.Locale /** * Shared detail screen for the three Analysis-tab "record holder" cards: * Top Caller, Longest Call, and Highest Total Call Duration. Which one is * shown is decided by the "mode" Intent extra; layout is identical, only * the stat rows underneath the contact card differ. * * Expected Intent extras: * MODE ("top_caller" | "longest_call" | "highest_duration") * FROM, TO (Long, ms) * EXCLUDE_DIGITS (ArrayList) * DESELECTED_TYPES (ArrayList) * FILTER_LABEL, RANGE_LABEL, EXNO_LABEL (String — the chip text already * computed by AnalyticsFragment, so this screen doesn't duplicate that logic) */ class RecordHolderDetailActivity : AppCompatActivity() { companion object { const val MODE = "mode" const val FROM = "from" const val TO = "to" const val EXCLUDE_DIGITS = "exclude_digits" const val DESELECTED_TYPES = "deselected_types" const val FILTER_LABEL = "filter_label" const val RANGE_LABEL = "range_label" const val EXNO_LABEL = "exno_label" } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_record_holder_detail) val mode = intent.getStringExtra(MODE) ?: "top_caller" val from = intent.getLongExtra(FROM, 0) val to = intent.getLongExtra(TO, System.currentTimeMillis()) val excludeDigits = intent.getStringArrayListExtra(EXCLUDE_DIGITS)?.toSet() ?: emptySet() val deselectedTypes = intent.getStringArrayListExtra(DESELECTED_TYPES)?.toSet() ?: emptySet() findViewById(R.id.btnBack).setOnClickListener { finish() } findViewById(R.id.chipFilter).text = intent.getStringExtra(FILTER_LABEL) ?: "⏷ Filter" findViewById(R.id.chipRange).text = intent.getStringExtra(RANGE_LABEL) ?: "Today ⌄" findViewById(R.id.chipExNo).text = intent.getStringExtra(EXNO_LABEL) ?: "Ex. No.: No ⌄" val df = SimpleDateFormat("dd-MMM-yyyy", Locale.getDefault()) findViewById(R.id.tvRange).text = "${df.format(from)} – ${df.format(to)}" val stats = CallStats(this) val rows = findViewById(R.id.rows) when (mode) { "top_caller" -> { findViewById(R.id.tvTitle).text = "Top Caller" val d = stats.topCallerDetail(from, to, excludeDigits, deselectedTypes) bindNumberDetail(d, rows, showCallCounts = true) } "highest_duration" -> { findViewById(R.id.tvTitle).text = "Highest Total Call Duration" val d = stats.highestTotalDurationDetail(from, to, excludeDigits, deselectedTypes) bindNumberDetail(d, rows, showCallCounts = false) } "longest_call" -> { findViewById(R.id.tvTitle).text = "Longest Call" val d = stats.longestCallDetail(from, to, excludeDigits, deselectedTypes) bindSingleCall(d, rows) } } } private fun bindNumberDetail(d: CallStats.NumberDetail?, rows: LinearLayout, showCallCounts: Boolean) { if (d == null) { showEmpty(rows); return } setAvatar(d.name) findViewById(R.id.tvName).text = d.name ?: d.number addRow(rows, "📱", "Phone Number", d.number) if (showCallCounts) { // Top Caller: about WHO called most — show call counts by direction. addRow(rows, "📞", "Total Calls", d.totalCalls.toString()) addRow(rows, "↙", "Total Incoming Calls", d.incomingCalls.toString()) addRow(rows, "↗", "Total Outgoing Calls", d.outgoingCalls.toString()) addRow(rows, "✕", "Total Missed Calls", d.missedCalls.toString()) addRow(rows, "⊘", "Total Rejected Calls", d.rejectedCalls.toString()) addRow(rows, "◒", "Total Duration", fmt(d.totalDurationSec)) } else { // Highest Total Call Duration: about total TIME spent — show duration by direction. addRow(rows, "◒", "Total Duration", fmt(d.totalDurationSec)) addRow(rows, "↙", "Total Incoming Calls", fmt(d.incomingDurationSec)) addRow(rows, "↗", "Total Outgoing Calls", fmt(d.outgoingDurationSec)) addRow(rows, "📞", "Total Calls", d.totalCalls.toString()) } } private fun bindSingleCall(d: CallStats.SingleCallDetail?, rows: LinearLayout) { if (d == null) { showEmpty(rows); return } setAvatar(d.name) findViewById(R.id.tvName).text = d.name ?: d.number val dateDf = SimpleDateFormat("dd MMM yyyy", Locale.getDefault()) val timeDf = SimpleDateFormat("hh:mm a", Locale.getDefault()) val typeLabel = when (d.type) { CallLog.Calls.INCOMING_TYPE -> "Incoming" CallLog.Calls.OUTGOING_TYPE -> "Outgoing" CallLog.Calls.MISSED_TYPE -> "Missed" CallLog.Calls.REJECTED_TYPE -> "Rejected" else -> "Unknown" } addRow(rows, "📱", "Phone Number", d.number) addRow(rows, "📅", "Date", dateDf.format(d.dateMs)) addRow(rows, "⏱", "Call Time", timeDf.format(d.dateMs)) addRow(rows, "↗", "Call Type", typeLabel) addRow(rows, "◒", "Total Duration", fmt(d.durationSec.toLong())) } private fun setAvatar(name: String?) { val letter = name?.trim()?.firstOrNull()?.uppercaseChar()?.toString() ?: "#" findViewById(R.id.avatarLetter).text = letter } private fun showEmpty(rows: LinearLayout) { findViewById(R.id.tvName).text = "No calls in this range" findViewById(R.id.avatarWrap).let { findViewById(R.id.avatarLetter).text = "—" } rows.removeAllViews() } private fun addRow(container: LinearLayout, icon: String, label: String, value: String) { val row = LinearLayout(this).apply { orientation = LinearLayout.HORIZONTAL gravity = Gravity.CENTER_VERTICAL setPadding(0, dp(14), 0, dp(14)) } row.addView(TextView(this).apply { text = icon; textSize = 16f; setTextColor(0xFF60A5FA.toInt()) layoutParams = LinearLayout.LayoutParams(dp(28), ViewGroup.LayoutParams.WRAP_CONTENT) }) row.addView(TextView(this).apply { text = label; textSize = 14f; setTextColor(0xFFCBD5E1.toInt()) layoutParams = LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f) }) row.addView(TextView(this).apply { text = value; textSize = 14f; setTextColor(0xFFFFFFFF.toInt()); gravity = Gravity.END }) container.addView(row) container.addView(View(this).apply { layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dp(1)) setBackgroundColor(0x22FFFFFF) }) } private fun fmt(s: Long): String { val h = s / 3600; val m = (s % 3600) / 60; val sec = s % 60 return "%dh %dm %ds".format(h, m, sec) } private fun dp(x: Int) = (x * resources.displayMetrics.density).toInt() }