优化 app 架构

This commit is contained in:
2025-02-14 01:28:37 +08:00
parent 68d6ca0285
commit fb947accd9
34 changed files with 1894 additions and 1435 deletions

View File

@@ -1,10 +1,12 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" /> <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<application <application
android:name=".App"
android:allowBackup="true" android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules" android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules" android:fullBackupContent="@xml/backup_rules"

View File

@@ -0,0 +1,7 @@
package com.zywl.test1229
import android.app.Application
import dagger.hilt.android.HiltAndroidApp
@HiltAndroidApp
class App : Application()

View File

@@ -1,210 +1,43 @@
package com.zywl.test1229 package com.zywl.test1229
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Intent
import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Environment
import android.provider.Settings
import android.util.Log
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import androidx.annotation.RequiresApi
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material3.Surface
import androidx.compose.foundation.layout.height import androidx.compose.runtime.collectAsState
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.lifecycle.ViewModelProvider
import androidx.compose.ui.unit.dp import com.zywl.test1229.ui.SharedNavHost
import androidx.lifecycle.Lifecycle import com.zywl.test1229.ui.common.PermissionDialog
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.google.gson.Gson
import com.zywl.test1229.bean.Constant
import com.zywl.test1229.bean.PointInfo
import com.zywl.test1229.bean.StakeInfo
import com.zywl.test1229.data.SimpleViewModel
import com.zywl.test1229.ktx.toast
import com.zywl.test1229.ui.theme.Test1229Theme import com.zywl.test1229.ui.theme.Test1229Theme
import com.zywl.test1229.utils.ExcelUtils import dagger.hilt.android.AndroidEntryPoint
import com.zywl.test1229.utils.Tools
import com.zywl.test1229.view.FilesScreen
import com.zywl.test1229.view.FloatingButtonS
import com.zywl.test1229.view.PermissionDialog
import com.zywl.test1229.view.StakeInfoViewPager
import com.zywl.test1229.view.TopBar
import com.zywl.test1229.view.mainPager
@AndroidEntryPoint
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
var lastBackPressedTime: Long = 0 private val viewModel by lazy {
val backPressInterval: Long = 2000 ViewModelProvider(this)[MainViewModel::class]
@RequiresApi(Build.VERSION_CODES.R) }
@SuppressLint("SourceLockedOrientationActivity") @SuppressLint("SourceLockedOrientationActivity")
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
enableEdgeToEdge() enableEdgeToEdge()
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
setContent { setContent {
MyApp() Test1229Theme {
Surface(modifier = Modifier.fillMaxSize()) {
SharedNavHost()
} }
} }
val outerItems:MutableList<StakeInfo> = mutableListOf( val state by viewModel.state.collectAsState()
StakeInfo("awdawd","awdawd","awdawda",1231.0,1231.0,0.0,"awdawd","awdawd","awdawd","","awdawd","awdawda","awda"),
StakeInfo("awdawd","awdawd","awdawda",1231.0,1231.0,0.0,"awdawd","awdawd","awdawd","","awdawd","awdawda","awda"),
StakeInfo("awdawd","awdawd","awdawda",1231.0,1231.0,0.0,"awdawd","awdawd","awdawd","","awdawd","awdawda","awda"),
StakeInfo("awdawd","awdawd","awdawda",1231.0,1231.0,0.0,"awdawd","awdawd","awdawd","","awdawd","awdawda","awda"),
StakeInfo("awdawd","awdawd","awdawda",1231.0,1231.0,0.0,"awdawd","awdawd","awdawd","","awdawd","awdawda","awda"),)
var isFirst=true
@RequiresApi(Build.VERSION_CODES.R)
@Composable
fun MyApp(){
val navController = rememberNavController()
// val viewModel:SimpleViewModel<List<StakeInfo>> by lazy { SimpleViewModel() }
val viewModel:SimpleViewModel<List<StakeInfo>> = viewModel()
// viewModel.setData(outerItems)
// viewModel.setData(mutableListOf())
NavHost(navController = navController, startDestination = "home") {
composable("home") {
HomePager(navController,viewModel)
}
composable("info") {
StakeInfoViewPager().MainView(navController,viewModel)
}
composable("info/{data}") { backStackEntry ->
val json = backStackEntry.arguments?.getString("data")
val stakeInfo=Gson().fromJson(json,StakeInfo::class.java)
StakeInfoViewPager().MainView(navController,viewModel=viewModel,stakeInfo)
}
composable("files") {
FilesScreen(navController,viewModel)
}
}
}
@RequiresApi(Build.VERSION_CODES.R)
@Composable
fun HomePager(navController: NavController,viewModel: SimpleViewModel<List<StakeInfo>>){
Test1229Theme() {
var isLoading by remember { mutableStateOf(true) }
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current
val (isPermissionGranted, onPermissionChange) = remember { mutableStateOf(Environment.isExternalStorageManager()) }
val permissionDialog = remember { mutableStateOf(false) }
DisposableEffect(Unit) {
val observer = object : LifecycleEventObserver {
@RequiresApi(Build.VERSION_CODES.R)
override fun onStateChanged(
source: LifecycleOwner,
event: Lifecycle.Event
) {
Log.d("MainActivity", "onStateChanged: $event")
when (event) {
Lifecycle.Event.ON_RESUME -> {
onPermissionChange(Environment.isExternalStorageManager())
}
else -> Unit
}
}
}
lifecycleOwner.lifecycle.addObserver(observer)
onDispose {
lifecycleOwner.lifecycle.removeObserver(observer)
}
}
LaunchedEffect(isPermissionGranted) {
if (isPermissionGranted&&!isFirst) {
context.toast("权限已授权")
}
}
if(isPermissionGranted){
permissionDialog.value=false
LaunchedEffect(Unit) {
val dataTmp=viewModel.stateFlow.value.data
if (dataTmp==null){
Log.d("MainActivity","LaunchedEffect $isLoading $dataTmp")
val directory=Constant.SDCARD+"/"+Constant.projectName+"/backup"
val data = ExcelUtils().parseExcel("$directory/main.xls")
viewModel.setData(data)
}
isLoading = false
}
if (isLoading){
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally, // 水平居中
verticalArrangement = Arrangement.Center // 垂直居中
){
CircularProgressIndicator(
modifier = Modifier.width(64.dp),
color = MaterialTheme.colorScheme.secondary,
trackColor = MaterialTheme.colorScheme.surfaceVariant,
)
Spacer(Modifier.fillMaxWidth().height(26.dp))
Text(
text = "数据加载中....",
)
}
}else{
Scaffold(
modifier = Modifier.fillMaxSize(),
topBar = {
if (context is MainActivity) {
// 当前是 MainActivity可以访问 MainActivity 的成员
val activity: MainActivity = context
// 做你需要的操作
TopBar(activity)
}
},
floatingActionButton = {
FloatingButtonS(navController,viewModel)
}
) { innerPadding ->
mainPager(navController,viewModel,Modifier.padding(innerPadding))
}
}
}else{
permissionDialog.value=true
}
PermissionDialog( PermissionDialog(
visible = permissionDialog.value, visible = state.permissionDialogVisible,
onConfirm = { onPermissionChange = viewModel::onPermissionChange
val intent = Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)
isFirst=false
context.startActivity(intent)
},
onDismissRequest = {
context.toast("权限取消授权")
finish()
}
) )
} }
} }

View File

@@ -0,0 +1,42 @@
package com.zywl.test1229
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.zywl.test1229.data.PermissionState
import com.zywl.test1229.di.PermissionStateFlow
import com.zywl.test1229.domain.CheckPermissionUseCase
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.update
import javax.inject.Inject
@HiltViewModel
class MainViewModel @Inject constructor(
@PermissionStateFlow
private val permissionState: MutableStateFlow<PermissionState>,
private val checkPermissionUseCase: CheckPermissionUseCase
) : ViewModel() {
private val _state = MutableStateFlow(MainViewState())
val state = _state.asStateFlow()
init {
permissionState.onEach {
when (it) {
PermissionState.None -> checkPermissionUseCase()
PermissionState.Granted -> _state.update { it.copy(permissionDialogVisible = false) }
PermissionState.Denied -> _state.update { it.copy(permissionDialogVisible = true) }
}
}.launchIn(viewModelScope)
}
fun onPermissionChange(value: Boolean) {
checkPermissionUseCase()
}
}
data class MainViewState(
val permissionDialogVisible: Boolean = false
)

View File

@@ -2,13 +2,11 @@ package com.zywl.test1229.bean
import android.os.Environment import android.os.Environment
class Constant { object Constant {
companion object{
val stakeTypeArray = listOf("里程桩","测试桩","转角桩","警示桩") val stakeTypeArray = listOf("里程桩","测试桩","转角桩","警示桩")
val depthArray = listOf("超长无法探测") val depthArray = listOf("超长无法探测")
val BuriedTechnologyArray = listOf("定向钻穿河","定向钻穿河路","直管平铺","平铺弯头") val BuriedTechnologyArray = listOf("定向钻穿河","定向钻穿河路","直管平铺","平铺弯头")
val terrainArray = listOf("铺装路面","绿化带","山坡","荒地") val terrainArray = listOf("铺装路面","绿化带","山坡","荒地")
var SDCARD: String = Environment.getExternalStorageDirectory().absolutePath var SDCARD: String = Environment.getExternalStorageDirectory().absolutePath
var projectName="Test1229" var projectName="Test1229"
}
} }

View File

@@ -1,21 +1,41 @@
package com.zywl.test1229.bean package com.zywl.test1229.bean
import android.os.Parcelable import android.os.Parcelable
import kotlinx.android.parcel.Parcelize import kotlinx.parcelize.Parcelize
import kotlinx.serialization.Serializable
@Serializable
@Parcelize @Parcelize
data class StakeInfo( data class StakeInfo(
var tempNo:String, val tempNo: String,
var pipeLine:String, val pipeLine: String,
var stakeType:String, val stakeType: String,
var latitude:Double, val latitude: Double,
var longitude:Double, val longitude: Double,
var z:Double, val z: Double,
var pipeDepth:String, val pipeDepth: String,
var mileage:String, val mileage: String,
var buryTech:String, val buryTech: String,
var isInPoint:String, val isInPoint: String,
var terrain:String, val terrain: String,
var imageName:String, val imageName: String,
var collectDate:String, val collectDate: String,
):Parcelable ) : Parcelable {
companion object {
val Empty = StakeInfo(
"",
"",
"",
0.0,
0.0,
0.0,
"",
"",
"",
"",
"",
"",
""
)
}
}

