Промежуточное

This commit is contained in:
ElEgEv 2023-12-11 15:29:25 +04:00
parent 38cb371048
commit 8f116e2005
21 changed files with 198 additions and 1 deletions

View File

@ -84,4 +84,8 @@ dependencies {
androidTestImplementation("androidx.compose.ui:ui-test-junit4") androidTestImplementation("androidx.compose.ui:ui-test-junit4")
debugImplementation("androidx.compose.ui:ui-tooling") debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest") debugImplementation("androidx.compose.ui:ui-test-manifest")
// Paging | +
val pagingVersion = "3.3.0-alpha02"
implementation("androidx.paging:paging-compose:$pagingVersion")
} }

View File

@ -63,9 +63,11 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.navigation.NavController import androidx.navigation.NavController
import ru.ulstu.`is`.pmu.tank.composeui.TankList import ru.ulstu.`is`.pmu.tank.composeui.TankList
import ru.ulstu.`is`.pmu.tank.composeui.list.NationListViewModel
import ru.ulstu.`is`.pmu.tanks.composeui.Account import ru.ulstu.`is`.pmu.tanks.composeui.Account
import ru.ulstu.`is`.pmu.tanks.composeui.Constructor import ru.ulstu.`is`.pmu.tanks.composeui.Constructor
import ru.ulstu.`is`.pmu.tanks.composeui.Hangar import ru.ulstu.`is`.pmu.tanks.composeui.Hangar
import ru.ulstu.`is`.pmu.tanks.composeui.NationList
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
@ -143,6 +145,7 @@ fun Navhost(
startDestination = Screen.TankList.route, startDestination = Screen.TankList.route,
) { ) {
composable(Screen.TankList.route) { TankList(navController) } composable(Screen.TankList.route) { TankList(navController) }
composable(Screen.NATIONS.route) { NationList(navController) }
composable( composable(
Screen.Constructor.route, Screen.Constructor.route,
arguments = listOf(navArgument("id") { type = NavType.LongType }) arguments = listOf(navArgument("id") { type = NavType.LongType })

View File

@ -4,6 +4,7 @@ import androidx.annotation.StringRes
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AccountCircle import androidx.compose.material.icons.filled.AccountCircle
import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Create
import androidx.compose.material.icons.filled.Favorite import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.Home import androidx.compose.material.icons.filled.Home
import androidx.compose.material.icons.filled.List import androidx.compose.material.icons.filled.List
@ -36,11 +37,14 @@ enum class Screen(
), ),
StudentView( StudentView(
"student-view/{id}", R.string.student_view_title, showInBottomBar = false "student-view/{id}", R.string.student_view_title, showInBottomBar = false
); ),
NATIONS("nations", R.string.nation, Icons.Filled.Create),
EDIT_NATIONS("edit-nation/{id}", R.string.nation);
companion object { companion object {
val bottomBarItems = listOf( val bottomBarItems = listOf(
TankList, TankList,
NATIONS,
Hangar, Hangar,
Account Account
) )
@ -49,5 +53,9 @@ enum class Screen(
val findRoute = route.split("/").first() val findRoute = route.split("/").first()
return values().find { value -> value.route.startsWith(findRoute) } return values().find { value -> value.route.startsWith(findRoute) }
} }
fun getEntityRoute(screen: Screen, itemId: Long): String {
return screen.route.replace("{id}", itemId.toString())
}
} }
} }

View File

@ -0,0 +1,21 @@
package ru.ulstu.`is`.pmu.tank.composeui.list
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.cachedIn
import ru.ulstu.`is`.pmu.tank.repository.NationRepository
class NationListViewModel(
nationRepository: NationRepository
) : ViewModel() {
private val pager = Pager(
config = PagingConfig(pageSize = 10),
pagingSourceFactory = {
nationRepository.pagingSource()
}
)
val nationPagingFlow = pager.flow.cachedIn(viewModelScope)
}

View File

