>
- suspend fun insertTank(tank: Tank)
- suspend fun updateTank(tank: Tank)
+ suspend fun insertTank(tank: Tank, image: Bitmap)
+ suspend fun updateTank(tank: Tank, image: Bitmap)
suspend fun deleteTank(tank: Tank)
+ suspend fun delete(tankId: Long)
}
\ No newline at end of file
diff --git a/compose/app/src/main/java/ru/ulstu/is/pmu/tanks/composeui/Constructor.kt b/compose/app/src/main/java/ru/ulstu/is/pmu/tanks/composeui/Constructor.kt
index 8bc8491..3d794f3 100644
--- a/compose/app/src/main/java/ru/ulstu/is/pmu/tanks/composeui/Constructor.kt
+++ b/compose/app/src/main/java/ru/ulstu/is/pmu/tanks/composeui/Constructor.kt
@@ -1,6 +1,7 @@
package ru.ulstu.`is`.pmu.tanks.composeui
import android.content.res.Configuration
+import android.graphics.Bitmap
import android.util.Log
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
@@ -39,6 +40,9 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
+import com.application.ui.miniatureBound
+import com.application.ui.resize
+import com.application.ui.tankImageBound
import kotlinx.coroutines.launch
import ru.ulstu.`is`.pmu.R
import ru.ulstu.`is`.pmu.tank.composeui.edit.LevelDropDownViewModel
@@ -54,6 +58,7 @@ import ru.ulstu.`is`.pmu.tank.composeui.edit.toUiState
import ru.ulstu.`is`.pmu.tank.model.Level
import ru.ulstu.`is`.pmu.tank.model.Nation
import ru.ulstu.`is`.pmu.tank.model.Tank
+import ru.ulstu.`is`.pmu.tanks.composeui.image.CuteImageUploader
import ru.ulstu.`is`.pmu.ui.AppViewModelProvider
import ru.ulstu.`is`.pmu.ui.theme.CustomDark
import ru.ulstu.`is`.pmu.ui.theme.CustomOrange
@@ -73,6 +78,7 @@ fun Constructor(
nationDropDownViewModel.setCurrentNation(tankEditViewModel.tankUiState.tankDetails.nationId ?: 1)
Constructor(
+ tankViewModel = tankEditViewModel,
tankUiState = tankEditViewModel.tankUiState,
levelUiState = levelDropDownViewModel.levelUiState,
levelsListUiState = levelDropDownViewModel.levelsListUiState,
@@ -192,6 +198,7 @@ private fun NationDropDown(
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun Constructor(
+ tankViewModel: TankEditViewModel,
tankUiState: TankUiState,
levelUiState: LevelUiState,
levelsListUiState: LevelsListUiState,
@@ -208,6 +215,15 @@ private fun Constructor(
//для работы выпадающего списка наций
var expandedNation by remember { mutableStateOf(false) }
+ fun handleImageUpload(bitmap: Bitmap) {
+ tankViewModel.updateUiState(
+ tankUiState.tankDetails.copy(
+ image = bitmap.resize(tankImageBound),
+ miniature = bitmap.resize(miniatureBound)
+ )
+ )
+ }
+
Column(
verticalArrangement = Arrangement.spacedBy(35.dp),
modifier = Modifier.padding(0.dp, 15.dp)
@@ -234,6 +250,8 @@ private fun Constructor(
modifier = Modifier.padding(0.dp, 5.dp)
) {
Text(text="Название:", fontSize = 30.sp, color = Color.Black, fontWeight = FontWeight.Bold)
+ Spacer(Modifier.height(25.dp))
+ Text(text="Изображение:", fontSize = 30.sp, color = Color.Black, fontWeight = FontWeight.Bold)
Spacer(Modifier.height(30.dp))
Text(text="Уровень:", fontSize = 30.sp, color = Color.Black, fontWeight = FontWeight.Bold)
Spacer(Modifier.height(30.dp))
@@ -250,6 +268,11 @@ private fun Constructor(
.width(200.dp),
)
Spacer(Modifier.height(10.dp))
+ CuteImageUploader(
+ bitmap = tankUiState.tankDetails.image,
+ onResult = { bitmap: Bitmap -> handleImageUpload(bitmap) }
+ )
+ Spacer(Modifier.height(10.dp))
// Выпадающий список уровней
LevelDropDown(
levelUiState = levelUiState,
@@ -421,6 +444,7 @@ fun ConstructorEditPreview() {
color = CustomDark
) {
Constructor(
+ tankViewModel = viewModel(factory = AppViewModelProvider.Factory),
tankUiState = Tank.getTank().toUiState(true),
levelUiState = Level.DEMO_LEVEL.toUiState(),
levelsListUiState = LevelsListUiState(listOf()),
diff --git a/compose/app/src/main/java/ru/ulstu/is/pmu/tanks/composeui/image/CuteImage.kt b/compose/app/src/main/java/ru/ulstu/is/pmu/tanks/composeui/image/CuteImage.kt
new file mode 100644
index 0000000..4f792ce
--- /dev/null
+++ b/compose/app/src/main/java/ru/ulstu/is/pmu/tanks/composeui/image/CuteImage.kt
@@ -0,0 +1,25 @@
+package ru.ulstu.`is`.pmu.tanks.composeui.image
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.aspectRatio
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.ImageBitmap
+import androidx.compose.ui.layout.ContentScale
+
+@Composable
+fun CuteImage(
+ imageBitmap: ImageBitmap,
+ modifier: Modifier = Modifier
+) {
+ Image(
+ bitmap = imageBitmap,
+ contentDescription = null,
+ contentScale = ContentScale.Crop,
+ modifier = modifier
+ .aspectRatio(1F)
+ .clip(RoundedCornerShape(Dimensions.cornerRadius))
+ )
+}
\ No newline at end of file
diff --git a/compose/app/src/main/java/ru/ulstu/is/pmu/tanks/composeui/image/CuteImageButton.kt b/compose/app/src/main/java/ru/ulstu/is/pmu/tanks/composeui/image/CuteImageButton.kt
new file mode 100644
index 0000000..2f014b2
--- /dev/null
+++ b/compose/app/src/main/java/ru/ulstu/is/pmu/tanks/composeui/image/CuteImageButton.kt
@@ -0,0 +1,31 @@
+package ru.ulstu.`is`.pmu.tanks.composeui.image
+
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.ImageBitmap
+import androidx.compose.ui.unit.dp
+
+@Composable
+fun CuteImageButton(
+ imageBitmap: ImageBitmap,
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier
+) {
+ val cornerShape = RoundedCornerShape(Dimensions.cornerRadius)
+ Button(
+ onClick = { onClick() },
+ modifier = modifier,
+ shape = cornerShape,
+ contentPadding = PaddingValues(0.dp),
+ colors = ButtonDefaults.buttonColors(
+ containerColor = Color.Transparent
+ )
+ ) {
+ CuteImage(imageBitmap)
+ }
+}
\ No newline at end of file
diff --git a/compose/app/src/main/java/ru/ulstu/is/pmu/tanks/composeui/image/CuteImageUploader.kt b/compose/app/src/main/java/ru/ulstu/is/pmu/tanks/composeui/image/CuteImageUploader.kt
new file mode 100644
index 0000000..299c328
--- /dev/null
+++ b/compose/app/src/main/java/ru/ulstu/is/pmu/tanks/composeui/image/CuteImageUploader.kt
@@ -0,0 +1,132 @@
+package ru.ulstu.`is`.pmu.tanks.composeui.image
+
+import android.content.res.Configuration
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.net.Uri
+import androidx.activity.compose.rememberLauncherForActivityResult
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.IntrinsicSize
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.aspectRatio
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.Icon
+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.graphics.asImageBitmap
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import ru.ulstu.`is`.pmu.R
+import ru.ulstu.`is`.pmu.ui.theme.CustomDark
+import ru.ulstu.`is`.pmu.ui.theme.CustomOrange
+import ru.ulstu.`is`.pmu.ui.theme.PmudemoTheme
+
+@Composable
+fun CuteImageUploader(
+ bitmap: Bitmap?,
+ onResult: (Bitmap) -> Unit
+) {
+ val context = LocalContext.current
+ val title: String = if (bitmap == null) {
+ stringResource(R.string.not_uploaded)
+ } else {
+ stringResource(R.string.size, bitmap.width, bitmap.height)
+ }
+
+ val launcher = rememberLauncherForActivityResult(
+ contract = ActivityResultContracts.GetContent(),
+ onResult = { uri: Uri? ->
+ uri?.let {
+ val inputStream = context.contentResolver.openInputStream(uri)
+ val newBitmap: Bitmap = BitmapFactory.decodeStream(inputStream)
+ onResult(newBitmap)
+ }
+ }
+ )
+
+ fun handleUploadButtonClick() {
+ launcher.launch("image/*")
+ }
+
+ Row(
+ modifier = Modifier.height(IntrinsicSize.Min)
+ ) {
+ Box(
+ contentAlignment = Alignment.Center,
+ modifier = Modifier
+ .background(
+ color = MaterialTheme.colorScheme.surface,
+ shape = RoundedCornerShape(Dimensions.cornerRadius)
+ )
+ .weight(0.25F)
+ .aspectRatio(1F)
+ ) {
+ if (bitmap != null) {
+ CuteImage(
+ imageBitmap = bitmap.asImageBitmap(),
+ modifier = Modifier.width(100.dp)
+ )
+ } else {
+ Icon(
+ painter = painterResource(R.drawable.ic_camera),
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.onBackground
+ )
+ }
+ }
+ Spacer(modifier = Modifier.width(10.dp))
+ Column(
+ modifier = Modifier
+ .background(
+ color = MaterialTheme.colorScheme.surface,
+ shape = RoundedCornerShape(Dimensions.cornerRadius)
+ )
+ .fillMaxHeight()
+ .padding(10.dp)
+ .weight(0.75F)
+ ) {
+ Text(
+ text = title,
+ color = MaterialTheme.colorScheme.onBackground
+ )
+ Spacer(modifier = Modifier.weight(1F))
+ Button(
+ modifier = Modifier
+ .width(200.dp)
+ .height(50.dp),
+ colors = ButtonDefaults.buttonColors(
+ containerColor = CustomOrange,
+ contentColor = CustomDark
+ ),
+ onClick = { handleUploadButtonClick() },
+ ){
+ Text(text = "Загрузить изображение")
+ }
+ }
+ }
+}
+
+@Preview(name = "Light Mode", uiMode = Configuration.UI_MODE_NIGHT_NO)
+@Preview(name = "Dark Mode", uiMode = Configuration.UI_MODE_NIGHT_YES)
+@Composable
+private fun CuteImageLoaderPreview() {
+ PmudemoTheme {
+ CuteImageUploader(null) {}
+ }
+}
\ No newline at end of file
diff --git a/compose/app/src/main/java/ru/ulstu/is/pmu/tanks/composeui/image/CuteZoomableImage.kt b/compose/app/src/main/java/ru/ulstu/is/pmu/tanks/composeui/image/CuteZoomableImage.kt
new file mode 100644
index 0000000..df32c91
--- /dev/null
+++ b/compose/app/src/main/java/ru/ulstu/is/pmu/tanks/composeui/image/CuteZoomableImage.kt
@@ -0,0 +1,61 @@
+package ru.ulstu.`is`.pmu.tanks.composeui.image
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.gestures.detectTransformGestures
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.mutableFloatStateOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.ImageBitmap
+import androidx.compose.ui.graphics.RectangleShape
+import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.layout.onSizeChanged
+import androidx.compose.ui.unit.IntSize
+
+@Composable
+fun CuteZoomableImage(
+ imageBitmap: ImageBitmap
+) {
+ val size = remember { mutableStateOf(IntSize.Zero) }
+ val scale = remember { mutableFloatStateOf(1f) }
+ val offsetX = remember { mutableFloatStateOf(0f) }
+ val offsetY = remember { mutableFloatStateOf(0f) }
+
+ Box(
+ modifier = Modifier
+ .clip(RectangleShape)
+ .fillMaxSize()
+ .pointerInput(Unit) {
+ detectTransformGestures { _, pan, zoom, _ ->
+ scale.floatValue = maxOf(1f, minOf(3f, scale.floatValue * zoom))
+ val maxX = (size.value.width * (scale.floatValue - 1)) / 2
+ val minX = -maxX
+ offsetX.floatValue = maxOf(minX, minOf(maxX, offsetX.floatValue + pan.x))
+ val maxY = (size.value.height * (scale.floatValue - 1)) / 2
+ val minY = -maxY
+ offsetY.floatValue = maxOf(minY, minOf(maxY, offsetY.floatValue + pan.y))
+ }
+ }.onSizeChanged {
+ size.value = it
+ }
+ ) {
+ Image(
+ bitmap = imageBitmap,
+ contentDescription = null,
+ modifier = Modifier
+ .align(Alignment.Center)
+ .graphicsLayer(
+ scaleX = scale.floatValue,
+ scaleY = scale.floatValue,
+ translationX = offsetX.floatValue,
+ translationY = offsetY.floatValue
+ )
+ )
+ }
+}
\ No newline at end of file
diff --git a/compose/app/src/main/java/ru/ulstu/is/pmu/tanks/composeui/image/Dimensions.kt b/compose/app/src/main/java/ru/ulstu/is/pmu/tanks/composeui/image/Dimensions.kt
new file mode 100644
index 0000000..5753a45
--- /dev/null
+++ b/compose/app/src/main/java/ru/ulstu/is/pmu/tanks/composeui/image/Dimensions.kt
@@ -0,0 +1,7 @@
+package ru.ulstu.`is`.pmu.tanks.composeui.image
+
+import androidx.compose.ui.unit.dp
+
+object Dimensions {
+ val cornerRadius = 10.dp
+}
\ No newline at end of file
diff --git a/compose/app/src/main/java/ru/ulstu/is/pmu/ui/ImageTools.kt b/compose/app/src/main/java/ru/ulstu/is/pmu/ui/ImageTools.kt
new file mode 100644
index 0000000..e6d71fc
--- /dev/null
+++ b/compose/app/src/main/java/ru/ulstu/is/pmu/ui/ImageTools.kt
@@ -0,0 +1,26 @@
+package com.application.ui
+
+import android.graphics.Bitmap
+import kotlin.math.sqrt
+
+const val miniatureBound: Int = 250
+const val tankImageBound: Int = 800
+
+fun getEmptyBitmap(): Bitmap {
+ return Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)
+}
+
+fun Bitmap.resize(bound: Int): Bitmap {
+ val width = this.width
+ val height = this.height
+ val size: Int = width * height
+ val newSize: Int = bound * bound
+ val factor: Double = if (size > newSize) {
+ sqrt(size.toDouble() / newSize)
+ } else {
+ 1.0
+ }
+ val newWidth: Int = (width / factor).toInt()
+ val newHeight: Int = (height / factor).toInt()
+ return Bitmap.createScaledBitmap(this, newWidth, newHeight, false)
+}
\ No newline at end of file
diff --git a/compose/app/src/main/res/drawable/ic_camera.xml b/compose/app/src/main/res/drawable/ic_camera.xml
new file mode 100644
index 0000000..e47edf5
--- /dev/null
+++ b/compose/app/src/main/res/drawable/ic_camera.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/compose/app/src/main/res/drawable/t_34_85.jpeg b/compose/app/src/main/res/drawable/t_34_85.jpeg
deleted file mode 100644
index c50d054..0000000
Binary files a/compose/app/src/main/res/drawable/t_34_85.jpeg and /dev/null differ
diff --git a/compose/app/src/main/res/values/strings.xml b/compose/app/src/main/res/values/strings.xml
index aca823a..c8d7550 100644
--- a/compose/app/src/main/res/values/strings.xml
+++ b/compose/app/src/main/res/values/strings.xml
@@ -31,4 +31,10 @@
Здесь могла быть Ваша реклама!
\n\n
Наш сайт ulstu.ru
+
+
+ Image
+ Not uploaded
+ Size: %1$dx%2$d
+ Upload image
\ No newline at end of file