录音自动上传
This commit is contained in:
1
.idea/misc.xml
generated
1
.idea/misc.xml
generated
@@ -1,4 +1,3 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="ms-21" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="ms-21" project-jdk-type="JavaSDK">
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.example.initiateaphonecallapp.data.model
|
||||||
|
|
||||||
|
data class CallRecordCheckRequest(
|
||||||
|
val data: List<String>? = null
|
||||||
|
)
|
||||||
@@ -2,9 +2,8 @@ package com.example.initiateaphonecallapp.data.network
|
|||||||
|
|
||||||
import com.example.initiateaphonecallapp.data.model.ApiCallRecord
|
import com.example.initiateaphonecallapp.data.model.ApiCallRecord
|
||||||
import com.example.initiateaphonecallapp.data.model.ApiResponse
|
import com.example.initiateaphonecallapp.data.model.ApiResponse
|
||||||
|
import com.example.initiateaphonecallapp.data.model.CallRecordCheckRequest
|
||||||
import com.example.initiateaphonecallapp.data.model.CallRecordRequest
|
import com.example.initiateaphonecallapp.data.model.CallRecordRequest
|
||||||
import com.example.initiateaphonecallapp.data.model.LoginRequest
|
|
||||||
import com.example.initiateaphonecallapp.data.model.LoginResponse
|
|
||||||
import retrofit2.Response
|
import retrofit2.Response
|
||||||
import retrofit2.http.Body
|
import retrofit2.http.Body
|
||||||
import retrofit2.http.POST
|
import retrofit2.http.POST
|
||||||
@@ -12,4 +11,7 @@ import retrofit2.http.POST
|
|||||||
interface ApiCallLogService {
|
interface ApiCallLogService {
|
||||||
@POST("app/call-log/my")
|
@POST("app/call-log/my")
|
||||||
suspend fun callLog(@Body callRecordRequest: CallRecordRequest): Response<ApiResponse<List<ApiCallRecord>>>
|
suspend fun callLog(@Body callRecordRequest: CallRecordRequest): Response<ApiResponse<List<ApiCallRecord>>>
|
||||||
|
|
||||||
|
@POST("app/call-log/check")
|
||||||
|
suspend fun callLogCheck(@Body callRecordRequest: CallRecordCheckRequest): Response<ApiResponse<List<String>>>
|
||||||
}
|
}
|
||||||
@@ -4,9 +4,9 @@ package com.example.initiateaphonecallapp.data.repository
|
|||||||
import com.example.initiateaphonecallapp.data.model.ApiCallRecord
|
import com.example.initiateaphonecallapp.data.model.ApiCallRecord
|
||||||
import com.example.initiateaphonecallapp.data.model.ApiResponse
|
import com.example.initiateaphonecallapp.data.model.ApiResponse
|
||||||
import com.example.initiateaphonecallapp.data.model.CallRecord
|
import com.example.initiateaphonecallapp.data.model.CallRecord
|
||||||
|
import com.example.initiateaphonecallapp.data.model.CallRecordCheckRequest
|
||||||
import com.example.initiateaphonecallapp.data.model.CallRecordRequest
|
import com.example.initiateaphonecallapp.data.model.CallRecordRequest
|
||||||
import com.example.initiateaphonecallapp.data.model.toCallRecords
|
import com.example.initiateaphonecallapp.data.model.toCallRecords
|
||||||
import com.example.initiateaphonecallapp.data.network.ApiCallLogService
|
|
||||||
import com.example.initiateaphonecallapp.data.network.RetrofitClient
|
import com.example.initiateaphonecallapp.data.network.RetrofitClient
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
@@ -16,6 +16,7 @@ class CallLogRepository(
|
|||||||
|
|
||||||
) {
|
) {
|
||||||
private val apiCallLogService = RetrofitClient.apiCallLogService
|
private val apiCallLogService = RetrofitClient.apiCallLogService
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取通话记录列表
|
* 获取通话记录列表
|
||||||
* @param request 时间范围请求参数
|
* @param request 时间范围请求参数
|
||||||
@@ -54,4 +55,44 @@ class CallLogRepository(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证录音文件
|
||||||
|
* @param data 请求参数
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
suspend fun checkCallLogs(data: CallRecordCheckRequest): Result<List<String>> {
|
||||||
|
return withContext(Dispatchers.IO) {
|
||||||
|
try {
|
||||||
|
val response = apiCallLogService.callLogCheck(data)
|
||||||
|
handleCheckResponse(response)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Result.failure(Exception("网络请求失败: ${e.message}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理 API 响应
|
||||||
|
*/
|
||||||
|
private fun handleCheckResponse(response: Response<ApiResponse<List<String>>>): Result<List<String>> {
|
||||||
|
return when {
|
||||||
|
response.isSuccessful -> {
|
||||||
|
val apiResponse = response.body()
|
||||||
|
when (apiResponse?.code) {
|
||||||
|
200 -> {
|
||||||
|
val callRecords = apiResponse.data
|
||||||
|
Result.success(callRecords)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
Result.failure(Exception(apiResponse?.message ?: "未知错误"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
Result.failure(Exception("网络错误: ${response.code()} ${response.message()}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -288,7 +288,7 @@ object CallRecordManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 上传通话记录
|
// 上传通话记录
|
||||||
private fun uploadCallRecord(callRecord: CallRecord) {
|
fun uploadCallRecord(callRecord: CallRecord) {
|
||||||
println("📤 CallRecordManager: 开始上传通话记录...")
|
println("📤 CallRecordManager: 开始上传通话记录...")
|
||||||
println(" 📞 电话号码: ${callRecord.phoneNumber}")
|
println(" 📞 电话号码: ${callRecord.phoneNumber}")
|
||||||
println(" ⏱️ 通话时长: ${callRecord.formattedDuration}")
|
println(" ⏱️ 通话时长: ${callRecord.formattedDuration}")
|
||||||
@@ -373,7 +373,16 @@ object CallRecordManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 以下辅助方法保持不变...
|
// 暴露接口
|
||||||
|
fun scanAudioFiles(context: Context, onResult: (List<AudioFile>) -> Unit) {
|
||||||
|
scope.launch {
|
||||||
|
val files = queryAudioInTargetDirs(context)
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
onResult(files)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun queryAudioInTargetDirs(context: Context): List<AudioFile> = withContext(Dispatchers.IO) {
|
private suspend fun queryAudioInTargetDirs(context: Context): List<AudioFile> = withContext(Dispatchers.IO) {
|
||||||
val audioList = mutableListOf<AudioFile>()
|
val audioList = mutableListOf<AudioFile>()
|
||||||
val TAG = "CallRecordManager"
|
val TAG = "CallRecordManager"
|
||||||
|
|||||||
@@ -7,35 +7,32 @@ import androidx.compose.foundation.layout.*
|
|||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Add
|
|
||||||
import androidx.compose.material.icons.filled.ArrowDropDown
|
import androidx.compose.material.icons.filled.ArrowDropDown
|
||||||
import androidx.compose.material.icons.filled.Call
|
import androidx.compose.material.icons.filled.Call
|
||||||
import androidx.compose.material.icons.filled.CheckCircle
|
import androidx.compose.material.icons.filled.CheckCircle
|
||||||
import androidx.compose.material.icons.filled.Info
|
import androidx.compose.material.icons.filled.Info
|
||||||
import androidx.compose.material.icons.filled.Phone
|
import androidx.compose.material.icons.filled.Phone
|
||||||
import androidx.compose.material.icons.filled.PlayArrow
|
|
||||||
import androidx.compose.material.icons.filled.Refresh
|
import androidx.compose.material.icons.filled.Refresh
|
||||||
import androidx.compose.material.icons.filled.Warning
|
import androidx.compose.material.icons.filled.Warning
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.example.initiateaphonecallapp.data.model.CallRecord
|
import com.example.initiateaphonecallapp.data.model.CallRecord
|
||||||
import com.example.initiateaphonecallapp.data.model.toCallRecord
|
|
||||||
import com.example.initiateaphonecallapp.enums.CallStatus
|
import com.example.initiateaphonecallapp.enums.CallStatus
|
||||||
import com.example.initiateaphonecallapp.enums.CallStatus.*
|
import com.example.initiateaphonecallapp.enums.CallStatus.*
|
||||||
|
import com.example.initiateaphonecallapp.manager.CallRecordManager
|
||||||
import com.example.initiateaphonecallapp.ui.contact.ContactsViewModel
|
import com.example.initiateaphonecallapp.ui.contact.ContactsViewModel
|
||||||
import com.example.initiateaphonecallapp.utils.TimeRangeUtils
|
import com.example.initiateaphonecallapp.utils.TimeRangeUtils
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
@@ -65,6 +62,9 @@ fun CallLogScreen(
|
|||||||
var selectedPhoneNumber by remember { mutableStateOf("") }
|
var selectedPhoneNumber by remember { mutableStateOf("") }
|
||||||
var showSuccessDialog by remember { mutableStateOf(false) } // 新增:成功提示框
|
var showSuccessDialog by remember { mutableStateOf(false) } // 新增:成功提示框
|
||||||
var successMessage by remember { mutableStateOf("") } // 新增:成功消息
|
var successMessage by remember { mutableStateOf("") } // 新增:成功消息
|
||||||
|
|
||||||
|
var showScanDialog by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
|
|
||||||
@@ -123,7 +123,7 @@ fun CallLogScreen(
|
|||||||
viewModel.loadCallRecords(range, request)
|
viewModel.loadCallRecords(range, request)
|
||||||
},
|
},
|
||||||
onScanAudio = {
|
onScanAudio = {
|
||||||
viewModel.scanAllAudio()
|
showScanDialog = true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@@ -195,6 +195,18 @@ fun CallLogScreen(
|
|||||||
onDismiss = { showSuccessDialog = false }
|
onDismiss = { showSuccessDialog = false }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 扫描录音弹窗
|
||||||
|
if (showScanDialog) {
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
viewModel.scanAndProcessAudio(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
ScanAudioDialog(
|
||||||
|
viewModel = viewModel,
|
||||||
|
onDismiss = { showScanDialog = false }
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -531,6 +543,51 @@ fun EmptyCallLog(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ScanAudioDialog(
|
||||||
|
viewModel: CallLogViewModel,
|
||||||
|
onDismiss: () -> Unit
|
||||||
|
) {
|
||||||
|
val audioFiles by remember { derivedStateOf { viewModel.audioFiles } }
|
||||||
|
val progress by remember { derivedStateOf { viewModel.progress } }
|
||||||
|
val isScanning by remember { derivedStateOf { viewModel.isScanning } }
|
||||||
|
|
||||||
|
AlertDialog(
|
||||||
|
onDismissRequest = { /* 禁止点击空白关闭 */ },
|
||||||
|
title = {
|
||||||
|
Text(
|
||||||
|
when {
|
||||||
|
isScanning -> "正在扫描录音…"
|
||||||
|
progress < audioFiles.size -> "处理中… $progress / ${audioFiles.size}"
|
||||||
|
else -> "处理完成!"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
text = {
|
||||||
|
Column {
|
||||||
|
if (isScanning) {
|
||||||
|
CircularProgressIndicator()
|
||||||
|
Spacer(Modifier.height(12.dp))
|
||||||
|
Text("正在扫描录音文件,请稍候…")
|
||||||
|
} else {
|
||||||
|
LinearProgressIndicator(
|
||||||
|
progress = if (audioFiles.isNotEmpty()) progress.toFloat() / audioFiles.size else 0f,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
)
|
||||||
|
Spacer(Modifier.height(8.dp))
|
||||||
|
Text("$progress / ${audioFiles.size}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
confirmButton = {
|
||||||
|
if (!isScanning && progress >= audioFiles.size) {
|
||||||
|
Button(onClick = onDismiss) { Text("关闭") }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dismissButton = {}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// 时间格式化辅助函数
|
// 时间格式化辅助函数
|
||||||
fun formatTimeOnly(date: Date): String {
|
fun formatTimeOnly(date: Date): String {
|
||||||
return SimpleDateFormat("HH:mm", Locale.getDefault()).format(date)
|
return SimpleDateFormat("HH:mm", Locale.getDefault()).format(date)
|
||||||
|
|||||||
@@ -1,17 +1,30 @@
|
|||||||
package com.example.initiateaphonecallapp.ui.calllog
|
package com.example.initiateaphonecallapp.ui.calllog
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateListOf
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.example.initiateaphonecallapp.data.model.AudioFile
|
||||||
import com.example.initiateaphonecallapp.data.model.CallRecord
|
import com.example.initiateaphonecallapp.data.model.CallRecord
|
||||||
|
import com.example.initiateaphonecallapp.data.model.CallRecordCheckRequest
|
||||||
import com.example.initiateaphonecallapp.data.model.CallRecordRequest
|
import com.example.initiateaphonecallapp.data.model.CallRecordRequest
|
||||||
import com.example.initiateaphonecallapp.data.repository.CallLogRepository
|
import com.example.initiateaphonecallapp.data.repository.CallLogRepository
|
||||||
|
import com.example.initiateaphonecallapp.enums.CallStatus
|
||||||
import com.example.initiateaphonecallapp.manager.AudioPlayManager
|
import com.example.initiateaphonecallapp.manager.AudioPlayManager
|
||||||
|
import com.example.initiateaphonecallapp.manager.CallRecordManager
|
||||||
import com.example.initiateaphonecallapp.utils.TimeRangeUtils
|
import com.example.initiateaphonecallapp.utils.TimeRangeUtils
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.time.LocalDateTime
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
class CallLogViewModel(
|
class CallLogViewModel(
|
||||||
private val callLogRepository: CallLogRepository = CallLogRepository()
|
private val callLogRepository: CallLogRepository = CallLogRepository()
|
||||||
@@ -36,6 +49,16 @@ class CallLogViewModel(
|
|||||||
private val _playbackError = MutableStateFlow<String?>(null)
|
private val _playbackError = MutableStateFlow<String?>(null)
|
||||||
val playbackError: StateFlow<String?> = _playbackError.asStateFlow()
|
val playbackError: StateFlow<String?> = _playbackError.asStateFlow()
|
||||||
|
|
||||||
|
|
||||||
|
private val _audioFiles = mutableStateListOf<AudioFile>()
|
||||||
|
val audioFiles: List<AudioFile> get() = _audioFiles
|
||||||
|
|
||||||
|
var progress by mutableStateOf(0)
|
||||||
|
private set
|
||||||
|
|
||||||
|
var isScanning by mutableStateOf(false)
|
||||||
|
private set
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 播放音频
|
* 播放音频
|
||||||
*/
|
*/
|
||||||
@@ -127,6 +150,93 @@ class CallLogViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 扫描并处理音频文件
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
fun scanAndProcessAudio(context: Context) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
isScanning = true
|
||||||
|
_audioFiles.clear()
|
||||||
|
progress = 0
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 1️⃣ 扫描
|
||||||
|
val files = suspendCancellableCoroutine { cont ->
|
||||||
|
CallRecordManager.scanAudioFiles(context) { scanned ->
|
||||||
|
cont.resume(scanned) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.d("ScanAudio", "扫描到 ${files.size} 个文件")
|
||||||
|
|
||||||
|
// 2️⃣ 验证录音文件
|
||||||
|
val fileNames = files.map { it.displayName }
|
||||||
|
val request = CallRecordCheckRequest(data = fileNames)
|
||||||
|
val checkResult = callLogRepository.checkCallLogs(request)
|
||||||
|
val needUploadNames = checkResult.getOrNull() ?: emptyList()
|
||||||
|
Log.d("ScanAudio", "需要上传的文件名列表: $needUploadNames")
|
||||||
|
|
||||||
|
// 3️⃣ 过滤扫描结果,只保留需要上传且能提取手机号的文件
|
||||||
|
val uploadFiles = files.filter { file ->
|
||||||
|
val needUpload = file.displayName in needUploadNames
|
||||||
|
val phoneNumber = extractPhoneNumber(file.displayName)
|
||||||
|
val hasPhone = phoneNumber != null
|
||||||
|
|
||||||
|
if (!needUpload) {
|
||||||
|
Log.d("ScanAudio", "文件 ${file.displayName} 不在上传列表,跳过")
|
||||||
|
} else if (!hasPhone) {
|
||||||
|
Log.d("ScanAudio", "文件 ${file.displayName} 没有手机号,跳过")
|
||||||
|
} else {
|
||||||
|
Log.d("ScanAudio", "文件 ${file.displayName} 准备上传, 手机号=$phoneNumber")
|
||||||
|
}
|
||||||
|
|
||||||
|
needUpload && hasPhone
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4️⃣ 加入 _audioFiles
|
||||||
|
_audioFiles.addAll(uploadFiles)
|
||||||
|
Log.d("ScanAudio", "最终准备上传的文件数量: ${_audioFiles.size}")
|
||||||
|
|
||||||
|
// 5️⃣ 上传
|
||||||
|
_audioFiles.forEachIndexed { index, file ->
|
||||||
|
pushFile(file)
|
||||||
|
progress = index + 1
|
||||||
|
Log.d("ScanAudio", "上传进度: $progress / ${_audioFiles.size}")
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e("ScanAudio", "扫描或验证异常: ${e.message}", e)
|
||||||
|
} finally {
|
||||||
|
isScanning = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 上传单个文件
|
||||||
|
fun pushFile(file: AudioFile) {
|
||||||
|
val phoneNumber = extractPhoneNumber(file.displayName) ?: run {
|
||||||
|
Log.d("ScanAudio", "文件 ${file.displayName} 没有手机号,跳过上传")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val callRecord = CallRecord(
|
||||||
|
phoneNumber = phoneNumber,
|
||||||
|
startTime = Date(file.dateAdded - file.duration),
|
||||||
|
endTime = Date(file.dateAdded),
|
||||||
|
duration = file.duration / 1000,
|
||||||
|
status = CallStatus.COMPLETED,
|
||||||
|
audioFileName = file.displayName,
|
||||||
|
audioFileUri = file.filePath
|
||||||
|
)
|
||||||
|
|
||||||
|
CallRecordManager.uploadCallRecord(callRecord)
|
||||||
|
Log.d("ScanAudio", "上传文件 ${file.displayName} 成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 正则提取手机号
|
||||||
|
fun extractPhoneNumber(fileName: String): String? {
|
||||||
|
val regex = Regex("""1[3-9]\d{9}""")
|
||||||
|
return regex.find(fileName)?.value
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 刷新数据(使用相同的请求参数)
|
* 刷新数据(使用相同的请求参数)
|
||||||
*/
|
*/
|
||||||
@@ -140,8 +250,4 @@ class CallLogViewModel(
|
|||||||
fun clearError() {
|
fun clearError() {
|
||||||
_errorMessage.value = null
|
_errorMessage.value = null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun scanAllAudio() {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.example.initiateaphonecallapp.ui.login
|
package com.example.initiateaphonecallapp.ui.login
|
||||||
|
|
||||||
data class LoginState(
|
data class LoginState(
|
||||||
val username: String = "",
|
val username: String = "sadmin",
|
||||||
val password: String = "",
|
val password: String = "admin123",
|
||||||
val isLoading: Boolean = false,
|
val isLoading: Boolean = false,
|
||||||
val errorMessage: String = "",
|
val errorMessage: String = "",
|
||||||
val isLoginSuccess: Boolean = false,
|
val isLoginSuccess: Boolean = false,
|
||||||
|
|||||||
Reference in New Issue
Block a user