View File

@@ -0,0 +1,5 @@
package com.zywl.test1229.data
enum class PermissionState {
None, Granted, Denied
}

View File

@@ -0,0 +1,25 @@
package com.zywl.test1229.di
import com.zywl.test1229.data.PermissionState
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import kotlinx.coroutines.flow.MutableStateFlow
import javax.inject.Qualifier
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
object SharedModule {
@Provides
@PermissionStateFlow
@Singleton
fun providePermissionState(): MutableStateFlow<PermissionState> {
return MutableStateFlow(PermissionState.None)
}
}
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class PermissionStateFlow

View File

@@ -0,0 +1,23 @@
package com.zywl.test1229.domain
import android.os.Build
import android.os.Environment
import com.zywl.test1229.data.PermissionState
import com.zywl.test1229.di.PermissionStateFlow
import kotlinx.coroutines.flow.MutableStateFlow
import javax.inject.Inject
class CheckPermissionUseCase @Inject constructor(
@PermissionStateFlow
private val permissionState: MutableStateFlow<PermissionState>
) {
operator fun invoke(): Boolean {
val granted = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
Environment.isExternalStorageManager()
} else {
TODO()
}
permissionState.value = if (granted) PermissionState.Granted else PermissionState.Denied
return granted
}
}

View File

@@ -0,0 +1,3 @@
package com.zywl.test1229.ktx
val Any.TAG: String get() = this::class.java.simpleName

View File

@@ -0,0 +1,24 @@
package com.zywl.test1229.ui
import androidx.compose.runtime.Composable
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.rememberNavController
import com.zywl.test1229.ui.files.files
import com.zywl.test1229.ui.home.HomeRoute
import com.zywl.test1229.ui.home.home
import com.zywl.test1229.ui.info.info
@Composable
fun SharedNavHost(
startDestination: Any = HomeRoute
) {
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = startDestination
) {
home(navController)
info(navController)
files(navController)
}
}

View File

@@ -0,0 +1,129 @@
package com.zywl.test1229.ui.common
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun EditableExposedDropdownMenuSample(
options: List<String>,
label: String,
content: String,
onPipeLineChanged: (String) -> Unit, modifier: Modifier = Modifier
) {
var expanded by remember { mutableStateOf(false) }
ExposedDropdownMenuBox(
//是否列出列表
expanded = expanded,
onExpandedChange = {
expanded = !expanded
},
) {
TextField(
value = content,
onValueChange = {
onPipeLineChanged(it)
},
label = { Text(label) },
trailingIcon = {
ExposedDropdownMenuDefaults.TrailingIcon(
expanded = expanded
)
},
colors = TextFieldDefaults.colors(
focusedContainerColor = Color.Transparent,
unfocusedContainerColor = Color.Transparent
),
modifier = modifier.menuAnchor()
)
val filteringOptions =
options.filter { it.contains(content, ignoreCase = true) }
if (filteringOptions.isNotEmpty()) {
ExposedDropdownMenu(
expanded = expanded,
onDismissRequest = {
expanded = false
}
) {
filteringOptions.forEach { selectionOption ->
DropdownMenuItem(
text = {
Text(text = selectionOption)
},
onClick = {
onPipeLineChanged(selectionOption)
expanded = false
}
)
}
}
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ExposedDropdownMenuSample(
label: String,
content: String,
onPipeLineChanged: (String) -> Unit, modifier: Modifier = Modifier
) {
val options = listOf("", "")
var expanded by remember { mutableStateOf(false) }
ExposedDropdownMenuBox(
expanded = expanded,
onExpandedChange = {
expanded = !expanded
}
) {
TextField(
readOnly = true,
value = content,
onValueChange = { },
label = { Text(label) },
trailingIcon = {
ExposedDropdownMenuDefaults.TrailingIcon(
//这里使用了 ExposedDropdownMenuDefaults.TrailingIcon 组件作为右侧图标。
//这个图标会根据 expanded 的状态变化,通常用于表示下拉菜单的打开或关闭状态
expanded = expanded
)
},
colors = TextFieldDefaults.colors(
focusedContainerColor = Color.Transparent,
unfocusedContainerColor = Color.Transparent
),
modifier = modifier.menuAnchor()
)
ExposedDropdownMenu(
expanded = expanded,
onDismissRequest = {
expanded = false
},
) {
options.forEach { selectionOption ->
DropdownMenuItem(
text = {
Text(selectionOption)
},
onClick = {
onPipeLineChanged(selectionOption)
expanded = false
}
)
}
}
}
}

View File

@@ -0,0 +1,79 @@
package com.zywl.test1229.ui.common
import android.util.Log
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.material3.DatePicker
import androidx.compose.material3.DatePickerDialog
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.rememberDatePickerState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun EditableTime(
label: String,
date: String,
onPipeLineChanged: (String) -> Unit, modifier: Modifier = Modifier
) {
var content = date
if (content.isEmpty()) {
content = "**-**-**"
}
Row(modifier = modifier, horizontalArrangement = Arrangement.SpaceBetween) {
var showTimePicker by remember { mutableStateOf(false) }
Text(text = label)
Text(text = content,
style = TextStyle(
fontSize = 14.sp,
fontWeight = FontWeight.Bold
),
modifier = Modifier.clickable {
showTimePicker = true
}
)
val datePickerState = rememberDatePickerState()
if (showTimePicker) {
DatePickerDialog(
onDismissRequest = { showTimePicker = false; },
confirmButton = {
TextButton(onClick = {
val formattedDate = datePickerState.selectedDateMillis?.let {
val date = Date(it)
val format =
SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) // 设置日期格式
format.format(date)
} ?: content
onPipeLineChanged(formattedDate)
Log.d("DatePickerDialog", formattedDate)
showTimePicker = false;
}) {
Text("OK")
}
},
dismissButton = {
TextButton(onClick = { showTimePicker = false; }) {
Text("Cancel")
}
}
) {
DatePicker(state = datePickerState)
}
}
}
}

View File

@@ -0,0 +1,83 @@
package com.zywl.test1229.ui.common
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.slideInVertically
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.FloatingActionButtonDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@Composable
fun FloatingActionButton(
onImport: () -> Unit,
onExport: () -> Unit,
onCreate: () -> Unit,
modifier: Modifier = Modifier
) {
var isShow by remember { mutableStateOf(false) }
Column(
modifier = modifier.padding(end = 16.dp, bottom = 8.dp)
) {
AnimatedVisibility(
visible = isShow,
enter = fadeIn() + slideInVertically(initialOffsetY = { it }) // Animation for appearing
) {
Column(
verticalArrangement = Arrangement.spacedBy(8.dp),
modifier = Modifier.padding(bottom = 8.dp)
) {
FloatingActionButton(
elevation = FloatingActionButtonDefaults.elevation(0.dp),
shape = CircleShape,
onClick = onImport,
modifier = Modifier.size(66.dp),
) {
Text("导入", color = Color.White)
}
FloatingActionButton(
elevation = FloatingActionButtonDefaults.elevation(0.dp),
shape = CircleShape,
onClick = onExport,
modifier = Modifier.size(66.dp),
) {
Text("导出", color = Color.White)
}
FloatingActionButton(
elevation = FloatingActionButtonDefaults.elevation(0.dp),
shape = CircleShape,
onClick = onCreate,
modifier = Modifier.size(66.dp),
) {
Text("新增", color = Color.White)
}
}
}
FloatingActionButton(
elevation = FloatingActionButtonDefaults.elevation(0.dp),
shape = CircleShape,
onClick = {
isShow = !isShow
},
modifier = Modifier.size(66.dp),
) {
var str = if (isShow) "-" else "+"
Text(str, color = Color.White, style = TextStyle(fontSize = 26.sp))
}
}
}

View File

@@ -0,0 +1,92 @@
package com.zywl.test1229.ui.common
import android.app.Activity
import android.content.Intent
import android.os.Build
import android.os.Environment
import android.provider.Settings
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.compose.LocalLifecycleOwner
import com.zywl.test1229.ktx.toast
@Composable
fun PermissionDialog(
visible: Boolean,
onPermissionChange: (Boolean) -> Unit
) {
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current
DisposableEffect(Unit) {
val observer = object : LifecycleEventObserver {
@RequiresApi(Build.VERSION_CODES.R)
override fun onStateChanged(
source: LifecycleOwner,
event: Lifecycle.Event
) {
Log.d("MainActivity", "onStateChanged: $event")
when (event) {
Lifecycle.Event.ON_RESUME -> {
onPermissionChange(Environment.isExternalStorageManager())
}
else -> Unit
}
}
}
lifecycleOwner.lifecycle.addObserver(observer)
onDispose {
lifecycleOwner.lifecycle.removeObserver(observer)
}
}
PermissionDialog(
visible = visible,
onConfirm = {
val intent = Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)
context.startActivity(intent)
},
onDismissRequest = {
context.toast("权限取消授权")
(context as? Activity)?.finish()
}
)
}
@Composable
fun PermissionDialog(
visible: Boolean,
onConfirm: () -> Unit,
onDismissRequest: () -> Unit,
) {
if (visible) AlertDialog(
title = {
Text(text = "管理所有文件")
}, text = {
Text(text = "授予app管理存储设备上的所有文件的权限")
},
confirmButton = {
TextButton(
onClick = {
onConfirm()
}
) {
Text(text = "确定")
}
}, dismissButton = {
TextButton(
onClick = onDismissRequest
) {
Text(text = "取消")
}
}, onDismissRequest = onDismissRequest
)
}

View File

@@ -0,0 +1,19 @@
package com.zywl.test1229.ui.common
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.zywl.test1229.ui.theme.Test1229Theme
@Composable
fun PreviewSurface(
modifier: Modifier = Modifier,
content: @Composable () -> Unit
) {
Test1229Theme {
Surface(
modifier = modifier,
content = content
)
}
}

View File

@@ -0,0 +1,9 @@
package com.zywl.test1229.ui.common
import android.content.res.Configuration.UI_MODE_NIGHT_NO
import android.content.res.Configuration.UI_MODE_NIGHT_YES
import androidx.compose.ui.tooling.preview.Preview
@Preview(uiMode = UI_MODE_NIGHT_YES)
@Preview(uiMode = UI_MODE_NIGHT_NO)
annotation class Previews

View File

@@ -0,0 +1,34 @@
package com.zywl.test1229.ui.common
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.width
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun ProgressDialog(visible: Boolean) {
if (visible) AlertDialog(
onDismissRequest = { },
title = {
Text(text = "正在处理...")
},
text = {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
CircularProgressIndicator(
modifier = Modifier.width(64.dp),
color = MaterialTheme.colorScheme.secondary,
trackColor = MaterialTheme.colorScheme.surfaceVariant,
)
}
},
confirmButton = {
}
)
}

