feat: complete DataViewModel with DataRepository integration and export/delete functionality
Build APK / build (push) Failing after 16m57s

This commit is contained in:
茂之钳
2026-05-25 07:08:54 +00:00
parent 6154104f1a
commit d738609f68
2 changed files with 132 additions and 11 deletions
@@ -7,8 +7,10 @@ import android.view.ViewGroup
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.senstools.databinding.FragmentDataBinding import com.senstools.databinding.FragmentDataBinding
import com.senstools.presentation.adapter.DataFileAdapter import com.senstools.presentation.adapter.DataFileAdapter
import com.senstools.presentation.viewmodel.DataFile
import com.senstools.presentation.viewmodel.DataViewModel import com.senstools.presentation.viewmodel.DataViewModel
class DataFragment : Fragment() { class DataFragment : Fragment() {
@@ -38,8 +40,8 @@ class DataFragment : Fragment() {
private fun setupRecyclerView() { private fun setupRecyclerView() {
adapter = DataFileAdapter( adapter = DataFileAdapter(
onItemClick = { file -> viewModel.openFile(file) }, onItemClick = { file -> viewModel.openFile(file) },
onExportClick = { file -> viewModel.exportFile(file) }, onExportClick = { file -> showExportDialog(file) },
onDeleteClick = { file -> viewModel.deleteFile(file) } onDeleteClick = { file -> showDeleteConfirmDialog(file) }
) )
binding.recyclerView.layoutManager = LinearLayoutManager(requireContext()) binding.recyclerView.layoutManager = LinearLayoutManager(requireContext())
binding.recyclerView.adapter = adapter binding.recyclerView.adapter = adapter
@@ -49,6 +51,17 @@ class DataFragment : Fragment() {
viewModel.dataFiles.observe(viewLifecycleOwner) { files -> viewModel.dataFiles.observe(viewLifecycleOwner) { files ->
adapter.submitList(files) adapter.submitList(files)
} }
viewModel.isExporting.observe(viewLifecycleOwner) { exporting ->
binding.swipeRefresh.isEnabled = !exporting
}
viewModel.exportResult.observe(viewLifecycleOwner) { result ->
result?.let {
showToast(it)
viewModel.clearExportResult()
}
}
} }
private fun setupListeners() { private fun setupListeners() {
@@ -58,6 +71,34 @@ class DataFragment : Fragment() {
} }
} }
private fun showExportDialog(file: DataFile) {
val options = arrayOf("Export to CSV", "Export to JSON")
MaterialAlertDialogBuilder(requireContext())
.setTitle("Export: " + file.name)
.setItems(options) { _, which ->
when (which) {
0 -> viewModel.exportToCSV(file)
1 -> viewModel.exportToJSON(file)
}
}
.show()
}
private fun showDeleteConfirmDialog(file: DataFile) {
MaterialAlertDialogBuilder(requireContext())
.setTitle("Delete File")
.setMessage("Delete " + file.name + "?")
.setPositiveButton("Delete") { _, _ ->
viewModel.deleteFile(file)
}
.setNegativeButton("Cancel", null)
.show()
}
private fun showToast(message: String) {
android.widget.Toast.makeText(requireContext(), message, android.widget.Toast.LENGTH_SHORT).show()
}
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
_binding = null _binding = null
@@ -1,37 +1,117 @@
package com.senstools.presentation.viewmodel package com.senstools.presentation.viewmodel
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope
import com.senstools.domain.repository.DataRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
class DataViewModel : ViewModel() { class DataViewModel(application: Application) : AndroidViewModel(application) {
private val _dataFiles = MutableLiveData<List<DataFile>>() private val _dataFiles = MutableLiveData<List<DataFile>>()
val dataFiles: LiveData<List<DataFile>> = _dataFiles val dataFiles: LiveData<List<DataFile>> = _dataFiles
private val _isExporting = MutableLiveData(false)
val isExporting: LiveData<Boolean> = _isExporting
private val _exportResult = MutableLiveData<String?>()
val exportResult: LiveData<String?> = _exportResult
private val dataRepository: DataRepository
init { init {
dataRepository = DataRepository(application.filesDir)
loadFiles() loadFiles()
} }
private fun loadFiles() { private fun loadFiles() {
// Load files from storage val files = dataRepository.listDataFiles().map { info ->
_dataFiles.value = emptyList() DataFile(
name = info.name,
path = info.path,
size = info.size,
date = info.lastModified
)
}
_dataFiles.value = files
} }
fun refreshFiles() { fun refreshFiles() {
loadFiles() loadFiles()
} }
fun openFile(file: DataFile) { fun openFile(file: DataFile) { // placeholder
// Open file for viewing
} }
fun exportFile(file: DataFile) { fun exportToCSV(file: DataFile) {
// Export file to CSV/JSON viewModelScope.launch {
_isExporting.value = true
val result = withContext(Dispatchers.IO) {
val exportDir = File(
getApplication<Application>().filesDir,
"senstools_export"
)
exportDir.mkdirs()
val csvPath = File(exportDir, file.name.replace(".bin", ".csv")).absolutePath
val success = dataRepository.exportToCSV(file.path, csvPath)
success to csvPath
}
_exportResult.value = if (result.first) {
"CSV exported to: " + result.second
} else {
"CSV export failed"
}
_isExporting.value = false
}
}
fun exportToJSON(file: DataFile) {
viewModelScope.launch {
_isExporting.value = true
val result = withContext(Dispatchers.IO) {
val exportDir = File(
getApplication<Application>().filesDir,
"senstools_export"
)
exportDir.mkdirs()
val jsonPath = File(exportDir, file.name.replace(".bin", ".json")).absolutePath
val success = dataRepository.exportToJSON(file.path, jsonPath)
success to jsonPath
}
_exportResult.value = if (result.first) {
"JSON exported to: " + result.second
} else {
"JSON export failed"
}
_isExporting.value = false
}
} }
fun deleteFile(file: DataFile) { fun deleteFile(file: DataFile) {
// Delete file viewModelScope.launch {
withContext(Dispatchers.IO) {
dataRepository.deleteFile(file.name)
}
loadFiles()
}
}
fun deleteAll() {
viewModelScope.launch {
withContext(Dispatchers.IO) {
dataRepository.deleteAll()
}
loadFiles()
}
}
fun clearExportResult() {
_exportResult.value = null
} }
} }