@ -1,5 +1,6 @@
package ru.ulstu.`is`.pmu.tank.dao package ru.ulstu.`is`.pmu.tank.dao
import androidx.paging.PagingSource
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Delete import androidx.room.Delete
import androidx.room.Insert import androidx.room.Insert
@ -31,6 +32,9 @@ interface NationDao {
) )
open fun getSimpleNationUid(uid: Long): Flow<Nation?> open fun getSimpleNationUid(uid: Long): Flow<Nation?>
@Query("SELECT * FROM nations")
fun pagingSource(): PagingSource<Int, Nation>
@Insert @Insert
suspend fun insert(nation: Nation) suspend fun insert(nation: Nation)

View File

@ -53,6 +53,10 @@ abstract class AppDatabase : RoomDatabase() {
val nation8 = Nation( 8L, "Китай") val nation8 = Nation( 8L, "Китай")
val nation9 = Nation( 9L, "Япония") val nation9 = Nation( 9L, "Япония")
val nation10 = Nation(10L, "Италия") val nation10 = Nation(10L, "Италия")
val nation11 = Nation(11L, "Бангладеш")
val nation12 = Nation(12L, "Зимбамбве")
val nation13 = Nation(13L, "Гондурас")
val nation14 = Nation(14L, "Майами")
nationDao.insert(nation1) nationDao.insert(nation1)
nationDao.insert(nation2) nationDao.insert(nation2)
@ -64,6 +68,10 @@ abstract class AppDatabase : RoomDatabase() {
nationDao.insert(nation8) nationDao.insert(nation8)
nationDao.insert(nation9) nationDao.insert(nation9)
nationDao.insert(nation10) nationDao.insert(nation10)
nationDao.insert(nation11)
nationDao.insert(nation12)
nationDao.insert(nation13)
nationDao.insert(nation14)
// Levels // Levels
val levelDao = database.levelDao() val levelDao = database.levelDao()

View File

@ -1,5 +1,6 @@
package ru.ulstu.`is`.pmu.tank.repository package ru.ulstu.`is`.pmu.tank.repository
import androidx.paging.PagingSource
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import ru.ulstu.`is`.pmu.tank.model.Nation import ru.ulstu.`is`.pmu.tank.model.Nation
import ru.ulstu.`is`.pmu.tank.model.NationWithTanks import ru.ulstu.`is`.pmu.tank.model.NationWithTanks
@ -8,6 +9,7 @@ interface NationRepository {
suspend fun getAllNations(): List<Nation> suspend fun getAllNations(): List<Nation>
fun getSimpleNation(uid: Long): Flow<Nation?> fun getSimpleNation(uid: Long): Flow<Nation?>
fun getFullNation(uid: Long): Flow<NationWithTanks?> fun getFullNation(uid: Long): Flow<NationWithTanks?>
fun pagingSource(): PagingSource<Int, Nation>
suspend fun insertNation(nation: Nation) suspend fun insertNation(nation: Nation)
suspend fun updateNation(nation: Nation) suspend fun updateNation(nation: Nation)
suspend fun deleteNation(nation: Nation) suspend fun deleteNation(nation: Nation)

View File

@ -1,5 +1,6 @@
package ru.ulstu.`is`.pmu.tank.repository package ru.ulstu.`is`.pmu.tank.repository
import androidx.paging.PagingSource
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import ru.ulstu.`is`.pmu.tank.dao.NationDao import ru.ulstu.`is`.pmu.tank.dao.NationDao
import ru.ulstu.`is`.pmu.tank.model.Nation import ru.ulstu.`is`.pmu.tank.model.Nation
@ -12,6 +13,8 @@ class OfflineNationRepository(private val nationDao: NationDao) : NationReposito
override fun getFullNation(uid: Long): Flow<NationWithTanks?> = nationDao.getNationUid(uid) override fun getFullNation(uid: Long): Flow<NationWithTanks?> = nationDao.getNationUid(uid)
override fun pagingSource(): PagingSource<Int, Nation> = nationDao.pagingSource()
override suspend fun insertNation(nation: Nation) = nationDao.insert(nation) override suspend fun insertNation(nation: Nation) = nationDao.insert(nation)
override suspend fun updateNation(nation: Nation) = nationDao.update(nation) override suspend fun updateNation(nation: Nation) = nationDao.update(nation)

View File

@ -0,0 +1,108 @@
package ru.ulstu.`is`.pmu.tanks.composeui
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.LocalOverscrollConfiguration
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.PaddingValues
import androidx.compose.foundation.layout.fillMaxHeight
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.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.overscroll
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import androidx.paging.compose.collectAsLazyPagingItems
import androidx.paging.compose.itemKey
import ru.ulstu.`is`.pmu.R
import ru.ulstu.`is`.pmu.composeui.navigation.Screen
import ru.ulstu.`is`.pmu.tank.composeui.list.NationListViewModel
import ru.ulstu.`is`.pmu.tank.model.Nation
import ru.ulstu.`is`.pmu.tanks.composeui.image.Dimensions
import ru.ulstu.`is`.pmu.ui.AppViewModelProvider
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun NationList(
navController: NavController,
viewModel: NationListViewModel = viewModel(factory = AppViewModelProvider.Factory)
) {
val nations = viewModel.nationPagingFlow.collectAsLazyPagingItems()
fun handleAddButtonClick() {
val route = Screen.getEntityRoute(Screen.Constructor, 0)
navController.navigate(route)
}
Box(
modifier = Modifier
.fillMaxSize()
.padding(10.dp)
) {
LazyColumn(
verticalArrangement = Arrangement.spacedBy(10.dp),
modifier = Modifier.height(300.dp * nations.itemCount / 5),
) {
items(
count = nations.itemCount,
key = nations.itemKey { it.uid!! }
) {
val nation: Nation = nations[it] ?: return@items
NationBox(
nation = nation,
navController = navController
)
}
}
}
}
@Composable
fun NationBox(
nation: Nation,
navController: NavController
) {
fun handleOnClick() {
val route = Screen.getEntityRoute(Screen.EDIT_NATIONS, nation.uid!!)
navController.navigate(route)
}
Box(
modifier = Modifier
.fillMaxWidth()
.clickable(
onClick = {
handleOnClick()
}
)
.background(
MaterialTheme.colorScheme.surface,
shape = RoundedCornerShape(Dimensions.cornerRadius)
)
.padding(15.dp)
) {
Text(
text = nation.nationName,
color = MaterialTheme.colorScheme.onSurface
)
}
}

View File

@ -8,8 +8,10 @@ import androidx.lifecycle.viewmodel.viewModelFactory
import ru.ulstu.`is`.pmu.TankApplication import ru.ulstu.`is`.pmu.TankApplication
import ru.ulstu.`is`.pmu.tank.composeui.edit.LevelDropDownViewModel import ru.ulstu.`is`.pmu.tank.composeui.edit.LevelDropDownViewModel
import ru.ulstu.`is`.pmu.tank.composeui.edit.NationDropDownViewModel import ru.ulstu.`is`.pmu.tank.composeui.edit.NationDropDownViewModel
import ru.ulstu.`is`.pmu.tank.composeui.edit.NationsListUiState
import ru.ulstu.`is`.pmu.tank.composeui.edit.TankEditViewModel import ru.ulstu.`is`.pmu.tank.composeui.edit.TankEditViewModel
import ru.ulstu.`is`.pmu.tank.composeui.edit.UserEditViewModel import ru.ulstu.`is`.pmu.tank.composeui.edit.UserEditViewModel
import ru.ulstu.`is`.pmu.tank.composeui.list.NationListViewModel
import ru.ulstu.`is`.pmu.tank.composeui.list.TankListViewModel import ru.ulstu.`is`.pmu.tank.composeui.list.TankListViewModel
object AppViewModelProvider { object AppViewModelProvider {
@ -35,6 +37,9 @@ object AppViewModelProvider {
initializer { initializer {
NationDropDownViewModel(tankApplication().container.nationRepository) NationDropDownViewModel(tankApplication().container.nationRepository)
} }
initializer {
NationListViewModel(tankApplication().container.nationRepository)
}
} }
} }

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android">
<svg fill="#000000" height="200px" width="200px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512" xml:space="preserve"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <g> <g> <g> <path d="M511.765,73.235c-0.064-0.533-0.107-1.045-0.256-1.557c-0.085-0.299-0.171-0.576-0.277-0.853 c-0.149-0.405-0.405-0.747-0.597-1.131c-0.235-0.427-0.405-0.875-0.683-1.259c-0.213-0.299-0.469-0.555-0.725-0.832 c-0.32-0.363-0.661-0.661-1.024-0.96c-0.277-0.235-0.512-0.533-0.811-0.747c-0.363-0.256-0.768-0.384-1.173-0.576 c-0.448-0.235-0.896-0.448-1.387-0.619c-0.277-0.107-0.512-0.277-0.811-0.363l-245.333-64c-1.749-0.448-3.627-0.448-5.376,0 l-245.333,64c-0.299,0.085-0.512,0.256-0.811,0.363c-0.491,0.171-0.939,0.384-1.387,0.619c-0.384,0.213-0.811,0.341-1.173,0.576 c-0.32,0.213-0.533,0.512-0.811,0.747c-0.363,0.32-0.704,0.619-1.024,0.96c-0.256,0.277-0.512,0.533-0.725,0.832 c-0.277,0.384-0.448,0.832-0.683,1.259c-0.213,0.384-0.448,0.725-0.597,1.131c-0.107,0.277-0.192,0.555-0.277,0.853 c-0.149,0.512-0.192,1.024-0.256,1.557C0.171,73.725,0,74.173,0,74.664v426.667c0,5.888,4.779,10.667,10.667,10.667h490.667 c5.888,0,10.667-4.779,10.667-10.667V74.664C512,74.173,511.829,73.725,511.765,73.235z M490.667,362.664H373.333 c-5.888,0-10.667,4.779-10.667,10.667v21.333c0,5.888,4.779,10.667,10.667,10.667h117.333v21.333h-160 c-5.888,0-10.667,4.779-10.667,10.667v53.333h-85.333v-53.333c0-5.888-4.779-10.667-10.667-10.667h-42.667 c-5.888,0-10.667,4.779-10.667,10.667v53.333h-21.333v-53.333c0-5.888-4.779-10.667-10.667-10.667H53.333 c-5.888,0-10.667,4.779-10.667,10.667v53.333H21.333V341.331h469.333V362.664z M490.667,277.331H21.333v-21.333h469.333V277.331z M490.667,191.997H21.333v-21.333h469.333V191.997z M490.667,106.664H21.333V85.331h469.333V106.664z"></path> <path d="M53.333,405.331h64c5.888,0,10.667-4.779,10.667-10.667v-21.333c0-5.888-4.779-10.667-10.667-10.667h-64 c-5.888,0-10.667,4.779-10.667,10.667v21.333C42.667,400.552,47.445,405.331,53.333,405.331z"></path> </g> </g> </g> </g></svg>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M18.41,5.8L17.2,4.59c-0.78,-0.78 -2.05,-0.78 -2.83,0l-2.68,2.68L3,15.96V20h4.04l8.74,-8.74 2.63,-2.63c0.79,-0.78 0.79,-2.05 0,-2.83zM6.21,18H5v-1.21l8.66,-8.66 1.21,1.21L6.21,18zM11,20l4,-4h6v4H11z"/>
</vector>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:pathData="M2,8L14,8"
android:strokeLineJoin="round"
android:strokeWidth="3"
android:fillColor="#00000000"
android:strokeColor="#FFFFFF"
android:strokeLineCap="round"/>
<path
android:pathData="M8,2L8,14"
android:strokeLineJoin="round"
android:strokeWidth="3"
android:fillColor="#00000000"
android:strokeColor="#FFFFFF"
android:strokeLineCap="round"/>
</vector>

View File

@ -26,6 +26,7 @@
<string name="t_34_85">T-34-85</string> <string name="t_34_85">T-34-85</string>
<string name="sherman">Sherman</string> <string name="sherman">Sherman</string>
<string name="tiger_1">Tiger 1</string> <string name="tiger_1">Tiger 1</string>
<string name="nation">Нации</string>
<string name="about_text"> <string name="about_text">
<p>Это текст <b>о нас</b>!</p>\n\n <p>Это текст <b>о нас</b>!</p>\n\n
<p>Здесь могла быть Ваша реклама!</p>\n\n <p>Здесь могла быть Ваша реклама!</p>\n\n