View File

@@ -0,0 +1,144 @@
package com.zywl.test1229.ui.common
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Button
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.zywl.test1229.bean.Constant
import com.zywl.test1229.bean.StakeInfo
@Composable
fun StakeInfoView(
isShow: Boolean,
stakeInfo: StakeInfo,
onPipeLineChanged: (StakeInfo) -> Unit,
onDeleteItem: () -> Unit
) {
if (!isShow) {
return
}
Surface(
shape = RoundedCornerShape(8.dp),
shadowElevation = 10.dp,
) {
Column {
EditableTextField(
"管线",
stakeInfo.pipeLine,
modifier = Modifier.fillMaxWidth(),
onPipeLineChanged = {
onPipeLineChanged(stakeInfo.copy(pipeLine = it))
}
)
EditableExposedDropdownMenuSample(
Constant.stakeTypeArray,
"桩类型",
stakeInfo.stakeType,
modifier = Modifier.fillMaxWidth(),
onPipeLineChanged = {
onPipeLineChanged(stakeInfo.copy(stakeType = it))
}
)
EditableExposedDropdownMenuSample(
Constant.depthArray,
"管中埋深(米)",
stakeInfo.pipeDepth,
modifier = Modifier.fillMaxWidth(),
onPipeLineChanged = {
onPipeLineChanged(stakeInfo.copy(pipeDepth = it))
}
)
EditableTextField(
"里程",
stakeInfo.mileage,
modifier = Modifier.fillMaxWidth(),
onPipeLineChanged = {
onPipeLineChanged(stakeInfo.copy(mileage = it))
}
)
EditableExposedDropdownMenuSample(
Constant.BuriedTechnologyArray,
"埋设工艺",
stakeInfo.buryTech,
modifier = Modifier.fillMaxWidth(),
onPipeLineChanged = {
onPipeLineChanged(stakeInfo.copy(buryTech = it))
}
)
ExposedDropdownMenuSample(
"是否出入土点",
stakeInfo.isInPoint,
modifier = Modifier.fillMaxWidth(),
onPipeLineChanged = {
onPipeLineChanged(stakeInfo.copy(isInPoint = it))
}
)
EditableExposedDropdownMenuSample(
Constant.terrainArray,
"地形",
stakeInfo.terrain,
modifier = Modifier.fillMaxWidth(),
onPipeLineChanged = {
onPipeLineChanged(stakeInfo.copy(terrain = it))
}
)
Row {
EditableTextFieldInt("经度", "${stakeInfo.latitude}", modifier = Modifier
.fillMaxWidth()
.weight(1f), onPipeLineChanged = {
onPipeLineChanged(stakeInfo.copy(latitude = it))
})
EditableTextFieldInt(
"维度",
"${stakeInfo.longitude}",
onPipeLineChanged = {
onPipeLineChanged(stakeInfo.copy(longitude = it))
},
modifier = Modifier
.fillMaxWidth()
.weight(1f),
)
}
EditableTextFieldInt(
"Z(85高程桩根部)",
"${stakeInfo.z}",
onPipeLineChanged = {
onPipeLineChanged(stakeInfo.copy(z = it))
}, modifier = Modifier
.fillMaxWidth()
)
EditableTime(
"采集时间",
stakeInfo.collectDate,
modifier = Modifier
.fillMaxWidth()
.padding(start = 6.dp, end = 6.dp, top = 18.dp, bottom = 12.dp),
onPipeLineChanged = {
onPipeLineChanged(stakeInfo.copy(collectDate = it))
}
)
Row(
modifier = Modifier.fillMaxSize(),
horizontalArrangement = Arrangement.Center
) {
Button(
onClick = {
onDeleteItem()
}
) {
Text(text = "删除")
}
}
}
}
}

View File

@@ -0,0 +1,65 @@
package com.zywl.test1229.ui.common
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
@Composable
fun EditableTextField(
label: String,
content: String,
onPipeLineChanged: (String) -> Unit, modifier: Modifier = Modifier
) {
TextField(
modifier = modifier,
value = content,
onValueChange = {
onPipeLineChanged(it)
},
singleLine = true,
label = {
Text(label)
},
colors = TextFieldDefaults.colors(
focusedContainerColor = Color.Transparent,
unfocusedContainerColor = Color.Transparent
)
)
}
@Composable
fun EditableTextFieldInt(
label: String,
content: String,
onPipeLineChanged: (Double) -> Unit,
modifier: Modifier = Modifier
) {
TextField(
modifier = modifier,
value = content,
onValueChange = {
val newValue = it.toDoubleOrNull() // 将输入的字符串转换为 Double
if (newValue != null) {
onPipeLineChanged(newValue) // 如果转换成功,调用 onPipeLineChanged
}
},
singleLine = true,
label = {
Text(label)
},
keyboardOptions = KeyboardOptions.Default.copy(
keyboardType = KeyboardType.Number, // 设置为数字键盘
imeAction = ImeAction.Done
),
colors = TextFieldDefaults.colors(
focusedContainerColor = Color.Transparent,
unfocusedContainerColor = Color.Transparent
)
)
}

View File

@@ -0,0 +1,28 @@
package com.zywl.test1229.ui.files
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavHostController
import androidx.navigation.compose.composable
import kotlinx.serialization.Serializable
fun NavGraphBuilder.files(navController: NavHostController) = composable<FilesRoute> {
val viewModel: FilesViewModel = hiltViewModel()
FilesScreen(
fileState = viewModel.fileState,
onFileSelected = {
navController.previousBackStackEntry?.savedStateHandle?.set(FileSavedStateKey, it)
navController.navigateUp()
},
onCancel = navController::navigateUp
)
}
fun NavHostController.navigateToFiles() {
navigate(FilesRoute)
}
const val FileSavedStateKey = "file"
@Serializable
data object FilesRoute

View File

