From ca8bc638ba9cbca3f5f6a4d497d45f92e70064f3 Mon Sep 17 00:00:00 2001 From: cloudroam <cloudroam> Date: 星期三, 16 四月 2025 08:44:15 +0800 Subject: [PATCH] add: 火车票和航班处理 --- app/src/main/java/com/example/firstapp/activity/PickupActivity.kt | 8 app/src/main/res/layout/activity_phone_login.xml | 2 app/src/main/res/layout/item_train_package_home.xml | 47 ++ app/src/main/res/layout/item_flight.xml | 59 +++ app/src/main/java/com/example/firstapp/database/response/SmsProcessResponse.kt | 5 app/src/main/java/com/example/firstapp/receiver/SmsReceiver.kt | 46 ++ app/src/main/java/com/example/firstapp/model/TrainGroup.kt | 13 app/src/main/res/layout/item_train_group.xml | 58 +++ app/src/main/java/com/example/firstapp/model/FlightGroup.kt | 13 app/src/main/java/com/example/firstapp/ui/home/HomeViewModel.kt | 46 ++ app/src/main/java/com/example/firstapp/adapter/TrainAdapter.kt | 173 +++++++++ app/src/main/res/layout/item_flight_package_home.xml | 47 ++ app/src/main/java/com/example/firstapp/ui/home/HomeFragment.kt | 32 + app/src/main/res/layout/item_train.xml | 59 +++ app/src/main/java/com/example/firstapp/MainActivity.kt | 192 ++++++++-- app/src/main/java/com/example/firstapp/adapter/FlightAdapter.kt | 173 +++++++++ app/src/main/res/layout/item_flight_group.xml | 58 +++ 17 files changed, 978 insertions(+), 53 deletions(-) diff --git a/app/src/main/java/com/example/firstapp/MainActivity.kt b/app/src/main/java/com/example/firstapp/MainActivity.kt index 9c533a8..2e0691f 100644 --- a/app/src/main/java/com/example/firstapp/MainActivity.kt +++ b/app/src/main/java/com/example/firstapp/MainActivity.kt @@ -44,8 +44,7 @@ registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions -> when { permissions.getOrDefault( - Manifest.permission.RECEIVE_SMS, - false + Manifest.permission.RECEIVE_SMS, false ) && permissions.getOrDefault(Manifest.permission.READ_SMS, false) -> { // 两个权限都获得授权 registerSmsReceiver() @@ -77,7 +76,7 @@ // 重置提醒计划并检查是否有错过的提醒 resetReminders() - + // 检查权限 if (ContextCompat.checkSelfPermission( this, Manifest.permission.RECEIVE_SMS @@ -174,7 +173,7 @@ while (cursor.moveToNext()) { val messageBody = cursor.getString(cursor.getColumnIndexOrThrow("body")) val datetime = cursor.getLong(cursor.getColumnIndexOrThrow("date")) - + // 转换为 Date 对象 val date = Date(datetime) val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()) @@ -193,19 +192,21 @@ // 使用协程处理API调用和数据库操作 CoroutineScope(Dispatchers.IO).launch { try { - val response = RetrofitModelClient.modelService.processSms(mapOf("content" to messageBody)) - + val response = + RetrofitModelClient.modelService.processSms(mapOf("content" to messageBody)) + synchronized(syncLock) { if (response.status == "success") { when (response.data.category) { "快递" -> { val pickupCode = response.data.details.pickupCode ?: "" if (pickupCode.isNotEmpty()) { - val existingCode = Core.code.queryByTypeAndCodeAndDate( - response.data.category, - pickupCode, - dateString - ) + val existingCode = + Core.code.queryByTypeAndCodeAndDate( + response.data.category, + pickupCode, + dateString + ) if (existingCode == null) { val code = Code( @@ -217,32 +218,40 @@ msgId = msgId, createTime = dateString, oneLevel = response.data.details.post ?: "", - secondLevel = response.data.details.company ?: "", + secondLevel = response.data.details.company + ?: "", code = pickupCode, pickup = 0, pickupTime = "", overTime = "", - address = response.data.details.address ?: "", + address = response.data.details.address + ?: "", remarks = response.data.details.time ?: "", ) // if(code.oneLevel.isNotEmpty() && code.secondLevel.isNotEmpty() && code.code.isNotEmpty()) { - if(code.oneLevel.isNotEmpty() && code.code.isNotEmpty()) { + if (code.oneLevel.isNotEmpty() && code.code.isNotEmpty()) { Core.code.insert(code) - android.util.Log.d("MainActivity", "历史快递短信已保存: $pickupCode") + android.util.Log.d( + "MainActivity", + "历史快递短信已保存: $pickupCode" + ) } } else { - android.util.Log.d("MainActivity", "发现重复快递短信,跳过保存: $pickupCode") + android.util.Log.d( + "MainActivity", + "发现重复快递短信,跳过保存: $pickupCode" + ) } } } + "还款" -> { val amount = response.data.details.amount ?: "" if (amount.isNotEmpty()) { - val existingCode = Core.code.queryByTypeAndCodeAndDate( - response.data.category, - amount, - dateString - ) + val existingCode = + Core.code.queryByTypeAndCodeAndDate( + response.data.category, amount, dateString + ) if (existingCode == null) { val code = Code( @@ -254,31 +263,39 @@ msgId = msgId, createTime = dateString, oneLevel = response.data.details.type ?: "", - secondLevel = response.data.details.bank ?: "", + secondLevel = response.data.details.bank + ?: "", code = amount, pickup = 0, pickupTime = "", overTime = response.data.details.date ?: "", - address = response.data.details.address ?: "", + address = response.data.details.address + ?: "", remarks = "最小还款金额${response.data.details.min_amount}还款卡号${response.data.details.number}" ) - if(code.oneLevel.isNotEmpty() && code.secondLevel.isNotEmpty() && code.code.isNotEmpty()) { + if (code.oneLevel.isNotEmpty() && code.secondLevel.isNotEmpty() && code.code.isNotEmpty()) { Core.code.insert(code) - android.util.Log.d("MainActivity", "历史还款短信已保存: $amount") + android.util.Log.d( + "MainActivity", + "历史还款短信已保存: $amount" + ) } } else { - android.util.Log.d("MainActivity", "发现重复还款短信,跳过保存: $amount") + android.util.Log.d( + "MainActivity", + "发现重复还款短信,跳过保存: $amount" + ) } } } + "收入" -> { val amount = response.data.details.amount ?: "" if (amount.isNotEmpty()) { - val existingCode = Core.code.queryByTypeAndCodeAndDate( - response.data.category, - amount, - dateString - ) + val existingCode = + Core.code.queryByTypeAndCodeAndDate( + response.data.category, amount, dateString + ) if (existingCode == null) { val code = Code( @@ -290,21 +307,114 @@ msgId = msgId, createTime = dateString, oneLevel = response.data.details.bank ?: "", - secondLevel = response.data.details.bank ?: "", + secondLevel = response.data.details.bank + ?: "", code = amount, pickup = 0, // 0-未取件,1-已取件 pickupTime = "", // 取件时间为空 overTime = response.data.details.datetime ?: "", // 超时时间为空,暂时没有这块处理逻辑 - address = response.data.details.address ?: "", - remarks = "余额" + response.data.details.balance ?: "", + address = response.data.details.address + ?: "", + remarks = "余额" + response.data.details.balance + ?: "", ) - if(code.oneLevel.isNotEmpty() && code.secondLevel.isNotEmpty() && code.code.isNotEmpty()) { + if (code.oneLevel.isNotEmpty() && code.secondLevel.isNotEmpty() && code.code.isNotEmpty()) { Core.code.insert(code) - android.util.Log.d("MainActivity", "历史还款短信已保存: $amount") + android.util.Log.d( + "MainActivity", + "历史还款短信已保存: $amount" + ) } } else { - android.util.Log.d("MainActivity", "发现重复还款短信,跳过保存: $amount") + android.util.Log.d( + "MainActivity", + "发现重复还款短信,跳过保存: $amount" + ) + } + } + } + + "航班" -> { + val flight = response.data.details.flight ?: "" + if (flight.isNotEmpty()) { + val existingCode = + Core.code.queryByTypeAndCodeAndDate( + response.data.category, flight, dateString + ) + + if (existingCode == null) { + val code = Code( + id = 0, + category = response.data.category, + categoryId = 4, // 4-航班类型 + typeId = 1, //暂时没有根据type分类 + ruleId = 2, //1-还款类型 + msgId = msgId, + createTime = dateString, + oneLevel = response.data.details.company + ?: "", + secondLevel = response.data.details.start + response.data.details.end + ?: "", + code = flight, + pickup = 0, // 0-未取件,1-已取件 + pickupTime = "", // 取件时间为空 + overTime = response.data.details.time + ?: "", // 超时时间为空,暂时没有这块处理逻辑 + address = response.data.details.address + ?: "", + remarks = response.data.details.seat ?: "", + ) + if (code.oneLevel != "" && code.secondLevel != "" && code.code != "") { + Core.code.insert(code) + } + } else { + android.util.Log.d( + "MainActivity", + "发现重复还款短信,跳过保存: $flight" + ) + } + } + } + + "火车票" -> { + val seat = response.data.details.seat ?: "" + if (seat.isNotEmpty()) { + val existingCode = + Core.code.queryByTypeAndCodeAndDate( + response.data.category, seat, dateString + ) + + if (existingCode == null) { + val code = Code( + id = 0, + category = response.data.category, + categoryId = 5, // 5-火车票类型 + typeId = 1, //暂时没有根据type分类 + ruleId = 2, //1-还款类型 + msgId = msgId, + createTime = dateString, + oneLevel = response.data.details.company + ?: "", + secondLevel = response.data.details.company + ?: "", + code = seat, + pickup = 0, // 0-未取件,1-已取件 + pickupTime = "", // 取件时间为空 + overTime = response.data.details.time + ?: "", // 超时时间为空,暂时没有这块处理逻辑 + address = response.data.details.address + ?: "", + remarks = response.data.details.trips ?: "", + ) + if (code.oneLevel != "" && code.secondLevel != "" && code.code != "") { + Core.code.insert(code) + } + } else { + android.util.Log.d( + "MainActivity", + "发现重复还款短信,跳过保存: $seat" + ) } } } @@ -332,16 +442,16 @@ try { // 取消所有现有的提醒任务 androidx.work.WorkManager.getInstance(this).cancelAllWorkByTag("reminder_worker") - + // 清除旧的提醒偏好设置 getSharedPreferences("reminder_prefs", Context.MODE_PRIVATE).edit().clear().apply() - + // 重新设置提醒任务 (application as App).setupReminderWorker() - + // 检查是否有错过的提醒 com.example.firstapp.service.ReminderWorker.checkMissedReminders(this) - + android.util.Log.d("MainActivity", "已重置提醒计划") } catch (e: Exception) { android.util.Log.e("MainActivity", "重置提醒计划失败: ${e.message}") diff --git a/app/src/main/java/com/example/firstapp/activity/PickupActivity.kt b/app/src/main/java/com/example/firstapp/activity/PickupActivity.kt index 48a6dc1..8c7cac4 100644 --- a/app/src/main/java/com/example/firstapp/activity/PickupActivity.kt +++ b/app/src/main/java/com/example/firstapp/activity/PickupActivity.kt @@ -20,6 +20,8 @@ const val TYPE_EXPRESS = "express" const val TYPE_REPAYMENT = "repayment" const val TYPE_INCOME = "income" + const val TYPE_TRAIN = "train" + const val TYPE_FLIGHT = "flight" } private var pageType = TYPE_EXPRESS @@ -65,6 +67,8 @@ TYPE_EXPRESS -> "是否确认取出所有包裹?" TYPE_REPAYMENT -> "是否确认处理所有还款?" TYPE_INCOME -> "是否确认处理所有收入?" + TYPE_TRAIN -> "是否确认处理所有火车票?" + TYPE_FLIGHT -> "是否确认处理所有机票?" else -> "是否确认处理所有项目?" } } @@ -74,6 +78,8 @@ TYPE_EXPRESS -> "全部取件" TYPE_REPAYMENT -> "全部还款" TYPE_INCOME -> "全部收款" + TYPE_TRAIN -> "全部处理票务" + TYPE_FLIGHT -> "全部处理机票" else -> "全部处理" } } @@ -132,6 +138,8 @@ TYPE_EXPRESS -> "共${count}个包裹" TYPE_REPAYMENT -> "共${count}笔还款" TYPE_INCOME -> "共${count}笔收入" + TYPE_TRAIN -> "共${count}张车票" + TYPE_FLIGHT -> "共${count}张机票" else -> "共${count}个" } } diff --git a/app/src/main/java/com/example/firstapp/adapter/FlightAdapter.kt b/app/src/main/java/com/example/firstapp/adapter/FlightAdapter.kt new file mode 100644 index 0000000..2c1365f --- /dev/null +++ b/app/src/main/java/com/example/firstapp/adapter/FlightAdapter.kt @@ -0,0 +1,173 @@ +package com.example.firstapp.adapter + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import com.example.firstapp.R +import com.example.firstapp.databinding.ItemFlightGroupBinding +import com.example.firstapp.databinding.ItemFlightPackageHomeBinding +import com.example.firstapp.databinding.ItemFlightBinding +import com.example.firstapp.model.FlightGroup +import com.example.firstapp.model.FlightPackage + +class FlightAdapter : + ListAdapter<FlightGroup, FlightAdapter.ViewHolder>(FlightGroupDiffCallback()) { + + private var onPackageClickListener: (FlightGroup, FlightPackage) -> Unit = { _, _ -> } + + fun setOnPackageClickListener(listener: (FlightGroup, FlightPackage) -> Unit) { + onPackageClickListener = listener + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + val binding = ItemFlightGroupBinding.inflate( + LayoutInflater.from(parent.context), parent, false + ) + return ViewHolder(binding) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val group = getItem(position) + holder.bind(group) + holder.setOnPackageClickListener(onPackageClickListener) + } + + + inner class ViewHolder(private val binding: ItemFlightGroupBinding) : + RecyclerView.ViewHolder(binding.root) { + private val packagesAdapter = FlightPackageHomeAdapter { pack -> + currentGroup?.let { group -> + onPackageClickListener(group, pack) + } + } + private var currentGroup: FlightGroup? = null + + init { + binding.rvPackages.apply { + layoutManager = LinearLayoutManager(context) + adapter = packagesAdapter + } + } + + fun bind(group: FlightGroup) { + currentGroup = group + binding.tvStationName.text = group.stationName + binding.tvPackageCount.text = "共${group.packages.size}张机票" + packagesAdapter.submitList(group.packages) + } + + fun setOnPackageClickListener(listener: (FlightGroup, FlightPackage) -> Unit) { + // 这个方法可以移除,因为我们在构造 FlightPackageHomeAdapter 时已经处理了点击事件 + // 或者保留这个方法但不做任何操作 + } + } +} + +// 首页使用的机票适配器 - 简化版本 +class FlightPackageHomeAdapter(private val onPackageClick: (FlightPackage) -> Unit) : + ListAdapter<FlightPackage, FlightPackageHomeAdapter.ViewHolder>(FlightPackageDiffCallback()) { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + val binding = ItemFlightPackageHomeBinding.inflate( + LayoutInflater.from(parent.context), parent, false + ) + return ViewHolder(binding) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val pack = getItem(position) + holder.bind(pack) + } + + inner class ViewHolder(private val binding: ItemFlightPackageHomeBinding) : + RecyclerView.ViewHolder(binding.root) { + + init { + binding.root.setOnClickListener { + val pack = getItem(adapterPosition) + onPackageClick(pack) + } + } + + fun bind(pack: FlightPackage) { + binding.tvCompany.text = pack.company + binding.tvCreateTime.text = pack.createTime + binding.tvTrackingNumber.text = pack.trackingNumber + } + } +} + +// 取件页面使用的机票适配器 +class FlightPackageAdapter(private val onPackagePickup: (FlightPackage) -> Unit = { _ -> }) : + ListAdapter<FlightPackage, FlightPackageAdapter.ViewHolder>(FlightPackageDiffCallback()) { + + private var onPackageClickListener: (FlightPackage) -> Unit = {} + private var stationName: String = "" + + fun setStationInfo(station: String) { + stationName = station + } + + fun setOnPackageClickListener(listener: (FlightPackage) -> Unit) { + onPackageClickListener = listener + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + val binding = ItemFlightBinding.inflate( + LayoutInflater.from(parent.context), parent, false + ) + return ViewHolder(binding) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val pack = getItem(position) + holder.bind(pack) + } + + inner class ViewHolder(private val binding: ItemFlightBinding) : + RecyclerView.ViewHolder(binding.root) { + + init { + binding.ivPackageStatus.setOnClickListener { + val pack = getItem(adapterPosition) + onPackagePickup(pack) + } + + binding.root.setOnClickListener(null) + } + + fun bind(pack: FlightPackage) { + binding.tvPackageId.text = pack.id.toString() + binding.tvCompany.text = pack.company + binding.tvCreateTime.text = pack.createTime + binding.tvTrackingNumber.text = pack.trackingNumber + binding.ivPackageStatus.setImageResource( + R.drawable.circle + ) + } + } +} + + +private class FlightGroupDiffCallback : DiffUtil.ItemCallback<FlightGroup>() { + override fun areItemsTheSame(oldItem: FlightGroup, newItem: FlightGroup): Boolean { + return oldItem.stationName == newItem.stationName + } + + override fun areContentsTheSame(oldItem: FlightGroup, newItem: FlightGroup): Boolean { + return oldItem == newItem + } +} + +private class FlightPackageDiffCallback : DiffUtil.ItemCallback<FlightPackage>() { + override fun areItemsTheSame(oldItem: FlightPackage, newItem: FlightPackage): Boolean { + return oldItem.trackingNumber == newItem.trackingNumber + } + + override fun areContentsTheSame(oldItem: FlightPackage, newItem: FlightPackage): Boolean { + return oldItem == newItem + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/firstapp/adapter/TrainAdapter.kt b/app/src/main/java/com/example/firstapp/adapter/TrainAdapter.kt new file mode 100644 index 0000000..0efd02f --- /dev/null +++ b/app/src/main/java/com/example/firstapp/adapter/TrainAdapter.kt @@ -0,0 +1,173 @@ +package com.example.firstapp.adapter + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import com.example.firstapp.R +import com.example.firstapp.databinding.ItemTrainGroupBinding +import com.example.firstapp.databinding.ItemTrainPackageHomeBinding +import com.example.firstapp.databinding.ItemTrainBinding +import com.example.firstapp.model.TrainGroup +import com.example.firstapp.model.TrainPackage + +class TrainAdapter : + ListAdapter<TrainGroup, TrainAdapter.ViewHolder>(TrainGroupDiffCallback()) { + + private var onPackageClickListener: (TrainGroup, TrainPackage) -> Unit = { _, _ -> } + + fun setOnPackageClickListener(listener: (TrainGroup, TrainPackage) -> Unit) { + onPackageClickListener = listener + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + val binding = ItemTrainGroupBinding.inflate( + LayoutInflater.from(parent.context), parent, false + ) + return ViewHolder(binding) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val group = getItem(position) + holder.bind(group) + holder.setOnPackageClickListener(onPackageClickListener) + } + + + inner class ViewHolder(private val binding: ItemTrainGroupBinding) : + RecyclerView.ViewHolder(binding.root) { + private val packagesAdapter = TrainPackageHomeAdapter { pack -> + currentGroup?.let { group -> + onPackageClickListener(group, pack) + } + } + private var currentGroup: TrainGroup? = null + + init { + binding.rvPackages.apply { + layoutManager = LinearLayoutManager(context) + adapter = packagesAdapter + } + } + + fun bind(group: TrainGroup) { + currentGroup = group + binding.tvStationName.text = group.stationName + binding.tvPackageCount.text = "共${group.packages.size}张车票" + packagesAdapter.submitList(group.packages) + } + + fun setOnPackageClickListener(listener: (TrainGroup, TrainPackage) -> Unit) { + // 这个方法可以移除,因为我们在构造 TrainPackageHomeAdapter 时已经处理了点击事件 + // 或者保留这个方法但不做任何操作 + } + } +} + +// 首页使用的车票适配器 - 简化版本 +class TrainPackageHomeAdapter(private val onPackageClick: (TrainPackage) -> Unit) : + ListAdapter<TrainPackage, TrainPackageHomeAdapter.ViewHolder>(TrainPackageDiffCallback()) { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + val binding = ItemTrainPackageHomeBinding.inflate( + LayoutInflater.from(parent.context), parent, false + ) + return ViewHolder(binding) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val pack = getItem(position) + holder.bind(pack) + } + + inner class ViewHolder(private val binding: ItemTrainPackageHomeBinding) : + RecyclerView.ViewHolder(binding.root) { + + init { + binding.root.setOnClickListener { + val pack = getItem(adapterPosition) + onPackageClick(pack) + } + } + + fun bind(pack: TrainPackage) { + binding.tvCompany.text = pack.company + binding.tvCreateTime.text = pack.createTime + binding.tvTrackingNumber.text = pack.trackingNumber + } + } +} + +// 取件页面使用的车票适配器 +class TrainPackageAdapter(private val onPackagePickup: (TrainPackage) -> Unit = { _ -> }) : + ListAdapter<TrainPackage, TrainPackageAdapter.ViewHolder>(TrainPackageDiffCallback()) { + + private var onPackageClickListener: (TrainPackage) -> Unit = {} + private var stationName: String = "" + + fun setStationInfo(station: String) { + stationName = station + } + + fun setOnPackageClickListener(listener: (TrainPackage) -> Unit) { + onPackageClickListener = listener + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + val binding = ItemTrainBinding.inflate( + LayoutInflater.from(parent.context), parent, false + ) + return ViewHolder(binding) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val pack = getItem(position) + holder.bind(pack) + } + + inner class ViewHolder(private val binding: ItemTrainBinding) : + RecyclerView.ViewHolder(binding.root) { + + init { + binding.ivPackageStatus.setOnClickListener { + val pack = getItem(adapterPosition) + onPackagePickup(pack) + } + + binding.root.setOnClickListener(null) + } + + fun bind(pack: TrainPackage) { + binding.tvPackageId.text = pack.id.toString() + binding.tvCompany.text = pack.company + binding.tvCreateTime.text = pack.createTime + binding.tvTrackingNumber.text = pack.trackingNumber + binding.ivPackageStatus.setImageResource( + R.drawable.circle + ) + } + } +} + + +private class TrainGroupDiffCallback : DiffUtil.ItemCallback<TrainGroup>() { + override fun areItemsTheSame(oldItem: TrainGroup, newItem: TrainGroup): Boolean { + return oldItem.stationName == newItem.stationName + } + + override fun areContentsTheSame(oldItem: TrainGroup, newItem: TrainGroup): Boolean { + return oldItem == newItem + } +} + +private class TrainPackageDiffCallback : DiffUtil.ItemCallback<TrainPackage>() { + override fun areItemsTheSame(oldItem: TrainPackage, newItem: TrainPackage): Boolean { + return oldItem.trackingNumber == newItem.trackingNumber + } + + override fun areContentsTheSame(oldItem: TrainPackage, newItem: TrainPackage): Boolean { + return oldItem == newItem + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/firstapp/database/response/SmsProcessResponse.kt b/app/src/main/java/com/example/firstapp/database/response/SmsProcessResponse.kt index 523f7aa..c5633f1 100644 --- a/app/src/main/java/com/example/firstapp/database/response/SmsProcessResponse.kt +++ b/app/src/main/java/com/example/firstapp/database/response/SmsProcessResponse.kt @@ -28,4 +28,9 @@ val number: String?, val datetime: String?, val balance: String?, + val seat: String?, + val trips: String?, + val start: String?, + val end: String?, + val flight: String?, ) \ No newline at end of file diff --git a/app/src/main/java/com/example/firstapp/model/FlightGroup.kt b/app/src/main/java/com/example/firstapp/model/FlightGroup.kt new file mode 100644 index 0000000..5fe244e --- /dev/null +++ b/app/src/main/java/com/example/firstapp/model/FlightGroup.kt @@ -0,0 +1,13 @@ +package com.example.firstapp.model + +data class FlightGroup( + val stationName: String, + val packages: List<FlightPackage> +) + +data class FlightPackage( + var id: Long, + val company: String, + val trackingNumber: String, + val createTime: String +) \ No newline at end of file diff --git a/app/src/main/java/com/example/firstapp/model/TrainGroup.kt b/app/src/main/java/com/example/firstapp/model/TrainGroup.kt new file mode 100644 index 0000000..b7f4229 --- /dev/null +++ b/app/src/main/java/com/example/firstapp/model/TrainGroup.kt @@ -0,0 +1,13 @@ +package com.example.firstapp.model + +data class TrainGroup( + val stationName: String, + val packages: List<TrainPackage> +) + +data class TrainPackage( + var id: Long, + val company: String, + val trackingNumber: String, + val createTime: String +) \ No newline at end of file diff --git a/app/src/main/java/com/example/firstapp/receiver/SmsReceiver.kt b/app/src/main/java/com/example/firstapp/receiver/SmsReceiver.kt index 9a611bb..f0e2073 100644 --- a/app/src/main/java/com/example/firstapp/receiver/SmsReceiver.kt +++ b/app/src/main/java/com/example/firstapp/receiver/SmsReceiver.kt @@ -142,6 +142,52 @@ Core.code.insert(code) } } + "航班" -> { + val code = Code( + id = 0, + category = response.data.category, + categoryId = 4, // 4-航班类型 + typeId = 1, //暂时没有根据type分类 + ruleId = 2, //1-还款类型 + msgId = msgId, + createTime = createtime, + oneLevel = response.data.details.company ?: "", + secondLevel = response.data.details.start +response.data.details.end?: "", + code = response.data.details.seat ?: "", + pickup = 0, // 0-未取件,1-已取件 + pickupTime = "", // 取件时间为空 + overTime = response.data.details.time + ?: "", // 超时时间为空,暂时没有这块处理逻辑 + address = response.data.details.address ?: "", + remarks = response.data.details.seat ?: "", + ) + if(code.oneLevel!="" && code.secondLevel!="" && code.code!="") { + Core.code.insert(code) + } + } + "火车票" -> { + val code = Code( + id = 0, + category = response.data.category, + categoryId = 5, // 5-火车票类型 + typeId = 1, //暂时没有根据type分类 + ruleId = 2, //1-还款类型 + msgId = msgId, + createTime = createtime, + oneLevel = response.data.details.company ?: "", + secondLevel = response.data.details.company ?: "", + code = response.data.details.seat ?: "", + pickup = 0, // 0-未取件,1-已取件 + pickupTime = "", // 取件时间为空 + overTime = response.data.details.time + ?: "", // 超时时间为空,暂时没有这块处理逻辑 + address = response.data.details.address ?: "", + remarks = response.data.details.trips ?: "", + ) + if(code.oneLevel!="" && code.secondLevel!="" && code.code!="") { + Core.code.insert(code) + } + } } // 发送广播通知数据已更新 diff --git a/app/src/main/java/com/example/firstapp/ui/home/HomeFragment.kt b/app/src/main/java/com/example/firstapp/ui/home/HomeFragment.kt index edaff47..03440a8 100644 --- a/app/src/main/java/com/example/firstapp/ui/home/HomeFragment.kt +++ b/app/src/main/java/com/example/firstapp/ui/home/HomeFragment.kt @@ -22,6 +22,8 @@ import com.example.firstapp.adapter.FinanceAdapter import com.example.firstapp.adapter.CategorySelectorAdapter import com.example.firstapp.adapter.IncomeAdapter +import com.example.firstapp.adapter.TrainAdapter +import com.example.firstapp.adapter.FlightAdapter import com.example.firstapp.database.service.RetrofitClient import com.example.firstapp.databinding.FragmentHomeBinding import com.example.firstapp.databinding.DialogCategorySelectorBinding @@ -45,8 +47,8 @@ private lateinit var expressAdapter: ExpressAdapter private lateinit var financeAdapter: FinanceAdapter private lateinit var incomeAdapter: IncomeAdapter - private lateinit var flightAdapter: FinanceAdapter - private lateinit var trainAdapter: FinanceAdapter + private lateinit var flightAdapter: FlightAdapter + private lateinit var trainAdapter: TrainAdapter private lateinit var dataUpdateReceiver: BroadcastReceiver private lateinit var reminderUpdateReceiver: BroadcastReceiver private var reminderBadge: TextView? = null @@ -185,16 +187,38 @@ binding.flightRecycler.apply { layoutManager = LinearLayoutManager(context) - flightAdapter = FinanceAdapter() + flightAdapter = FlightAdapter() adapter = flightAdapter visibility = View.GONE + + // 设置点击监听 + flightAdapter.setOnPackageClickListener { group, pack -> + // 跳转到航班处理页面 + val intent = Intent(requireContext(), PickupActivity::class.java).apply { + putExtra("station_name", group.stationName) + putExtra("company", pack.company) + putExtra("page_type", PickupActivity.TYPE_FLIGHT) + } + startActivity(intent) + } } binding.trainRecycler.apply { layoutManager = LinearLayoutManager(context) - trainAdapter = FinanceAdapter() + trainAdapter = TrainAdapter() adapter = trainAdapter visibility = View.GONE + + // 设置点击监听 + trainAdapter.setOnPackageClickListener { group, pack -> + // 跳转到火车票页面 + val intent = Intent(requireContext(), PickupActivity::class.java).apply { + putExtra("station_name", group.stationName) + putExtra("company", pack.company) + putExtra("page_type", PickupActivity.TYPE_TRAIN) + } + startActivity(intent) + } } } diff --git a/app/src/main/java/com/example/firstapp/ui/home/HomeViewModel.kt b/app/src/main/java/com/example/firstapp/ui/home/HomeViewModel.kt index 0601ec9..45b5b0a 100644 --- a/app/src/main/java/com/example/firstapp/ui/home/HomeViewModel.kt +++ b/app/src/main/java/com/example/firstapp/ui/home/HomeViewModel.kt @@ -21,20 +21,24 @@ import kotlinx.coroutines.launch import com.example.firstapp.database.repository.ReminderRecordRepository import com.example.firstapp.database.entity.ReminderRecord +import com.example.firstapp.model.TrainGroup +import com.example.firstapp.model.TrainPackage +import com.example.firstapp.model.FlightGroup +import com.example.firstapp.model.FlightPackage class HomeViewModel : ViewModel() { private val _expressItems = MutableLiveData<List<ExpressGroup>>() private val _financeItems = MutableLiveData<List<FinanceGroup>>() private val _incomeItems = MutableLiveData<List<IncomeGroup>>() - private val _flightItems = MutableLiveData<List<FinanceGroup>>() - private val _trainItems = MutableLiveData<List<FinanceGroup>>() + private val _flightItems = MutableLiveData<List<FlightGroup>>() + private val _trainItems = MutableLiveData<List<TrainGroup>>() val expressItems: LiveData<List<ExpressGroup>> = _expressItems val financeItems: LiveData<List<FinanceGroup>> = _financeItems val incomeItems: LiveData<List<IncomeGroup>> = _incomeItems - val flightItems: LiveData<List<FinanceGroup>> = _flightItems - val trainItems: LiveData<List<FinanceGroup>> = _trainItems + val flightItems: LiveData<List<FlightGroup>> = _flightItems + val trainItems: LiveData<List<TrainGroup>> = _trainItems private val _categories = MutableLiveData<List<CategoryConfig>>() val categories: LiveData<List<CategoryConfig>> = _categories @@ -105,8 +109,38 @@ } _incomeItems.postValue(groups) } + "火车票" -> { + // 处理火车票类型 + val groups = stations.map { station -> + val packages = Core.code.getPackagesByTypeAndStation(type, station.stationName).map { code -> + TrainPackage( + id = code.id, + company = code.secondLevel, + trackingNumber = code.code, + createTime = code.createTime + ) + } + TrainGroup(stationName = station.stationName, packages = packages) + } + _trainItems.postValue(groups) + } + "航班" -> { + // 处理航班类型 + val groups = stations.map { station -> + val packages = Core.code.getPackagesByTypeAndStation(type, station.stationName).map { code -> + FlightPackage( + id = code.id, + company = code.secondLevel, + trackingNumber = code.code, + createTime = code.createTime + ) + } + FlightGroup(stationName = station.stationName, packages = packages) + } + _flightItems.postValue(groups) + } else -> { - // 处理其他类型(还款、航班、火车票) + // 处理其他类型(还款) val groups = stations.map { station -> val packages = Core.code.getPackagesByTypeAndStation(type, station.stationName).map { code -> FinancePackage( @@ -122,8 +156,6 @@ // 根据类型更新对应的 LiveData when (type) { "还款" -> _financeItems.postValue(groups) - "航班" -> _flightItems.postValue(groups) - "火车票" -> _trainItems.postValue(groups) } } } diff --git a/app/src/main/res/layout/activity_phone_login.xml b/app/src/main/res/layout/activity_phone_login.xml index 833feb5..3144a69 100644 --- a/app/src/main/res/layout/activity_phone_login.xml +++ b/app/src/main/res/layout/activity_phone_login.xml @@ -97,7 +97,7 @@ android:layout_height="wrap_content" android:background="@null" android:hint="邀请码" - android:inputType="phone" + android:inputType="textVisiblePassword" android:maxLength="11" android:textSize="16sp" android:padding="12dp"/> diff --git a/app/src/main/res/layout/item_flight.xml b/app/src/main/res/layout/item_flight.xml new file mode 100644 index 0000000..6c4e6cb --- /dev/null +++ b/app/src/main/res/layout/item_flight.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:padding="12dp" + android:gravity="center_vertical"> + + <ImageView + android:id="@+id/iv_package_status" + android:layout_width="12dp" + android:layout_height="12dp" + android:src="@drawable/circle"/> + + <TextView + android:id="@+id/tv_package_id" + android:layout_width="0dp" + android:layout_height="0dp" + android:visibility="gone"/> + + <ImageView + android:id="@+id/iv_company_logo" + android:layout_width="20dp" + android:layout_height="20dp" + android:layout_marginEnd="6dp"/> + + <LinearLayout + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:orientation="vertical"> + + <TextView + android:id="@+id/tv_company" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="12sp" + android:textColor="#333333" + android:textStyle="bold"/> + + <TextView + android:id="@+id/tv_create_time" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="12sp" + android:textColor="#666666" + android:layout_marginTop="4dp"/> + </LinearLayout> + + <TextView + android:id="@+id/tv_tracking_number" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="25sp" + android:textColor="#333333" + android:layout_marginStart="12dp" + android:textStyle="bold"/> + +</LinearLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/item_flight_group.xml b/app/src/main/res/layout/item_flight_group.xml new file mode 100644 index 0000000..cde9c53 --- /dev/null +++ b/app/src/main/res/layout/item_flight_group.xml @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="utf-8"?> +<com.google.android.material.card.MaterialCardView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginHorizontal="12dp" + android:layout_marginVertical="6dp" + app:cardCornerRadius="8dp" + app:cardElevation="2dp" + app:cardBackgroundColor="@android:color/white" + app:strokeColor="#FF000000" + app:strokeWidth="2dp"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:padding="16dp"> + + <!-- 机场名称和机票数量 --> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:layout_marginBottom="12dp"> + + <ImageView + android:id="@+id/iv_station_icon" + android:layout_width="20dp" + android:layout_height="20dp" + android:layout_gravity="center_vertical" + android:src="@drawable/location"/> + + <TextView + android:id="@+id/tv_station_name" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:layout_marginStart="8dp" + android:textSize="16sp" + android:textColor="#333333"/> + + <TextView + android:id="@+id/tv_package_count" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="14sp" + android:textColor="#666666"/> + </LinearLayout> + + <!-- 机票列表 --> + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/rv_packages" + android:layout_width="match_parent" + android:layout_height="wrap_content"/> + </LinearLayout> +</com.google.android.material.card.MaterialCardView> \ No newline at end of file diff --git a/app/src/main/res/layout/item_flight_package_home.xml b/app/src/main/res/layout/item_flight_package_home.xml new file mode 100644 index 0000000..ef12f23 --- /dev/null +++ b/app/src/main/res/layout/item_flight_package_home.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:padding="12dp" + android:gravity="center_vertical"> + + <ImageView + android:id="@+id/iv_company_logo" + android:layout_width="20dp" + android:layout_height="20dp" + android:layout_marginEnd="6dp"/> + + <LinearLayout + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:orientation="vertical"> + + <TextView + android:id="@+id/tv_company" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="12sp" + android:textColor="#333333" + android:textStyle="bold"/> + + <TextView + android:id="@+id/tv_create_time" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="10sp" + android:textColor="#666666" + android:layout_marginTop="4dp"/> + </LinearLayout> + + <TextView + android:id="@+id/tv_tracking_number" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="25sp" + android:textColor="#333333" + android:layout_marginStart="12dp" + android:textStyle="bold"/> + +</LinearLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/item_train.xml b/app/src/main/res/layout/item_train.xml new file mode 100644 index 0000000..6c4e6cb --- /dev/null +++ b/app/src/main/res/layout/item_train.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:padding="12dp" + android:gravity="center_vertical"> + + <ImageView + android:id="@+id/iv_package_status" + android:layout_width="12dp" + android:layout_height="12dp" + android:src="@drawable/circle"/> + + <TextView + android:id="@+id/tv_package_id" + android:layout_width="0dp" + android:layout_height="0dp" + android:visibility="gone"/> + + <ImageView + android:id="@+id/iv_company_logo" + android:layout_width="20dp" + android:layout_height="20dp" + android:layout_marginEnd="6dp"/> + + <LinearLayout + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:orientation="vertical"> + + <TextView + android:id="@+id/tv_company" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="12sp" + android:textColor="#333333" + android:textStyle="bold"/> + + <TextView + android:id="@+id/tv_create_time" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="12sp" + android:textColor="#666666" + android:layout_marginTop="4dp"/> + </LinearLayout> + + <TextView + android:id="@+id/tv_tracking_number" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="25sp" + android:textColor="#333333" + android:layout_marginStart="12dp" + android:textStyle="bold"/> + +</LinearLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/item_train_group.xml b/app/src/main/res/layout/item_train_group.xml new file mode 100644 index 0000000..80083d8 --- /dev/null +++ b/app/src/main/res/layout/item_train_group.xml @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="utf-8"?> +<com.google.android.material.card.MaterialCardView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginHorizontal="12dp" + android:layout_marginVertical="6dp" + app:cardCornerRadius="8dp" + app:cardElevation="2dp" + app:cardBackgroundColor="@android:color/white" + app:strokeColor="#FF000000" + app:strokeWidth="2dp"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:padding="16dp"> + + <!-- 车站名称和车票数量 --> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:layout_marginBottom="12dp"> + + <ImageView + android:id="@+id/iv_station_icon" + android:layout_width="20dp" + android:layout_height="20dp" + android:layout_gravity="center_vertical" + android:src="@drawable/location"/> + + <TextView + android:id="@+id/tv_station_name" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:layout_marginStart="8dp" + android:textSize="16sp" + android:textColor="#333333"/> + + <TextView + android:id="@+id/tv_package_count" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="14sp" + android:textColor="#666666"/> + </LinearLayout> + + <!-- 车票列表 --> + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/rv_packages" + android:layout_width="match_parent" + android:layout_height="wrap_content"/> + </LinearLayout> +</com.google.android.material.card.MaterialCardView> \ No newline at end of file diff --git a/app/src/main/res/layout/item_train_package_home.xml b/app/src/main/res/layout/item_train_package_home.xml new file mode 100644 index 0000000..ef12f23 --- /dev/null +++ b/app/src/main/res/layout/item_train_package_home.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:padding="12dp" + android:gravity="center_vertical"> + + <ImageView + android:id="@+id/iv_company_logo" + android:layout_width="20dp" + android:layout_height="20dp" + android:layout_marginEnd="6dp"/> + + <LinearLayout + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:orientation="vertical"> + + <TextView + android:id="@+id/tv_company" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="12sp" + android:textColor="#333333" + android:textStyle="bold"/> + + <TextView + android:id="@+id/tv_create_time" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="10sp" + android:textColor="#666666" + android:layout_marginTop="4dp"/> + </LinearLayout> + + <TextView + android:id="@+id/tv_tracking_number" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="25sp" + android:textColor="#333333" + android:layout_marginStart="12dp" + android:textStyle="bold"/> + +</LinearLayout> \ No newline at end of file -- Gitblit v1.9.3