@@ -1,4 +1,4 @@
package com.zywl.test1229.view package com.zywl.test1229.ui.files
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context import android.content.Context
@@ -6,13 +6,13 @@ import android.content.Intent
import android.os.Environment import android.os.Environment
import android.util.Log import android.util.Log
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
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.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.rounded.ArrowBack
import androidx.compose.material.icons.filled.Done import androidx.compose.material.icons.filled.Done
import androidx.compose.material.icons.rounded.ArrowBack import androidx.compose.material.icons.rounded.ArrowBack
import androidx.compose.material.icons.rounded.Clear import androidx.compose.material.icons.rounded.Clear
@@ -33,25 +33,22 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import androidx.navigation.NavController
import com.zywl.test1229.utils.ExcelUtils
import com.zywl.test1229.R import com.zywl.test1229.R
import com.zywl.test1229.bean.StakeInfo
import com.zywl.test1229.data.SimpleViewModel
import java.io.File import java.io.File
import java.nio.file.Files import java.nio.file.Files
@SuppressLint("UnrememberedGetBackStackEntry") @SuppressLint("UnrememberedGetBackStackEntry")
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun FilesScreen(navController:NavController,viewModel: SimpleViewModel<List<StakeInfo>>){ fun FilesScreen(
val context = LocalContext.current fileState: FileState,
val fileState = remember { FileState() } onFileSelected: (String) -> Unit,
val action = remember { mutableStateOf<FileAction>(FileAction.None) } onCancel: () -> Unit
) {
val action = remember { mutableStateOf<FileAction>(FileAction.None(onBack = { onCancel() })) }
//设置copy或者select里的parentfile路径 //设置copy或者select里的parentfile路径
LaunchedEffect(fileState.current) { LaunchedEffect(fileState.current) {
@@ -63,18 +60,7 @@ fun FilesScreen(navController:NavController,viewModel: SimpleViewModel<List<Stak
} }
val listState = rememberLazyListState() val listState = rememberLazyListState()
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior() val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
var isLoading by remember { mutableStateOf(false) }
var filePath by remember { mutableStateOf<String?>(null) }
LaunchedEffect(filePath) {
filePath?.let {
isLoading = true
var excelUtils= ExcelUtils()
var excelData=excelUtils.parseExcel(filePath!!)
isLoading = false
viewModel.setData(excelData);
navController.popBackStack()
}
}
Scaffold( Scaffold(
topBar = { topBar = {
TopAppBar( TopAppBar(
@@ -118,8 +104,8 @@ fun FilesScreen(navController:NavController,viewModel: SimpleViewModel<List<Stak
// } // }
// } // }
// } // }
,modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection) , modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection)
){ innerPadding -> ) { innerPadding ->
LazyColumn( LazyColumn(
state = listState, state = listState,
contentPadding = innerPadding contentPadding = innerPadding
@@ -141,14 +127,14 @@ fun FilesScreen(navController:NavController,viewModel: SimpleViewModel<List<Stak
Text(text = item.name) Text(text = item.name)
}, leadingContent = { }, leadingContent = {
if (item.isDirectory) { if (item.isDirectory) {
Image( Icon(
painter = painterResource(R.mipmap.directory), painter = painterResource(R.mipmap.directory),
contentDescription = "Vector Image", contentDescription = "Vector Image",
modifier = Modifier.size(30.dp) // 控制图片的大小 modifier = Modifier.size(30.dp), // 控制图片的大小
) )
} }
if (item.isFile) { if (item.isFile) {
Image( Icon(
painter = painterResource(R.mipmap.file), painter = painterResource(R.mipmap.file),
contentDescription = "Vector Image", contentDescription = "Vector Image",
modifier = Modifier.size(30.dp) // 控制图片的大小 modifier = Modifier.size(30.dp) // 控制图片的大小
@@ -171,7 +157,8 @@ fun FilesScreen(navController:NavController,viewModel: SimpleViewModel<List<Stak
var fileActionCopy: FileAction.Select = FileAction.Select( var fileActionCopy: FileAction.Select = FileAction.Select(
source = item, source = item,
onPasteResult = { str -> onPasteResult = { str ->
filePath=str //filePath = str
onFileSelected(str)
//返回数据 //返回数据
// action.value = FileAction.None // action.value = FileAction.None
// navController.previousBackStackEntry?.savedStateHandle?.set("resultKey", str) // navController.previousBackStackEntry?.savedStateHandle?.set("resultKey", str)
@@ -186,7 +173,7 @@ fun FilesScreen(navController:NavController,viewModel: SimpleViewModel<List<Stak
// navController.popBackStack() // navController.popBackStack()
}, onCancel = { }, onCancel = {
action.value = FileAction.None action.value = FileAction.None(onBack = { onCancel() })
} }
) )
action.value = fileActionCopy action.value = fileActionCopy
@@ -196,8 +183,8 @@ fun FilesScreen(navController:NavController,viewModel: SimpleViewModel<List<Stak
} }
} }
} }
ProgressDialogView(isLoading)
} }
fun Context.openExternal(file: File) { fun Context.openExternal(file: File) {
if (file.isDirectory) return if (file.isDirectory) return
val contentType = Files.probeContentType(file.toPath()) val contentType = Files.probeContentType(file.toPath())
@@ -210,6 +197,7 @@ fun Context.openExternal(file: File) {
} }
startActivity(intent) startActivity(intent)
} }
class FileState { class FileState {
var items by mutableStateOf(emptyList<File>()) var items by mutableStateOf(emptyList<File>())
var root: String by mutableStateOf(Environment.getExternalStorageDirectory().path) var root: String by mutableStateOf(Environment.getExternalStorageDirectory().path)
@@ -233,7 +221,10 @@ class FileState {
// 先获取所有文件夹,再获取所有后缀为 .xls 的文件 // 先获取所有文件夹,再获取所有后缀为 .xls 的文件
when { when {
it.isDirectory -> listOf(it) // 如果是目录,添加到列表中 it.isDirectory -> listOf(it) // 如果是目录,添加到列表中
it.extension.equals("xls", ignoreCase = true) -> listOf(it) // 如果是 .xls 文件,添加到列表中 it.extension.equals(
"xls",
ignoreCase = true
) -> listOf(it) // 如果是 .xls 文件,添加到列表中
else -> emptyList() // 否则不做任何处理 else -> emptyList() // 否则不做任何处理
} }
} }
@@ -245,14 +236,16 @@ class FileState {
parent?.let { current = it } parent?.let { current = it }
} }
} }
sealed interface FileAction { sealed interface FileAction {
val topBarTitle: String val topBarTitle: String
val navigation: Pair<ImageVector, FileAction.() -> Unit>? val navigation: Pair<ImageVector, FileAction.() -> Unit>?
val actions: List<Pair<ImageVector, () -> Unit>> val actions: List<Pair<ImageVector, () -> Unit>>
data object None : FileAction { data class None(val onBack: FileAction.() -> Unit = {}) : FileAction {
override val topBarTitle: String = "文件选择" override val topBarTitle: String = "文件选择"
override val navigation: Pair<ImageVector, (FileAction) -> Unit>? = null override val navigation: Pair<ImageVector, (FileAction) -> Unit>? =
Icons.AutoMirrored.Rounded.ArrowBack to onBack
override val actions: List<Pair<ImageVector, () -> Unit>> = emptyList() override val actions: List<Pair<ImageVector, () -> Unit>> = emptyList()
} }
@@ -260,11 +253,12 @@ sealed interface FileAction {
val source: File, val source: File,
val onPasteResult: (String) -> Unit, val onPasteResult: (String) -> Unit,
val onCancel: FileAction.() -> Unit val onCancel: FileAction.() -> Unit
):FileAction{ ) : FileAction {
fun sure() { fun sure() {
Log.d("MainActivity","${source.path} ${source.name}") Log.d("MainActivity", "${source.path} ${source.name}")
onPasteResult(source.path); onPasteResult(source.path);
} }
override val topBarTitle: String = "已经选中 ${source.name} " override val topBarTitle: String = "已经选中 ${source.name} "
override val navigation: Pair<ImageVector, FileAction.() -> Unit>? = override val navigation: Pair<ImageVector, FileAction.() -> Unit>? =
Icons.Rounded.Clear to onCancel Icons.Rounded.Clear to onCancel

View File

@@ -0,0 +1,10 @@
package com.zywl.test1229.ui.files
import androidx.lifecycle.ViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
@HiltViewModel
class FilesViewModel @Inject constructor() : ViewModel() {
val fileState = FileState()
}

View File

@@ -0,0 +1,63 @@
package com.zywl.test1229.ui.home
import android.app.Activity
import android.util.Log
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableLongStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavHostController
import androidx.navigation.compose.composable
import com.zywl.test1229.bean.StakeInfo
import com.zywl.test1229.ktx.TAG
import com.zywl.test1229.ktx.toast
import com.zywl.test1229.ui.files.FileSavedStateKey
import com.zywl.test1229.ui.files.navigateToFiles
import com.zywl.test1229.ui.info.StakeInfoSavedStateKey
import com.zywl.test1229.ui.info.navigateToInfo
import kotlinx.serialization.Serializable
fun NavGraphBuilder.home(navController: NavHostController) = composable<HomeRoute> {
val file = it.savedStateHandle.get<String>(FileSavedStateKey)
val stakeInfo = it.savedStateHandle.get<StakeInfo>(StakeInfoSavedStateKey)
val context = LocalContext.current
val viewModel: HomeViewModel = hiltViewModel()
val state by viewModel.state.collectAsState()
var lastBackPressedTime: Long by remember { mutableLongStateOf(0) }
val backPressInterval: Long = 2000
val actions = remember(viewModel.actions) {
viewModel.actions.copy(
onFinishedActivity = {
val currentTime = System.currentTimeMillis()
if (currentTime - lastBackPressedTime < backPressInterval) {
(context as? Activity)?.finish()
} else {
context.toast("再按一次退出")
lastBackPressedTime = currentTime
}
}, navigateToInfo = {
navController.navigateToInfo(it ?: StakeInfo.Empty)
}, navigateToFiles = navController::navigateToFiles
)
}
LaunchedEffect(file) {
file?.let(actions.onFileSelected)
it.savedStateHandle[FileSavedStateKey] = null
}
LaunchedEffect(stakeInfo) {
stakeInfo?.let { actions.onPipeLineChanged(state.editingIndex, it) }
it.savedStateHandle[StakeInfoSavedStateKey] = null
}
HomeScreen(state = state, actions = actions)
}
@Serializable
data object HomeRoute

View File

@@ -0,0 +1,185 @@
package com.zywl.test1229.ui.home
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.VerticalDivider
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.zywl.test1229.R
import com.zywl.test1229.bean.StakeInfo
import com.zywl.test1229.ui.common.FloatingActionButton
import com.zywl.test1229.ui.common.PreviewSurface
import com.zywl.test1229.ui.common.Previews
import com.zywl.test1229.ui.common.ProgressDialog
import com.zywl.test1229.ui.common.StakeInfoView
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun HomeScreen(
state: HomeViewState,
actions: HomeActions
) {
val listState = rememberLazyListState()
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
Scaffold(
topBar = {
TopAppBar(
title = {
Text(text = "桩管理")
},
navigationIcon = {
IconButton(onClick = actions.onFinishedActivity) {
Icon(
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Back"
)
}
}, scrollBehavior = scrollBehavior
)
}, floatingActionButton = {
FloatingActionButton(
onImport = actions.navigateToFiles,
onExport = actions.onExport,
onCreate = {
actions.onEditingIndexChange(-1)
actions.navigateToInfo(null)
}
)
}, modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection)
) { innerPadding ->
Box(
modifier = Modifier.fillMaxSize()
) {
LazyColumn(
state = listState,
contentPadding = innerPadding,
verticalArrangement = Arrangement.spacedBy(8.dp),
modifier = Modifier.imePadding()
) {
itemsIndexed(state.items) { index, item ->
var expanded by remember { mutableStateOf(false) }
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
modifier = Modifier
.background(
color = MaterialTheme.colorScheme.surfaceContainerLow
)
.padding(8.dp)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.clickable {
actions.onEditingIndexChange(index)
actions.navigateToInfo(item)
},
) {
Text(
text = "${index + 1}",
style = TextStyle(
fontSize = 16.sp,
fontWeight = FontWeight.Bold,
), modifier = Modifier.padding(start = 6.dp)
)
Text(
text = "测绘临时编号:${item.tempNo}",
style = TextStyle(
fontSize = 14.sp,
fontWeight = FontWeight.Bold
), textAlign = TextAlign.Center,
modifier = Modifier.weight(1f)
)
IconButton(
onClick = {
expanded = !expanded
}
) {
Icon(
painter = painterResource((if (!expanded) R.mipmap.downdraw else R.mipmap.updraw)),
contentDescription = null,
modifier = Modifier.size(12.dp)
)
}
}
StakeInfoView(
isShow = expanded,
stakeInfo = item,
onPipeLineChanged = {
actions.onPipeLineChanged(index, it)
},
onDeleteItem = {
actions.onDeleteItem(index)
}
)
VerticalDivider()
}
}
item {
Spacer(modifier = Modifier.height(96.dp))
}
}
Button(
onClick = { /* Handle Click */ },
modifier = Modifier
.align(Alignment.BottomStart) // 设置它在Box中的右下角
.navigationBarsPadding()
) {
Text("设置点的线")
}
}
}
ProgressDialog(visible = state.exporting)
}
@Composable
@Previews
fun HomeScreenPreview() {
val state = HomeViewState(
items = List(10) { StakeInfo.Empty }
)
PreviewSurface {
HomeScreen(state = state, actions = HomeActions())
}
}

View File

@@ -0,0 +1,125 @@
package com.zywl.test1229.ui.home
import android.content.Context
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.zywl.test1229.bean.Constant
import com.zywl.test1229.bean.StakeInfo
import com.zywl.test1229.data.PermissionState
import com.zywl.test1229.di.PermissionStateFlow
import com.zywl.test1229.ktx.TAG
import com.zywl.test1229.ktx.toast
import com.zywl.test1229.utils.ExcelUtils
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
import javax.inject.Inject
@HiltViewModel
class HomeViewModel @Inject constructor(
@ApplicationContext
private val context: Context,
@PermissionStateFlow
private val permissionState: MutableStateFlow<PermissionState>
) : ViewModel() {
private val _state = MutableStateFlow(HomeViewState())
val state = _state.asStateFlow()
val actions = HomeActions(
onFileSelected = ::onFileSelected,
onPipeLineChanged = ::onPipeLineChanged,
onExport = ::onExport,
onDeleteItem = ::onDeleteItem,
onEditingIndexChange = ::onEditingIndexChange
)
init {
viewModelScope.launch(Dispatchers.Default) {
while (isActive) {
delay(10_000)
val items = _state.value.items
if (items.isEmpty()) continue
ExcelUtils.produceExcel(context, items, true)
}
}
permissionState.onEach {
if (it == PermissionState.Granted) {
val file = File(File(Constant.SDCARD, Constant.projectName), "backup/main.xls")
onFileSelected(file.path)
}
}.launchIn(viewModelScope)
}
private fun onFileSelected(file: String) {
viewModelScope.launch(Dispatchers.IO) {
val stakeInfoList = ExcelUtils.parseExcel(file)
Log.d(TAG, "onFileSelected: $stakeInfoList")
_state.update { it.copy(items = it.items + stakeInfoList) }
}
}
private fun onPipeLineChanged(index: Int, value: StakeInfo) {
Log.d(TAG, "onPipeLineChanged: $index, $value")
_state.update {
val stakeInfoList = it.items.toMutableList()
if (index >= 0) {
stakeInfoList[index] = value
} else {
stakeInfoList.add(value)
}
it.copy(items = stakeInfoList)
}
}
private fun onExport() {
val items = _state.value.items
if (items.isEmpty()) return context.toast("导出失败,没有数据")
viewModelScope.launch(Dispatchers.IO) {
_state.update { it.copy(exporting = true) }
ExcelUtils.produceExcel(context, items)
_state.update { it.copy(exporting = false) }
withContext(Dispatchers.Main) {
context.toast("导出成功")
}
}
}
private fun onDeleteItem(index: Int) {
_state.update {
val stakeInfoList = it.items.toMutableList()
stakeInfoList.removeAt(index)
it.copy(items = stakeInfoList)
}
}
private fun onEditingIndexChange(index: Int) {
_state.update { it.copy(editingIndex = index) }
}
}
data class HomeViewState(
val items: List<StakeInfo> = emptyList(),
val exporting: Boolean = false,
val editingIndex: Int = -1,
)
data class HomeActions(
val navigateToInfo: (StakeInfo?) -> Unit = {},
val onFinishedActivity: () -> Unit = {},
val onPipeLineChanged: (index: Int, StakeInfo) -> Unit = { _, _ -> },
val onExport: () -> Unit = {},
val navigateToFiles: () -> Unit = {},
val onFileSelected: (String) -> Unit = {},
val onDeleteItem: (index: Int) -> Unit = {},
val onEditingIndexChange: (Int) -> Unit = {}
)

View File

@@ -0,0 +1,40 @@
package com.zywl.test1229.ui.info
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavHostController
import androidx.navigation.compose.composable
import com.zywl.test1229.bean.StakeInfo
import kotlinx.serialization.Serializable
fun NavGraphBuilder.info(navController: NavHostController) = composable<StakeInfo> {
val viewModel: InfoViewModel = hiltViewModel()
val state by viewModel.state.collectAsState()
val actions = remember(viewModel.actions) {
viewModel.actions.copy(
onDone = {
navController.previousBackStackEntry?.savedStateHandle?.set(
StakeInfoSavedStateKey,
state.info
)
navController.navigateUp()
},
onCancel = navController::navigateUp,
)
}
InfoScreen(state = state, actions = actions)
}
fun NavHostController.navigateToInfo(info: StakeInfo) {
navigate(info)
}
const val StakeInfoSavedStateKey = "stake_info"
@Serializable
data class InfoRoute(
val info: StakeInfo
)

View File

@@ -0,0 +1,179 @@
package com.zywl.test1229.ui.info
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.zywl.test1229.bean.Constant
import com.zywl.test1229.ui.common.EditableExposedDropdownMenuSample
import com.zywl.test1229.ui.common.EditableTextField
import com.zywl.test1229.ui.common.EditableTextFieldInt
import com.zywl.test1229.ui.common.EditableTime
import com.zywl.test1229.ui.common.ExposedDropdownMenuSample
import com.zywl.test1229.ui.common.PreviewSurface
import com.zywl.test1229.ui.common.Previews
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun InfoScreen(
state: InfoViewState,
actions: InfoActions
) {
val scrollState = rememberScrollState()
val data = state.info
Column(
modifier = Modifier
.fillMaxSize()
.navigationBarsPadding()
.imePadding()
.statusBarsPadding()
.padding(8.dp)
.background(color = MaterialTheme.colorScheme.surfaceContainer)
.verticalScroll(scrollState)
) {
EditableTextField(
"桩号",
data.tempNo,
modifier = Modifier.fillMaxWidth(),
onPipeLineChanged = {
actions.onInfoChange(data.copy(tempNo = it))
}
)
EditableTextField(
"管线",
data.pipeLine,
modifier = Modifier.fillMaxWidth(),
onPipeLineChanged = {
actions.onInfoChange(data.copy(pipeLine = it))
}
)
EditableExposedDropdownMenuSample(
Constant.stakeTypeArray,
"桩类型",
data.stakeType,
modifier = Modifier.fillMaxWidth(),
onPipeLineChanged = {
actions.onInfoChange(data.copy(stakeType = it))
}
)
EditableExposedDropdownMenuSample(
Constant.depthArray,
"管中埋深(米)",
data.pipeDepth,
modifier = Modifier.fillMaxWidth(),
onPipeLineChanged = {
actions.onInfoChange(data.copy(pipeDepth = it))
}
)
EditableTextField(
"里程",
data.mileage,
modifier = Modifier.fillMaxWidth(),
onPipeLineChanged = {
actions.onInfoChange(data.copy(mileage = it))
}
)
EditableExposedDropdownMenuSample(
Constant.BuriedTechnologyArray,
"埋设工艺",
data.buryTech,
modifier = Modifier.fillMaxWidth(),
onPipeLineChanged = {
actions.onInfoChange(data.copy(buryTech = it))
}
)
ExposedDropdownMenuSample(
"是否出入土点",
data.isInPoint,
modifier = Modifier.fillMaxWidth(),
onPipeLineChanged = {
actions.onInfoChange(data.copy(isInPoint = it))
}
)
EditableExposedDropdownMenuSample(
Constant.terrainArray,
"地形",
data.terrain,
modifier = Modifier.fillMaxWidth(),
onPipeLineChanged = {
actions.onInfoChange(data.copy(terrain = it))
}
)
Row {
EditableTextFieldInt(
label = "经度",
content = (data.latitude).toString(),
modifier = Modifier
.fillMaxWidth()
.weight(1f), onPipeLineChanged = {
actions.onInfoChange(data.copy(latitude = it))
}
)
EditableTextFieldInt(
label = "维度",
content = (data.longitude).toString(),
modifier = Modifier
.fillMaxWidth()
.weight(1f), onPipeLineChanged = {
actions.onInfoChange(data.copy(longitude = it))
}
)
}
EditableTime(
label = "采集时间",
date = data.collectDate,
modifier = Modifier
.fillMaxWidth()
.padding(start = 6.dp, end = 6.dp, top = 18.dp, bottom = 12.dp),
onPipeLineChanged = {
actions.onInfoChange(data.copy(collectDate = it))
}
)
Row(
horizontalArrangement = Arrangement.Center,
modifier = Modifier.fillMaxWidth()
) {
Button(
modifier = Modifier,
onClick = actions.onDone
) {
Text(text = "确定")
}
Spacer(modifier = Modifier.width(16.dp))
Button(
modifier = Modifier,
onClick = actions.onCancel
) {
Text(text = "取消")
}
}
Spacer(modifier = Modifier.height(8.dp))
}
}
@Composable
@Previews
fun InfoScreenPreview() {
PreviewSurface {
InfoScreen(state = InfoViewState(), actions = InfoActions())
}
}

View File

@@ -0,0 +1,37 @@
package com.zywl.test1229.ui.info
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.navigation.toRoute
import com.zywl.test1229.bean.StakeInfo
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import javax.inject.Inject
@HiltViewModel
class InfoViewModel @Inject constructor(
private val savedStateHandle: SavedStateHandle
) : ViewModel() {
private val info = savedStateHandle.toRoute<StakeInfo>()
private val _state = MutableStateFlow(InfoViewState(info = info))
val state = _state.asStateFlow()
val actions = InfoActions(
onInfoChange = ::onInfoChange
)
private fun onInfoChange(value: StakeInfo) {
_state.update { it.copy(info = value) }
}
}
data class InfoViewState(
val info: StakeInfo = StakeInfo.Empty
)
data class InfoActions(
val onInfoChange: (StakeInfo) -> Unit = {},
val onDone: () -> Unit = {},
val onCancel: () -> Unit = {},
)

View File

@@ -14,38 +14,38 @@ import java.io.FileInputStream
import java.time.LocalDate import java.time.LocalDate
class ExcelUtils { object ExcelUtils {
fun parseExcel(path:String):MutableList<StakeInfo>{ fun parseExcel(path: String): MutableList<StakeInfo> {
val list:MutableList<StakeInfo> = mutableListOf() val list: MutableList<StakeInfo> = mutableListOf()
var file=File(path) var file = File(path)
if (!file.exists()) if (!file.exists())
return list return list
var fileByte=FileInputStream(file) var fileByte = FileInputStream(file)
val workbook=HSSFWorkbook(fileByte) val workbook = HSSFWorkbook(fileByte)
val sheet=workbook.getSheetAt(0); val sheet = workbook.getSheetAt(0);
for (rowIndex in 1 until sheet.physicalNumberOfRows) { for (rowIndex in 1 until sheet.physicalNumberOfRows) {
val row = sheet.getRow(rowIndex) val row = sheet.getRow(rowIndex)
var index3=0.0 var index3 = 0.0
var index4=0.0 var index4 = 0.0
var index5=0.0 var index5 = 0.0
try { try {
index3=getCellData(row.getCell(9)).toDouble(); index3 = getCellData(row.getCell(9)).toDouble();
} catch (e: NumberFormatException) { } catch (e: NumberFormatException) {
index3=0.0 index3 = 0.0
} }
try { try {
index4=getCellData(row.getCell(10)).toDouble(); index4 = getCellData(row.getCell(10)).toDouble();
} catch (e: NumberFormatException) { } catch (e: NumberFormatException) {
index4=0.0 index4 = 0.0
} }
try { try {
index5=getCellData(row.getCell(10)).toDouble(); index5 = getCellData(row.getCell(10)).toDouble();
} catch (e: NumberFormatException) { } catch (e: NumberFormatException) {
index5=0.0 index5 = 0.0
} }
// 跳过空行 // 跳过空行
if (row == null) continue if (row == null) continue
var stakeInfo=StakeInfo( var stakeInfo = StakeInfo(
getCellData(row.getCell(1)), getCellData(row.getCell(1)),
getCellData(row.getCell(0)), getCellData(row.getCell(0)),
getCellData(row.getCell(2)), getCellData(row.getCell(2)),
@@ -64,7 +64,8 @@ class ExcelUtils {
} }
return list; return list;
} }
fun getCellData(cell:Cell):String{
fun getCellData(cell: Cell): String {
val cellValue = when (cell.cellType) { val cellValue = when (cell.cellType) {
CellType.STRING -> cell.stringCellValue CellType.STRING -> cell.stringCellValue
CellType.NUMERIC -> cell.numericCellValue.toString() CellType.NUMERIC -> cell.numericCellValue.toString()
@@ -73,7 +74,8 @@ class ExcelUtils {
} }
return cellValue return cellValue
} }
fun produceExcel(context: Context?,array:List<StakeInfo>,isbackUp: Boolean=false){
fun produceExcel(context: Context?, array: List<StakeInfo>, isbackUp: Boolean = false) {
val primeExlPFixedSizeWidth = JsonUils.parseJSONListDouble( val primeExlPFixedSizeWidth = JsonUils.parseJSONListDouble(
JsonUils.loadJSONFromAssets("pile_data.json", context), JsonUils.loadJSONFromAssets("pile_data.json", context),
"primeExlPFixedSizeWidth" "primeExlPFixedSizeWidth"
@@ -84,8 +86,8 @@ class ExcelUtils {
) )
// softexportPrimeDataP(m_excelFiledNameP,m_pointListGroup); // softexportPrimeDataP(m_excelFiledNameP,m_pointListGroup);
var listMain= mutableListOf<List<String>>() var listMain = mutableListOf<List<String>>()
for (index in array){ for (index in array) {
var list = mutableListOf<String>() var list = mutableListOf<String>()
list.add(index.pipeLine) list.add(index.pipeLine)
list.add(index.tempNo) list.add(index.tempNo)
@@ -108,30 +110,42 @@ class ExcelUtils {
JsonUils.loadJSONFromAssets("pile_data.json", context), JsonUils.loadJSONFromAssets("pile_data.json", context),
"primeExlP" "primeExlP"
) )
var directory="" var directory = ""
var date=LocalDate.now() var date = LocalDate.now()
if (!isbackUp){ if (!isbackUp) {
var pointTitleInfo=Tools.getDataClassFieldNames(PointInfo()) var pointTitleInfo = Tools.getDataClassFieldNames(PointInfo())
var lineTitleInfo=Tools.getDataClassFieldNames(LineInfo()) var lineTitleInfo = Tools.getDataClassFieldNames(LineInfo())
var pointInfos = Tools.getDataClassFieldNamesAndValueForMap(collectPoints(array)) var pointInfos = Tools.getDataClassFieldNamesAndValueForMap(collectPoints(array))
var points=Tools.getDataClassFieldNamesAndValuesForList(pointTitleInfo,pointInfos) var points =
directory=Constant.SDCARD+"/"+Constant.projectName+"/tables" Tools.getDataClassFieldNamesAndValuesForList(pointTitleInfo, pointInfos)
directory = Constant.SDCARD + "/" + Constant.projectName + "/tables"
FileUtils.mkDir(directory) FileUtils.mkDir(directory)
var fileNum = FileUtils.getFileCountInDirectory(directory, ".xls")/2+1 var fileNum = FileUtils.getFileCountInDirectory(directory, ".xls") / 2 + 1
ExcelUtilsOfPoi.initExcelPrime( ExcelUtilsOfPoi.initExcelPrime(
"$directory/桩表_${date}_${fileNum}.xls", "$directory/桩表_${date}_${fileNum}.xls",
parseJSONprimeExlP, "桩表", primeExlPFixedSizeWidth, primeExlFixedHeight parseJSONprimeExlP, "桩表", primeExlPFixedSizeWidth, primeExlFixedHeight
) )
ExcelUtilsOfPoi.initExcel("$directory/桩表PC_${date}_${fileNum}.xls",pointTitleInfo,lineTitleInfo,"P_ALL", "L_All") ExcelUtilsOfPoi.initExcel(
"$directory/桩表PC_${date}_${fileNum}.xls",
pointTitleInfo,
lineTitleInfo,
"P_ALL",
"L_All"
)
ExcelUtilsOfPoi.writeObjListToExcelPrime( ExcelUtilsOfPoi.writeObjListToExcelPrime(
listMain, "$directory/桩表_${date}_${fileNum}.xls", listMain, "$directory/桩表_${date}_${fileNum}.xls",
primeExlFixedHeight, primeExlPFixedSizeWidth primeExlFixedHeight, primeExlPFixedSizeWidth
) )
ExcelUtilsOfPoi.writeObjListToExcel(0,points,"$directory/桩表PC_${date}_${fileNum}.xls") ExcelUtilsOfPoi.writeObjListToExcel(
}else{ 0,
directory=Constant.SDCARD+"/"+Constant.projectName+"/backup" points,
FileUtils.mkDir(directory) "$directory/桩表PC_${date}_${fileNum}.xls"
)
} else {
directory = Constant.SDCARD + "/" + Constant.projectName + "/backup"
// FileUtils.mkDir(directory)
File(directory).mkdirs()
ExcelUtilsOfPoi.initExcelPrime( ExcelUtilsOfPoi.initExcelPrime(
"$directory/main.xls", "$directory/main.xls",
parseJSONprimeExlP, "桩表", primeExlPFixedSizeWidth, primeExlFixedHeight parseJSONprimeExlP, "桩表", primeExlPFixedSizeWidth, primeExlFixedHeight
@@ -141,48 +155,50 @@ class ExcelUtils {
primeExlFixedHeight, primeExlPFixedSizeWidth primeExlFixedHeight, primeExlPFixedSizeWidth
) )
} }
Log.d("MainActivity","produceExcel") Log.d("MainActivity", "produceExcel")
} }
fun collectPoints(data:List<StakeInfo>):List<PointInfo>{
var list:MutableList<PointInfo> = mutableListOf() fun collectPoints(data: List<StakeInfo>): List<PointInfo> {
var list: MutableList<PointInfo> = mutableListOf()
var point = PointInfo() var point = PointInfo()
var index=1; var index = 1;
data.forEach { item-> data.forEach { item ->
point.buryTech=item.buryTech point.buryTech = item.buryTech
point.collectDate=item.collectDate point.collectDate = item.collectDate
point.exp_Date=item.collectDate point.exp_Date = item.collectDate
point.exp_Num="RQa$index" point.exp_Num = "RQa$index"
point.id="RQa$index" point.id = "RQa$index"
point.isInPoint=item.isInPoint point.isInPoint = item.isInPoint
point.latitude=item.latitude.toString() point.latitude = item.latitude.toString()
point.longitude=item.longitude.toString() point.longitude = item.longitude.toString()
point.mileage=item.mileage point.mileage = item.mileage
point.pipeDepth=item.pipeDepth point.pipeDepth = item.pipeDepth
point.pipeLine=item.pipeLine point.pipeLine = item.pipeLine
point.serialNum=index.toString() point.serialNum = index.toString()
point.situation="T-正常" point.situation = "T-正常"
point.stakeType=item.stakeType point.stakeType = item.stakeType
point.state="新测" point.state = "新测"
point.subsid=item.stakeType point.subsid = item.stakeType
point.symbol="探测点" point.symbol = "探测点"
point.symbolExpression="RQ-探测点" point.symbolExpression = "RQ-探测点"
point.symbolID="472" point.symbolID = "472"
point.symbolSizeX="4.0" point.symbolSizeX = "4.0"
point.symbolSizeY="4.0" point.symbolSizeY = "4.0"
point.tempNo=item.tempNo point.tempNo = item.tempNo
point.terrain=item.terrain point.terrain = item.terrain
point.code="RQ" point.code = "RQ"
point.pipeLine="燃气-RQ" point.pipeLine = "燃气-RQ"
point.rangeExpression="3.5" point.rangeExpression = "3.5"
point.shortCode="RQ" point.shortCode = "RQ"
point.sysId=index.toString() point.sysId = index.toString()
point.type="Type_None" point.type = "Type_None"
list.add(point) list.add(point)
} }
return list return list
} }
fun collectLines(data:List<StakeInfo>):List<LineInfo>{
var list:MutableList<LineInfo> = mutableListOf() fun collectLines(data: List<StakeInfo>): List<LineInfo> {
var list: MutableList<LineInfo> = mutableListOf()
return list return list
} }
} }

View File

@@ -1,257 +0,0 @@
package com.zywl.test1229.view
import android.util.Log
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.DatePicker
import androidx.compose.material3.DatePickerDialog
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.material3.rememberDatePickerState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.sp
import com.zywl.test1229.utils.ExcelUtils
import com.zywl.test1229.bean.StakeInfo
import com.zywl.test1229.data.SimpleViewModel
import kotlinx.coroutines.delay
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun EditableExposedDropdownMenuSample(options:List<String>,
label:String,
content:String,
onPipeLineChanged: (String) -> Unit,modifier: Modifier=Modifier) {
var expanded by remember { mutableStateOf(false) }
ExposedDropdownMenuBox(
//是否列出列表
expanded = expanded,
onExpandedChange = {
expanded = !expanded
},
) {
TextField(
value = content,
onValueChange = {
onPipeLineChanged(it)
},
label = { Text(label) },
trailingIcon = {
ExposedDropdownMenuDefaults.TrailingIcon(
expanded = expanded
)
},
colors = TextFieldDefaults.colors(focusedContainerColor = Color.Transparent, unfocusedContainerColor = Color.Transparent ),
modifier = modifier.menuAnchor()
)
val filteringOptions =
options.filter { it.contains(content, ignoreCase = true) }
if (filteringOptions.isNotEmpty()) {
ExposedDropdownMenu(
expanded = expanded,
onDismissRequest = {
expanded = false
}
) {
filteringOptions.forEach { selectionOption ->
DropdownMenuItem(
text = {
Text(text = selectionOption)
},
onClick = {
onPipeLineChanged(selectionOption)
expanded = false
}
)
}
}
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ExposedDropdownMenuSample(label:String,
content:String,
onPipeLineChanged: (String) -> Unit,modifier: Modifier=Modifier) {
val options = listOf("", "")
var expanded by remember { mutableStateOf(false) }
ExposedDropdownMenuBox(
expanded = expanded,
onExpandedChange = {
expanded = !expanded
}
) {
TextField(
readOnly = true,
value = content,
onValueChange = { },
label = { Text(label) },
trailingIcon = {
ExposedDropdownMenuDefaults.TrailingIcon(
//这里使用了 ExposedDropdownMenuDefaults.TrailingIcon 组件作为右侧图标。
//这个图标会根据 expanded 的状态变化,通常用于表示下拉菜单的打开或关闭状态
expanded = expanded
)
},
colors = TextFieldDefaults.colors(focusedContainerColor = Color.Transparent, unfocusedContainerColor = Color.Transparent ),
modifier = modifier.menuAnchor()
)
ExposedDropdownMenu(
expanded = expanded,
onDismissRequest = {
expanded = false
},
) {
options.forEach { selectionOption ->
DropdownMenuItem(
text = {
Text(selectionOption)
},
onClick = {
onPipeLineChanged(selectionOption)
expanded = false
}
)
}
}
}
}
@Composable
fun EditableTextField(label:String,
content:String,
onPipeLineChanged: (String) -> Unit,modifier: Modifier=Modifier){
TextField(
modifier = modifier,
value =content,
onValueChange = {
onPipeLineChanged(it)
},
singleLine = true,
label = {
Text(label)
},
colors = TextFieldDefaults.colors(focusedContainerColor = Color.Transparent, unfocusedContainerColor = Color.Transparent )
)
}
@Composable
fun EditableTextFieldInt(label:String,
content:String,
onPipeLineChanged: (Double) -> Unit,modifier: Modifier=Modifier){
TextField(
modifier = modifier,
value =content,
onValueChange = {
val newValue = it.toDoubleOrNull() // 将输入的字符串转换为 Double
if (newValue != null) {
onPipeLineChanged(newValue) // 如果转换成功,调用 onPipeLineChanged
}
},
singleLine = true,
label = {
Text(label)
},
keyboardOptions = KeyboardOptions.Default.copy(
keyboardType = KeyboardType.Number, // 设置为数字键盘
imeAction = ImeAction.Done
),
colors = TextFieldDefaults.colors(focusedContainerColor = Color.Transparent, unfocusedContainerColor = Color.Transparent )
)
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun EditableTime(label:String,
date:String,
onPipeLineChanged: (String) -> Unit,modifier: Modifier=Modifier){
var content=date
if(content.isEmpty()) {
content="**-**-**"
}
Row(modifier = modifier, horizontalArrangement = Arrangement.SpaceBetween) {
var showTimePicker by remember { mutableStateOf(false) }
Text(text = label)
Text(text = content,
style = TextStyle(
fontSize = 14.sp,
fontWeight = FontWeight.Bold
),
modifier = Modifier.clickable {
showTimePicker = true
}
)
val datePickerState = rememberDatePickerState()
if (showTimePicker) {
DatePickerDialog(
onDismissRequest = { showTimePicker=false; },
confirmButton = {
TextButton(onClick = {
val formattedDate = datePickerState.selectedDateMillis?.let {
val date = Date(it)
val format = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) // 设置日期格式
format.format(date)
} ?: content
onPipeLineChanged(formattedDate)
Log.d("DatePickerDialog",formattedDate)
showTimePicker=false;
}) {
Text("OK")
}
},
dismissButton = {
TextButton(onClick = {showTimePicker=false;}) {
Text("Cancel")
}
}
) {
DatePicker(state = datePickerState)
}
}
}
}
@Composable
fun PeriodicTaskForDataSave(viewModel: SimpleViewModel<List<StakeInfo>>){
var context = LocalContext.current
LaunchedEffect(key1 = Unit) {
while (true){
delay(10_000)
var data=viewModel.stateFlow.value.data
Log.d("MainActivity","PeriodicTaskForDataSave")
if (data!=null){
if (data.isNotEmpty())
ExcelUtils().produceExcel(context,data,true)
else
Log.d("MainActivity","PeriodicTaskForDataSave is Empty")
}else{
Log.d("MainActivity","PeriodicTaskForDataSave is null")
}
}
}
}

View File

@@ -1,331 +0,0 @@
package com.zywl.test1229.view
import android.net.Uri
import android.util.Log
import android.widget.Toast
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.slideInVertically
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.FloatingActionButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.imageResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import com.google.gson.Gson
import com.zywl.test1229.utils.ExcelUtils
import com.zywl.test1229.MainActivity
import com.zywl.test1229.R
import com.zywl.test1229.bean.Constant
import com.zywl.test1229.bean.StakeInfo
import com.zywl.test1229.data.SimpleViewModel
import kotlinx.coroutines.delay
@Composable
fun FloatingButtonS(navController: NavController,viewModel: SimpleViewModel<List<StakeInfo>>){
// var viewModel= viewModel();
var isShow by remember { mutableStateOf(false) }
var isShowDialog by remember { mutableStateOf(false) }
val context = LocalContext.current
// val result = navController.currentBackStackEntry?.savedStateHandle?.get<String>("resultKey")
// SideEffect {
// Log.d("mainPager","stakeInfoView $result")
// }
Column(modifier = Modifier.padding(end = 16.dp,bottom = 8.dp)) {
AnimatedVisibility(
visible = isShow,
enter = fadeIn() + slideInVertically(initialOffsetY = { it }) // Animation for appearing
) {
Column(
verticalArrangement = Arrangement.spacedBy(8.dp),
modifier = Modifier.padding(bottom = 8.dp)
) {
FloatingActionButton(
elevation = FloatingActionButtonDefaults.elevation(0.dp),
shape = CircleShape,
onClick = {
navController.navigate("files")
},
modifier = Modifier.size(66.dp),
) {
Text("导入", color = Color.White)
}
FloatingActionButton(
elevation = FloatingActionButtonDefaults.elevation(0.dp),
shape = CircleShape,
onClick = {
isShowDialog=true
var excelUtils = ExcelUtils()
var data=viewModel.stateFlow.value.data
if (data!=null){
if (data.isNotEmpty()){
excelUtils.produceExcel(context,data)
Toast.makeText(context, "导出成功", Toast.LENGTH_SHORT).show()
}
else{
Toast.makeText(context, "导出失败,没有数据", Toast.LENGTH_SHORT).show()
}
}else{
Toast.makeText(context, "导出失败,没有数据", Toast.LENGTH_SHORT).show()
}
isShowDialog=false
},
modifier = Modifier.size(66.dp),
) {
Text("导出", color = Color.White)
}
FloatingActionButton(
elevation = FloatingActionButtonDefaults.elevation(0.dp),
shape = CircleShape,
onClick = {
navController.navigate("info")
},
modifier = Modifier.size(66.dp),
) {
Text("新增", color = Color.White)
}
}
}
FloatingActionButton(
elevation = FloatingActionButtonDefaults.elevation(0.dp),
shape = CircleShape,
onClick = {
isShow=!isShow
},
modifier = Modifier.size(66.dp),
containerColor = Color.Blue
) {
var str=if (isShow) "-" else "+"
Text(str, color = Color.White, style = TextStyle(fontSize = 26.sp))
}
}
ProgressDialogView(isShowDialog)
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TopBar(activity: MainActivity){
// 设置两次点击之间的间隔时间为 2 秒
var showExitMessage by remember { mutableStateOf(false) }
if (showExitMessage) {
Toast.makeText(LocalContext.current, "再按一次退出", Toast.LENGTH_SHORT).show()
LaunchedEffect(Unit) {
delay(activity.backPressInterval)
showExitMessage = false // 2 秒后隐藏提示
}
}
TopAppBar(
title = { Text(text = "桩管理") },
colors = TopAppBarDefaults.mediumTopAppBarColors(
containerColor = Color.Cyan
),
navigationIcon = {
IconButton(onClick = {
val currentTime = System.currentTimeMillis()
if (currentTime - activity.lastBackPressedTime < activity.backPressInterval) {
// 如果两次点击的时间间隔小于规定的时间2000ms退出应用
activity.finish() // 或者使用 `exitProcess(0)` 来退出应用
} else {
// 否则显示提示信息并记录当前时间
activity.lastBackPressedTime = currentTime
showExitMessage = true
}
}) {
Icon(imageVector = Icons.Default.ArrowBack, contentDescription = "Back")
}
}
)
}
var outerItems:MutableList<StakeInfo> = mutableListOf()
@Composable
fun mainPager(navController: NavController, viewModel: SimpleViewModel<List<StakeInfo>>, modifier: Modifier = Modifier){
// 订阅 stateFlow 以获取数据
val result = viewModel.stateFlow.collectAsState()
val dataList = result.value.data
PeriodicTaskForDataSave(viewModel)
SideEffect {
Log.d("sss","mainPager outerItems")
dataList?.let {
outerItems= dataList as MutableList<StakeInfo>
}
}
Box(modifier= modifier
.fillMaxSize()
.padding(start = 36.dp, end = 36.dp)){
LazyColumn(modifier=Modifier.fillMaxSize()) {
itemsIndexed(dataList?:ArrayList<StakeInfo>()){
index, item ->
var expanded by remember { mutableStateOf(false) }
var stakeInfo by remember {
mutableStateOf(item)
}
SideEffect {
outerItems[index] = stakeInfo
}
Column(modifier = Modifier
.fillParentMaxWidth()
.padding(top = 16.dp), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center) {
Row(modifier = Modifier
.fillMaxWidth()
.height(26.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween) {
Text(text = "${index+1}", style = TextStyle(
fontSize = 16.sp,
fontWeight = FontWeight.Bold,
), modifier = Modifier.padding(start = 6.dp)
)
Text(text = "测绘临时编号:${item.tempNo}",style = TextStyle(
fontSize = 14.sp,
fontWeight = FontWeight.Bold
), modifier = Modifier
.padding(start = 26.dp)
.clickable {
navController.navigate("info/${Uri.encode(Gson().toJson(item))}")
}
)
Icon(bitmap = ImageBitmap.imageResource( id = (if (!expanded) R.mipmap.downdraw else R.mipmap.updraw)),
contentDescription = null,modifier= Modifier
.size(16.dp)
.padding(end = 6.dp)
.clickable {
expanded = !expanded
}
)
}
StakeInfoView(isShow = expanded, stakeInfo = stakeInfo,
onPipeLineChanged = { newStakeInfo->
stakeInfo=newStakeInfo
},
onDeleteItem = {
}
)
Box(modifier = Modifier.padding(top = 6.dp)) {
Spacer(modifier = Modifier
.fillMaxWidth()
.height(1.dp)
.background(Color.Blue))
}
}
}
}
Button(
onClick = { /* Handle Click */ },
modifier = Modifier
.align(Alignment.BottomStart) // 设置它在Box中的右下角
.padding(bottom = 36.dp)
) {
Text("设置点的线")
}
}
}
@Composable
fun StakeInfoView(isShow:Boolean, stakeInfo: StakeInfo, onPipeLineChanged:(StakeInfo)->Unit,onDeleteItem:()->Unit){
if (!isShow){
return
}
Surface(
shape = RoundedCornerShape(8.dp),
shadowElevation = 10.dp,
){
Column {
EditableTextField("管线",stakeInfo.pipeLine, modifier = Modifier.fillMaxWidth(), onPipeLineChanged = {
onPipeLineChanged(stakeInfo.copy(pipeLine = it))
})
EditableExposedDropdownMenuSample(Constant.stakeTypeArray,"桩类型",stakeInfo.stakeType,modifier = Modifier.fillMaxWidth(),onPipeLineChanged = {
onPipeLineChanged(stakeInfo.copy(stakeType = it))
})
EditableExposedDropdownMenuSample(Constant.depthArray,"管中埋深(米)",stakeInfo.pipeDepth,modifier = Modifier.fillMaxWidth(),onPipeLineChanged = {
onPipeLineChanged(stakeInfo.copy(pipeDepth = it))
})
EditableTextField("里程",stakeInfo.mileage, modifier = Modifier.fillMaxWidth(), onPipeLineChanged = {
onPipeLineChanged(stakeInfo.copy(mileage = it))
})
EditableExposedDropdownMenuSample(Constant.BuriedTechnologyArray,"埋设工艺",stakeInfo.buryTech,modifier = Modifier.fillMaxWidth(),onPipeLineChanged = {
onPipeLineChanged(stakeInfo.copy(buryTech = it))
})
ExposedDropdownMenuSample("是否出入土点",stakeInfo.isInPoint, modifier = Modifier.fillMaxWidth(), onPipeLineChanged = {
onPipeLineChanged(stakeInfo.copy(isInPoint = it))
})
EditableExposedDropdownMenuSample(Constant.terrainArray,"地形",stakeInfo.terrain,modifier = Modifier.fillMaxWidth(),onPipeLineChanged = {
onPipeLineChanged(stakeInfo.copy(terrain = it))
})
Row {
EditableTextFieldInt("经度","${stakeInfo.latitude}", modifier = Modifier
.fillMaxWidth()
.weight(1f), onPipeLineChanged = {
onPipeLineChanged(stakeInfo.copy(latitude = it))
})
EditableTextFieldInt("维度","${stakeInfo.longitude}", modifier = Modifier
.fillMaxWidth()
.weight(1f), onPipeLineChanged = {
onPipeLineChanged(stakeInfo.copy(longitude = it))
})
}
EditableTextFieldInt("Z(85高程桩根部)","${stakeInfo.z}", modifier = Modifier
.fillMaxWidth(), onPipeLineChanged = {
onPipeLineChanged(stakeInfo.copy(z = it))
})
EditableTime("采集时间",stakeInfo.collectDate, modifier = Modifier
.fillMaxWidth()
.padding(start = 6.dp, end = 6.dp, top = 18.dp, bottom = 12.dp), onPipeLineChanged = {
onPipeLineChanged(stakeInfo.copy(collectDate = it))
})
Row (modifier = Modifier.fillMaxSize(),horizontalArrangement = Arrangement.Center){
Button(onClick = {
onDeleteItem()
}) {
Text(text = "删除")
}
}
}
}
}

View File

@@ -1,112 +0,0 @@
package com.zywl.test1229.view
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.unit.dp
import java.awt.Color
@Composable
fun SimpleDialogView(showDialog : Boolean,
dialogTitle: String,
dialogText: String,
onDismissRequest: () -> Unit,
onConfirmation: () -> Unit){
if (showDialog) {
AlertDialog(
onDismissRequest = {
onDismissRequest()
},
title = {
Text(dialogTitle)
},
text = {
Text(dialogText)
},
confirmButton = {
TextButton(
onClick = {
onConfirmation()
}
) {
Text("确定")
}
},
dismissButton = {
TextButton(
onClick = {
onDismissRequest()
}
) {
Text("取消")
}
}
)
}
}
@Composable
fun PermissionDialog(
visible: Boolean,
onConfirm: () -> Unit,
onDismissRequest: () -> Unit,
) {
if (visible) AlertDialog(
title = {
Text(text = "管理所有文件")
}, text = {
Text(text = "授予app管理存储设备上的所有文件的权限")
},
confirmButton = {
TextButton(
onClick = {
onConfirm()
onDismissRequest()
}
) {
Text(text = "确定")
}
}, dismissButton = {
TextButton(
onClick = onDismissRequest
) {
Text(text = "取消")
}
}, onDismissRequest = onDismissRequest
)
}
@Composable
fun ProgressDialogView(visible: Boolean){
if (visible)
AlertDialog(
onDismissRequest = { },
title = {
Text(text = "正在处理...")
},
text = {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
CircularProgressIndicator(
modifier = Modifier.width(64.dp),
color = MaterialTheme.colorScheme.secondary,
trackColor = MaterialTheme.colorScheme.surfaceVariant,
)
}
},
confirmButton = {
}
)
}

View File

@@ -1,154 +0,0 @@
package com.zywl.test1229.view
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import com.zywl.test1229.bean.Constant
import com.zywl.test1229.bean.StakeInfo
import com.zywl.test1229.bean.User
import com.zywl.test1229.data.SimpleViewModel
class StakeInfoViewPager {
@Composable
fun MainView(navController: NavController,
viewModel: SimpleViewModel<List<StakeInfo>>,
stakeInfo: StakeInfo? =null,
modifier: Modifier=Modifier){
val result = viewModel.stateFlow.collectAsState()
val dataList = result.value.data as MutableList<StakeInfo>
val scrollState = rememberScrollState()
var index=-1
var dataTmp=StakeInfo("","","",0.0,0.0,0.0,
"","","","","","","")
var data by remember { mutableStateOf(dataTmp) }
stakeInfo?.let {
data=stakeInfo
dataList?.let{
index= dataList.indexOf(stakeInfo) ?: -1
}
}
Scaffold(
modifier = Modifier.fillMaxSize().padding(start = 26.dp, end = 26.dp),
) { innerPadding ->
Column(modifier = Modifier.fillMaxSize().padding(innerPadding).verticalScroll(scrollState)) {
EditableTextField(
"桩号",
data.tempNo,
modifier = Modifier.fillMaxWidth(),
onPipeLineChanged = {
data=data.copy(tempNo = it)
})
EditableTextField(
"管线",
data.pipeLine,
modifier = Modifier.fillMaxWidth(),
onPipeLineChanged = {
data=data.copy(pipeLine = it)
})
EditableExposedDropdownMenuSample(
Constant.stakeTypeArray,
"桩类型",
data.stakeType,
modifier = Modifier.fillMaxWidth(),
onPipeLineChanged = {
data=data.copy(stakeType = it)
})
EditableExposedDropdownMenuSample(
Constant.depthArray,
"管中埋深(米)",
data.pipeDepth,
modifier = Modifier.fillMaxWidth(),
onPipeLineChanged = {
data=data.copy(pipeDepth = it)
})
EditableTextField(
"里程",
data.mileage,
modifier = Modifier.fillMaxWidth(),
onPipeLineChanged = {
data=data.copy(mileage = it)
})
EditableExposedDropdownMenuSample(
Constant.BuriedTechnologyArray,
"埋设工艺",
data.buryTech ,
modifier = Modifier.fillMaxWidth(),
onPipeLineChanged = {
data=data.copy(buryTech = it)
})
ExposedDropdownMenuSample(
"是否出入土点",
data.isInPoint,
modifier = Modifier.fillMaxWidth(),
onPipeLineChanged = {
data=data.copy(isInPoint = it)
})
EditableExposedDropdownMenuSample(
Constant.terrainArray,
"地形",
data.terrain,
modifier = Modifier.fillMaxWidth(),
onPipeLineChanged = {
data=data.copy(terrain = it)
})
Row {
EditableTextFieldInt("经度", (data.latitude).toString(), modifier = Modifier
.fillMaxWidth()
.weight(1f), onPipeLineChanged = {
data=data.copy(latitude = it)
})
EditableTextFieldInt("维度", (data.longitude).toString(), modifier = Modifier
.fillMaxWidth()
.weight(1f), onPipeLineChanged = {
data=data.copy(longitude = it)
})
}
EditableTime("采集时间",
data.collectDate,
modifier = Modifier
.fillMaxWidth()
.padding(start = 6.dp, end = 6.dp, top = 18.dp, bottom = 12.dp),
onPipeLineChanged = {
data=data.copy(collectDate = it)
})
Row(horizontalArrangement = Arrangement.Center, modifier = Modifier.fillMaxWidth()) {
Button(modifier = Modifier.padding(end = 16.dp),onClick = {
dataList?.let {
if (index>=0)
dataList[index]=data
else
dataList.add(data)
viewModel.setData(dataList)
}
navController.popBackStack()
}) {
Text(text = "确定")
}
Button(modifier = Modifier.padding(start = 16.dp),onClick = {
navController.popBackStack()
}) {
Text(text = "取消")
}
}
}
}
}
}