From 4cfdbb45cb5d7e2aab090d719d5abd0782ddf6fc Mon Sep 17 00:00:00 2001 From: Niket <52085669+nikeight@users.noreply.github.com> Date: Mon, 26 Aug 2024 02:30:45 +0530 Subject: [PATCH] Make app sync with DB (#4) * add: Passing BoardId btw navGraphs * fix: Update Card details functionality * add: Dialog for updating the List title. * fix: Create Card Flow with selected boardId and Listid * random Images Cover for boards. --- .../jettaskboard/navigation/JtbNavHost.kt | 15 +- core/common/build.gradle.kts | 1 + .../jettaskboard/CreateformDropDown.kt | 175 +++++++++++++++-- .../jetapps/jettaskboard/di/DatabaseModule.kt | 9 +- .../jettaskboard/local/dao/BoardDao.kt | 3 +- .../jetapps/jettaskboard/local/dao/CardDao.kt | 3 + .../jettaskboard/local/dao/DashboardDao.kt | 8 +- .../local/database/JtbDatabase.kt | 4 +- .../jettaskboard/local/entity/BoardEntity.kt | 4 +- .../jettaskboard/local/entity/CardEntity.kt | 6 +- .../jettaskboard/local/entity/ListEntity.kt | 4 +- .../local/source/DatabaseSource.kt | 5 +- .../local/source/DatabaseSourceImpl.kt | 18 +- .../jettaskboard/mapper/BoardMapper.kt | 2 +- .../jetapps/jettaskboard/mapper/CardMapper.kt | 40 +++- .../jetapps/jettaskboard/mapper/ListMapper.kt | 4 +- .../model/db/BoardListCardLabelEntity.kt | 4 +- .../jettaskboard/repo/BoardRepoImpl.kt | 38 ++-- .../jetapps/jettaskboard/repo/CardRepoImpl.kt | 9 +- .../jettaskboard/repo/DashboardRepoImpl.kt | 2 +- .../jettaskboard/components/TaskCard.kt | 49 +++-- .../jettaskboard/model/BoardListModel.kt | 14 +- .../jetapps/jettaskboard/model/BoardModel.kt | 25 ++- .../jetapps/jettaskboard/model/CardModel.kt | 41 +++- .../jetapps/jettaskboard/model/ListModel.kt | 8 +- .../jetapps/jettaskboard/repo/BoardRepo.kt | 2 +- .../com/jetapps/jettaskboard/repo/CardRepo.kt | 4 + .../jettaskboard/repo/DashboardRepo.kt | 2 +- .../jettaskboard/usecase/FetchCardsUseCase.kt | 4 +- .../usecase/board/FetchCardDetailsUseCase.kt | 10 + .../usecase/board/GetBoardDetailsUseCase.kt | 7 +- .../FetchAllListsRelatedToBoardUseCase.kt | 4 +- .../jetapps/jettaskboard/CardDetailsScreen.kt | 8 +- .../com/jetapps/jettaskboard/CardViewModel.kt | 177 ++++++++++++++---- .../jetapps/jettaskboard/CreateCardScreen.kt | 53 +++--- .../CardDetailsMainPane.kt | 64 ++++++- .../components/EditTextCard.kt | 29 ++- .../components/MotionTopBar.kt | 9 +- .../jettaskboard/navigation/CardNav.kt | 34 +++- .../jettaskboard/state/CardDetailState.kt | 11 -- .../jettaskboard/state/CreateCardStates.kt | 14 ++ .../jettaskboard/uimodel/CardDetail.kt | 6 +- .../jettaskboard/DashboardDetailPane.kt | 46 +++-- .../jetapps/jettaskboard/DashboardMainPane.kt | 61 +++--- .../jetapps/jettaskboard/DashboardScreen.kt | 18 +- .../jettaskboard/DashboardViewModel.kt | 17 +- .../jettaskboard/navigation/DashboardNav.kt | 2 +- .../com/jetapps/jettaskboard/board/Board.kt | 146 +++++++++++++-- .../jettaskboard/board/TaskBoardScreen.kt | 9 +- .../createboard/CreateBoardScreen.kt | 24 ++- .../components/CreateFormEditText.kt | 2 +- .../jettaskboard/navigation/CreateBoardNav.kt | 4 +- .../jettaskboard/navigation/TaskBoardNav.kt | 18 +- .../jettaskboard/vm/TaskBoardViewModel.kt | 69 +++---- 54 files changed, 997 insertions(+), 348 deletions(-) create mode 100644 core/domain/src/main/java/com/jetapps/jettaskboard/usecase/board/FetchCardDetailsUseCase.kt delete mode 100644 feature/card/src/main/java/com/jetapps/jettaskboard/state/CardDetailState.kt create mode 100644 feature/card/src/main/java/com/jetapps/jettaskboard/state/CreateCardStates.kt diff --git a/app/src/main/java/com/jetapps/jettaskboard/navigation/JtbNavHost.kt b/app/src/main/java/com/jetapps/jettaskboard/navigation/JtbNavHost.kt index 93c3530..eaa617b 100644 --- a/app/src/main/java/com/jetapps/jettaskboard/navigation/JtbNavHost.kt +++ b/app/src/main/java/com/jetapps/jettaskboard/navigation/JtbNavHost.kt @@ -47,10 +47,10 @@ fun JtbNavHost( ) { dashboardGraph( isExpandedScreen = isExpandedScreen, - navigateToTaskBoard = { + navigateToTaskBoard = { boardId -> onNavigateToDestination( TaskBoardDestination, - TaskBoardDestination.route + TaskBoardDestination.route + "/$boardId" ) }, navigateToCreateCard = { @@ -77,10 +77,10 @@ fun JtbNavHost( taskBoardGraph( isExpandedScreen = isExpandedScreen, onBackClick = onBackClick, - navigateToCreateCard = { + navigateToCreateCard = { boardId, listId, cardId -> onNavigateToDestination( CardDetailsDestination, - CardDetailsDestination.route + CardDetailsDestination.route + "/$boardId" + "/$listId" + "/$cardId" ) }, navigateToChangeBackgroundScreen = { @@ -98,10 +98,13 @@ fun JtbNavHost( createBoardGraph( onBackClick = onBackClick, - navigateToBoardRoute = { + navigateToBoardRoute = { passedId -> + // Clear the Create Board Screen then only + // Navigate to the TaskBoard Screen + navController.popBackStack() onNavigateToDestination( TaskBoardDestination, - TaskBoardDestination.route, + TaskBoardDestination.route + "/$passedId", ) } ) diff --git a/core/common/build.gradle.kts b/core/common/build.gradle.kts index 99c98fd..8f4cdaa 100644 --- a/core/common/build.gradle.kts +++ b/core/common/build.gradle.kts @@ -51,6 +51,7 @@ dependencies { /* Android Designing and layout */ implementation(platform(libs.androidx.compose.bom)) implementation(libs.compose.material) + implementation(project(":core:domain")) // implementation("androidx.test.ext:junit-ktx:1.2.1") /* Testing */ diff --git a/core/common/src/main/java/com/jetapps/jettaskboard/CreateformDropDown.kt b/core/common/src/main/java/com/jetapps/jettaskboard/CreateformDropDown.kt index 7821a9e..ce5a791 100644 --- a/core/common/src/main/java/com/jetapps/jettaskboard/CreateformDropDown.kt +++ b/core/common/src/main/java/com/jetapps/jettaskboard/CreateformDropDown.kt @@ -37,20 +37,23 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.toSize +import com.jetapps.jettaskboard.model.BoardModel +import com.jetapps.jettaskboard.model.ListModel @Composable -fun CreateFormDropDown( +fun CreateBoardListFormDropDown( headingText: String, modifier: Modifier = Modifier, - contentMap: Map, - initiallyOpened: Boolean = false + contentMap: Map, + initiallyOpened: Boolean = false, + onListSelected: (ListModel) -> Unit, ) { var isOpen by remember { mutableStateOf(initiallyOpened) } var dropDownWidth by remember { mutableStateOf(Size.Zero) } var selectMenuItem by remember { - mutableStateOf("") + mutableStateOf(null) } var selectedMenuItemHeading by remember { @@ -61,8 +64,7 @@ fun CreateFormDropDown( Column( modifier = Modifier - .fillMaxWidth() - .padding(16.dp), + .fillMaxWidth(), horizontalAlignment = Alignment.Start ) { Column( @@ -127,6 +129,7 @@ fun CreateFormDropDown( isOpen = !isOpen selectMenuItem = itemValue selectedMenuItemHeading = itemKey + onListSelected(itemValue) }, modifier = Modifier .background(color = MaterialTheme.colors.background) @@ -147,7 +150,7 @@ fun CreateFormDropDown( Text( modifier = modifier .padding(all = 4.dp), - text = itemValue, + text = itemValue.title ?: "", fontWeight = FontWeight.Medium, fontSize = 12.sp ) @@ -159,16 +162,14 @@ fun CreateFormDropDown( } } - selectMenuItem.let { selectedItem -> - if (selectedItem.isNotEmpty()) { - Spacer(modifier = Modifier.height(8.dp)) + selectMenuItem?.let { item -> + Spacer(modifier = Modifier.height(8.dp)) - Text( - text = selectMenuItem.ifEmpty { " " }, - fontSize = 12.sp, - modifier = Modifier.padding(8.dp) - ) - } + Text( + text = item.title ?: " ", + fontSize = 12.sp, + modifier = Modifier.padding(8.dp) + ) } } } @@ -177,15 +178,16 @@ fun CreateFormDropDown( fun CreateBoardDropDown( headingText: String, modifier: Modifier = Modifier, - contentMap: Map, - initiallyOpened: Boolean = false + contentMap: Map, + initiallyOpened: Boolean = false, + onBoardSelected: (BoardModel) -> Unit, ) { var isOpen by remember { mutableStateOf(initiallyOpened) } var dropDownWidth by remember { mutableStateOf(Size.Zero) } var selectMenuItem by remember { - mutableStateOf("") + mutableStateOf(null) } Column( @@ -217,7 +219,7 @@ fun CreateBoardDropDown( } ) { Text( - text = selectMenuItem.ifEmpty { "Select from dropdown.. " }, + text = selectMenuItem?.title ?: "Select from dropdown.. ", color = Color.White, fontSize = 18.sp, modifier = Modifier @@ -255,6 +257,7 @@ fun CreateBoardDropDown( onClick = { isOpen = !isOpen selectMenuItem = itemValue + onBoardSelected(itemValue) }, modifier = Modifier .background(color = MaterialTheme.colors.background) @@ -270,6 +273,126 @@ fun CreateBoardDropDown( shape = RoundedCornerShape(4.dp), backgroundColor = itemKey as Color ) {} + if (contentMap.values.isNotEmpty()) { + Text( + modifier = modifier + .padding(all = 4.dp), + text = itemValue.title, + fontWeight = FontWeight.Medium, + fontSize = 12.sp + ) + } + } + } + } + } + } +} + +@Composable +fun CreateVisibilityFormDropDown( + headingText: String, + modifier: Modifier = Modifier, + contentMap: Map, + initiallyOpened: Boolean = false +) { + var isOpen by remember { mutableStateOf(initiallyOpened) } + + var dropDownWidth by remember { mutableStateOf(Size.Zero) } + + var selectMenuItem by remember { + mutableStateOf("") + } + + var selectedMenuItemHeading by remember { + mutableStateOf( + "" + ) + } + + Column( + modifier = Modifier + .fillMaxWidth(), + horizontalAlignment = Alignment.Start + ) { + Column( + modifier = Modifier.clickable { isOpen = !isOpen } + ) { + Text( + modifier = modifier + .padding(horizontal = 8.dp), + text = headingText, + fontWeight = FontWeight.SemiBold, + fontSize = 12.sp + ) + + Row( + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .padding(8.dp) + .fillMaxWidth() + .background(Color.Transparent) + .onGloballyPositioned { coordinates -> + dropDownWidth = coordinates.size.toSize() + } + ) { + Text( + text = selectedMenuItemHeading.ifEmpty { "Select from dropdown.. " }, + color = Color.White, + fontSize = 18.sp, + modifier = Modifier + ) + Icon( + imageVector = if (!isOpen) { + Icons.Default.KeyboardArrowDown + } else { + Icons.Default.KeyboardArrowUp + }, + contentDescription = "Open or close the drop down", + tint = Color.White, + modifier = Modifier + ) + } + } + + Divider( + color = MaterialTheme.colors.onBackground + ) + + DropdownMenu( + expanded = isOpen, + onDismissRequest = { isOpen = false }, + modifier = Modifier + .width( + with(LocalDensity.current) { + dropDownWidth.width.toDp() + } + ) + .padding(horizontal = 8.dp) + ) { + contentMap.forEach { (itemKey, itemValue) -> + DropdownMenuItem( + onClick = { + isOpen = !isOpen + selectMenuItem = itemValue + selectedMenuItemHeading = itemKey + }, + modifier = Modifier + .background(color = MaterialTheme.colors.background) + ) { + Column( + modifier = Modifier + .padding(8.dp), + horizontalAlignment = Alignment.Start + ) { + Text( + modifier = modifier + .padding(all = 4.dp), + text = itemKey, + fontWeight = FontWeight.Bold, + fontSize = 14.sp + ) if (contentMap.values.isNotEmpty()) { Text( modifier = modifier @@ -279,9 +402,21 @@ fun CreateBoardDropDown( fontSize = 12.sp ) } + + Divider() } } } } + + selectMenuItem.let { item -> + Spacer(modifier = Modifier.height(8.dp)) + + Text( + text = item, + fontSize = 12.sp, + modifier = Modifier.padding(8.dp) + ) + } } } diff --git a/core/data/src/main/java/com/jetapps/jettaskboard/di/DatabaseModule.kt b/core/data/src/main/java/com/jetapps/jettaskboard/di/DatabaseModule.kt index c92e3c4..2f39b61 100644 --- a/core/data/src/main/java/com/jetapps/jettaskboard/di/DatabaseModule.kt +++ b/core/data/src/main/java/com/jetapps/jettaskboard/di/DatabaseModule.kt @@ -2,6 +2,7 @@ package com.jetapps.jettaskboard.di import android.content.Context import androidx.room.Room +import com.jetapps.jettaskboard.local.dao.BoardDao import com.jetapps.jettaskboard.local.dao.DashboardDao import com.jetapps.jettaskboard.local.dao.CardDao import com.jetapps.jettaskboard.local.dao.LabelDao @@ -21,7 +22,7 @@ object DatabaseModule { @Provides @Singleton - fun provideDatabase(@ApplicationContext context: Context) : JtbDatabase { + fun provideDatabase(@ApplicationContext context: Context): JtbDatabase { return Room.databaseBuilder( context, JtbDatabase::class.java, @@ -41,7 +42,11 @@ object DatabaseModule { @Provides @Singleton - fun providesBoardDao(database: JtbDatabase): DashboardDao = database.boardDao() + fun providesDashBoardDao(database: JtbDatabase): DashboardDao = database.dashboardDao() + + @Provides + @Singleton + fun providesBoardDao(database: JtbDatabase): BoardDao = database.boardDao() @Provides @Singleton diff --git a/core/data/src/main/java/com/jetapps/jettaskboard/local/dao/BoardDao.kt b/core/data/src/main/java/com/jetapps/jettaskboard/local/dao/BoardDao.kt index e4fdbd5..551e3cd 100644 --- a/core/data/src/main/java/com/jetapps/jettaskboard/local/dao/BoardDao.kt +++ b/core/data/src/main/java/com/jetapps/jettaskboard/local/dao/BoardDao.kt @@ -6,11 +6,12 @@ import androidx.room.Transaction import com.jetapps.jettaskboard.local.entity.CardEntity import com.jetapps.jettaskboard.local.entity.ListEntity import com.jetapps.jettaskboard.model.db.BoardWithLists +import kotlinx.coroutines.flow.Flow @Dao interface BoardDao { @Transaction @Query("SELECT * FROM boardTable WHERE boardId = :boardId") - fun getBoardWithListsAndCards(boardId: Int): BoardWithLists + fun getBoardWithListsAndCards(boardId: Long): Flow } \ No newline at end of file diff --git a/core/data/src/main/java/com/jetapps/jettaskboard/local/dao/CardDao.kt b/core/data/src/main/java/com/jetapps/jettaskboard/local/dao/CardDao.kt index 9f8b35b..d4eee51 100644 --- a/core/data/src/main/java/com/jetapps/jettaskboard/local/dao/CardDao.kt +++ b/core/data/src/main/java/com/jetapps/jettaskboard/local/dao/CardDao.kt @@ -15,6 +15,9 @@ interface CardDao { @Query("SELECT * FROM cardTable") fun getAllCards(): Flow> + @Query("SELECT * FROM cardTable where cardId = :cardId") + fun fetchCardDetails(cardId: Long): CardEntity + @Insert(onConflict = OnConflictStrategy.REPLACE) fun insertAllCards(cards: List) diff --git a/core/data/src/main/java/com/jetapps/jettaskboard/local/dao/DashboardDao.kt b/core/data/src/main/java/com/jetapps/jettaskboard/local/dao/DashboardDao.kt index e70cccd..9839317 100644 --- a/core/data/src/main/java/com/jetapps/jettaskboard/local/dao/DashboardDao.kt +++ b/core/data/src/main/java/com/jetapps/jettaskboard/local/dao/DashboardDao.kt @@ -5,11 +5,9 @@ import androidx.room.Delete import androidx.room.Insert import androidx.room.OnConflictStrategy import androidx.room.Query -import androidx.room.Transaction import androidx.room.Update import com.jetapps.jettaskboard.local.entity.BoardEntity import com.jetapps.jettaskboard.local.entity.ListEntity -import com.jetapps.jettaskboard.model.db.BoardWithLists import kotlinx.coroutines.flow.Flow @Dao @@ -18,10 +16,6 @@ interface DashboardDao { @Query("SELECT * FROM boardTable") fun getAllBoards(): Flow> - @Transaction - @Query("SELECT * FROM boardTable WHERE boardId = :boardId") - fun getBoardDetails(boardId: Int): Flow - @Insert(onConflict = OnConflictStrategy.REPLACE) fun insertBoard(board: BoardEntity) @@ -38,5 +32,5 @@ interface DashboardDao { fun getAllLists(): List @Query("SELECT * FROM listTable where boardId = :boardId") - fun getAllBoardRelatedLists(boardId: Int): List + fun getAllBoardRelatedLists(boardId: Long): List } diff --git a/core/data/src/main/java/com/jetapps/jettaskboard/local/database/JtbDatabase.kt b/core/data/src/main/java/com/jetapps/jettaskboard/local/database/JtbDatabase.kt index b029848..ddb3e34 100644 --- a/core/data/src/main/java/com/jetapps/jettaskboard/local/database/JtbDatabase.kt +++ b/core/data/src/main/java/com/jetapps/jettaskboard/local/database/JtbDatabase.kt @@ -2,6 +2,7 @@ package com.jetapps.jettaskboard.local.database import androidx.room.Database import androidx.room.RoomDatabase +import com.jetapps.jettaskboard.local.dao.BoardDao import com.jetapps.jettaskboard.local.dao.DashboardDao import com.jetapps.jettaskboard.local.dao.CardDao import com.jetapps.jettaskboard.local.dao.LabelDao @@ -28,7 +29,8 @@ import com.jetapps.jettaskboard.model.db.ListWithCardCrossRef exportSchema = false ) abstract class JtbDatabase : RoomDatabase() { - abstract fun boardDao(): DashboardDao + abstract fun dashboardDao(): DashboardDao + abstract fun boardDao(): BoardDao abstract fun listDao(): ListDao abstract fun cardDao(): CardDao abstract fun labelDao(): LabelDao diff --git a/core/data/src/main/java/com/jetapps/jettaskboard/local/entity/BoardEntity.kt b/core/data/src/main/java/com/jetapps/jettaskboard/local/entity/BoardEntity.kt index 0832919..afe2eae 100644 --- a/core/data/src/main/java/com/jetapps/jettaskboard/local/entity/BoardEntity.kt +++ b/core/data/src/main/java/com/jetapps/jettaskboard/local/entity/BoardEntity.kt @@ -7,8 +7,8 @@ import androidx.room.PrimaryKey tableName = "boardTable" ) data class BoardEntity( - @PrimaryKey - val boardId: Int, + @PrimaryKey(autoGenerate = false) + val boardId: Long = 0, val title: String, val description: String, val isFav : Int, diff --git a/core/data/src/main/java/com/jetapps/jettaskboard/local/entity/CardEntity.kt b/core/data/src/main/java/com/jetapps/jettaskboard/local/entity/CardEntity.kt index 53ce212..c0724b8 100644 --- a/core/data/src/main/java/com/jetapps/jettaskboard/local/entity/CardEntity.kt +++ b/core/data/src/main/java/com/jetapps/jettaskboard/local/entity/CardEntity.kt @@ -9,13 +9,13 @@ import androidx.room.PrimaryKey ) data class CardEntity( @PrimaryKey(autoGenerate = true) - val cardId: Int, + val cardId: Long = 0, val title: String, val description: String?, @ColumnInfo(name = "column_image_url") val coverImageUrl: String?, - val boardId: Int, - val listId: Int, + val boardId: Long, + val listId: Long, @ColumnInfo(name = "author_id") val authorId: String?, @ColumnInfo(name = "start_date") diff --git a/core/data/src/main/java/com/jetapps/jettaskboard/local/entity/ListEntity.kt b/core/data/src/main/java/com/jetapps/jettaskboard/local/entity/ListEntity.kt index 6f49d60..35ce340 100644 --- a/core/data/src/main/java/com/jetapps/jettaskboard/local/entity/ListEntity.kt +++ b/core/data/src/main/java/com/jetapps/jettaskboard/local/entity/ListEntity.kt @@ -8,7 +8,7 @@ import androidx.room.PrimaryKey ) data class ListEntity( @PrimaryKey(autoGenerate = true) - val listId: Int = 0, + val listId: Long = 0, val title: String, - val boardId: Int + val boardId: Long ) diff --git a/core/data/src/main/java/com/jetapps/jettaskboard/local/source/DatabaseSource.kt b/core/data/src/main/java/com/jetapps/jettaskboard/local/source/DatabaseSource.kt index 9f30e1a..4ebfae1 100644 --- a/core/data/src/main/java/com/jetapps/jettaskboard/local/source/DatabaseSource.kt +++ b/core/data/src/main/java/com/jetapps/jettaskboard/local/source/DatabaseSource.kt @@ -10,10 +10,10 @@ import kotlinx.coroutines.flow.Flow interface DatabaseSource { suspend fun createBoard(boardEntity: BoardEntity) - suspend fun getBoard(boardId : Int) : Flow + suspend fun getBoard(boardId : Long) : Flow suspend fun getBoards() : Flow> suspend fun getAllLists() : List - suspend fun getAllListsRelatedToBoard(boardId : Int) : List + suspend fun getAllListsRelatedToBoard(boardId : Long) : List suspend fun updateCard(cardEntity: CardEntity) suspend fun createCard(cardEntity: CardEntity) suspend fun deleteCard(cardEntity: CardEntity) @@ -21,4 +21,5 @@ interface DatabaseSource { suspend fun deleteList(listEntity: ListEntity) suspend fun createLabel(labelEntity: LabelEntity) suspend fun deleteLabel(labelEntity: LabelEntity) + suspend fun getCardDetails(cardId : Long) : CardEntity } \ No newline at end of file diff --git a/core/data/src/main/java/com/jetapps/jettaskboard/local/source/DatabaseSourceImpl.kt b/core/data/src/main/java/com/jetapps/jettaskboard/local/source/DatabaseSourceImpl.kt index 71a23c9..16ad30b 100644 --- a/core/data/src/main/java/com/jetapps/jettaskboard/local/source/DatabaseSourceImpl.kt +++ b/core/data/src/main/java/com/jetapps/jettaskboard/local/source/DatabaseSourceImpl.kt @@ -1,5 +1,6 @@ package com.jetapps.jettaskboard.local.source +import com.jetapps.jettaskboard.local.dao.BoardDao import com.jetapps.jettaskboard.local.dao.CardDao import com.jetapps.jettaskboard.local.dao.DashboardDao import com.jetapps.jettaskboard.local.dao.LabelDao @@ -17,6 +18,7 @@ import javax.inject.Inject class DatabaseSourceImpl @Inject constructor( private val dashboardDao: DashboardDao, + private val boardDao: BoardDao, private val cardDao: CardDao, private val listDao: ListDao, private val labelDao: LabelDao @@ -26,8 +28,10 @@ class DatabaseSourceImpl @Inject constructor( dashboardDao.insertBoard(boardEntity) } - override suspend fun getBoard(boardId: Int): Flow { - return dashboardDao.getBoardDetails(boardId) + override suspend fun getBoard(boardId: Long): Flow { + return withContext(Dispatchers.IO) { + boardDao.getBoardWithListsAndCards(boardId) + } } override suspend fun getBoards(): Flow> { @@ -38,12 +42,14 @@ class DatabaseSourceImpl @Inject constructor( return dashboardDao.getAllLists() } - override suspend fun getAllListsRelatedToBoard(boardId: Int): List { + override suspend fun getAllListsRelatedToBoard(boardId: Long): List { return dashboardDao.getAllBoardRelatedLists(boardId) } override suspend fun updateCard(cardEntity: CardEntity) { - cardDao.updateCard(cardEntity) + withContext(Dispatchers.IO) { + cardDao.updateCard(cardEntity) + } } override suspend fun createCard(cardEntity: CardEntity) { @@ -74,5 +80,7 @@ class DatabaseSourceImpl @Inject constructor( labelDao.deleteLabel(labelEntity) } - + override suspend fun getCardDetails(cardId: Long): CardEntity { + return cardDao.fetchCardDetails(cardId) + } } \ No newline at end of file diff --git a/core/data/src/main/java/com/jetapps/jettaskboard/mapper/BoardMapper.kt b/core/data/src/main/java/com/jetapps/jettaskboard/mapper/BoardMapper.kt index 361e386..d3bf540 100644 --- a/core/data/src/main/java/com/jetapps/jettaskboard/mapper/BoardMapper.kt +++ b/core/data/src/main/java/com/jetapps/jettaskboard/mapper/BoardMapper.kt @@ -10,7 +10,7 @@ class BoardMapper @Inject constructor() : EntityMapper boardId = entity.id ?: 0, title = entity.title, description = entity.title, - workSpaceId = entity.id ?: 0, + workSpaceId = entity.id?.toInt() ?: 0, isFav = 0 ) } diff --git a/core/data/src/main/java/com/jetapps/jettaskboard/mapper/CardMapper.kt b/core/data/src/main/java/com/jetapps/jettaskboard/mapper/CardMapper.kt index 20956f5..a3476ae 100644 --- a/core/data/src/main/java/com/jetapps/jettaskboard/mapper/CardMapper.kt +++ b/core/data/src/main/java/com/jetapps/jettaskboard/mapper/CardMapper.kt @@ -6,7 +6,7 @@ import javax.inject.Inject class CardMapper @Inject constructor( private val labelMapper: LabelMapper, -) : EntityMapper { +) : EntityMapper { override fun mapToDomain(entity: CardEntity): CardModel { return CardModel( @@ -25,15 +25,35 @@ class CardMapper @Inject constructor( override fun mapToData(model: CardModel): CardEntity { return CardEntity( - model.id, - model.title, - model.description, - model.coverImageUrl, - model.boardId, - model.listId, - model.authorId, - model.startDate, - model.dueDate + title = model.title, + description = model.description, + coverImageUrl = model.coverImageUrl, + boardId = model.boardId, + listId = model.listId, + authorId = model.authorId, + startDate = model.startDate, + dueDate = model.dueDate ) } } + +/** + * When creating a new Card, we don't want to pass the Id, + * But for updating the card we need Id + * Creating a extension function for updating the card and + * Mapper Class for new card creation. + */ +fun CardModel.mapToDomain(): CardEntity { + return CardEntity( + cardId = id, + title = title, + description = description, + coverImageUrl = coverImageUrl, + boardId = boardId, + listId = listId, + authorId = authorId, + startDate = startDate, + dueDate = dueDate + ) +} + diff --git a/core/data/src/main/java/com/jetapps/jettaskboard/mapper/ListMapper.kt b/core/data/src/main/java/com/jetapps/jettaskboard/mapper/ListMapper.kt index 1b5b41a..e8e0be5 100644 --- a/core/data/src/main/java/com/jetapps/jettaskboard/mapper/ListMapper.kt +++ b/core/data/src/main/java/com/jetapps/jettaskboard/mapper/ListMapper.kt @@ -9,8 +9,8 @@ class ListMapper @Inject constructor( ) : EntityMapper { override fun mapToDomain(entity: ListModel): ListEntity { return ListEntity( - title = entity.title, - boardId = entity.boardId, + title = entity.title ?: "", + boardId = entity.boardId ?: 0, ) } diff --git a/core/data/src/main/java/com/jetapps/jettaskboard/model/db/BoardListCardLabelEntity.kt b/core/data/src/main/java/com/jetapps/jettaskboard/model/db/BoardListCardLabelEntity.kt index cd6cdbb..096327f 100644 --- a/core/data/src/main/java/com/jetapps/jettaskboard/model/db/BoardListCardLabelEntity.kt +++ b/core/data/src/main/java/com/jetapps/jettaskboard/model/db/BoardListCardLabelEntity.kt @@ -22,7 +22,7 @@ data class ListWithCardCrossRef( * but many list can't have n boards */ data class BoardWithLists( - @Embedded val boardEntity: BoardEntity, + @Embedded val boardEntity: BoardEntity?, @Relation( entity = ListEntity::class, parentColumn = "boardId", @@ -38,7 +38,7 @@ data class BoardWithLists( * but many cards can't have n lists. */ data class ListWithCards( - @Embedded val columnList: ListEntity, + @Embedded val columnList: ListEntity?, @Relation( parentColumn = "listId", entityColumn = "listId", diff --git a/core/data/src/main/java/com/jetapps/jettaskboard/repo/BoardRepoImpl.kt b/core/data/src/main/java/com/jetapps/jettaskboard/repo/BoardRepoImpl.kt index 0b632ac..2caa594 100644 --- a/core/data/src/main/java/com/jetapps/jettaskboard/repo/BoardRepoImpl.kt +++ b/core/data/src/main/java/com/jetapps/jettaskboard/repo/BoardRepoImpl.kt @@ -6,11 +6,13 @@ import com.jetapps.jettaskboard.local.source.DatabaseSource import com.jetapps.jettaskboard.mapper.BoardMapper import com.jetapps.jettaskboard.mapper.CardMapper import com.jetapps.jettaskboard.mapper.ListMapper +import com.jetapps.jettaskboard.mapper.mapToDomain import com.jetapps.jettaskboard.model.BoardWithListAndCard import com.jetapps.jettaskboard.model.CardModel import com.jetapps.jettaskboard.model.ListModel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.retry import javax.inject.Inject class BoardRepoImpl @Inject constructor( @@ -34,24 +36,26 @@ class BoardRepoImpl @Inject constructor( * This task can be expensive as it loads lots of data once and Map each property * Need to explore more and check for better solution. */ - override suspend fun getBoardDetails(boardId: Int): Flow { + override suspend fun getBoardDetails(boardId: Long): Flow { return databaseSource.getBoard(boardId).map { boardWithLists -> Log.d("DAO_RELATION", "getBoardDetails: $boardWithLists") - BoardWithListAndCard( - boardId = boardWithLists.boardEntity.boardId, - boardTitle = boardWithLists.boardEntity.title, - isFav = boardWithLists.boardEntity.isFav == 1, - listModel = boardWithLists.boardList.map { listWithCards -> - ListModel( - listId = listWithCards.columnList.listId, - title = listWithCards.columnList.title, - cards = listWithCards.cardList.map { cardEntity -> - cardMapper.mapToDomain(cardEntity) - }.toMutableList(), - boardId = listWithCards.columnList.boardId - ) - } - ) + boardWithLists?.run { + BoardWithListAndCard( + boardId = boardEntity?.boardId, + boardTitle = boardEntity?.title, + isFav = boardEntity?.isFav == 1, + listModel = boardList.map { listWithCards -> + ListModel( + listId = listWithCards.columnList?.listId, + title = listWithCards.columnList?.title, + cards = listWithCards.cardList.map { cardEntity -> + cardMapper.mapToDomain(cardEntity) + }.toMutableList(), + boardId = listWithCards.columnList?.boardId + ) + } + ) + } } } @@ -64,7 +68,7 @@ class BoardRepoImpl @Inject constructor( } override suspend fun updateCard(cardModel: CardModel) { - databaseSource.updateCard(cardMapper.mapToData(cardModel)) + databaseSource.updateCard(cardModel.mapToDomain()) } override suspend fun deleteCard(cardModel: CardModel) { diff --git a/core/data/src/main/java/com/jetapps/jettaskboard/repo/CardRepoImpl.kt b/core/data/src/main/java/com/jetapps/jettaskboard/repo/CardRepoImpl.kt index e8386f3..4c0f963 100644 --- a/core/data/src/main/java/com/jetapps/jettaskboard/repo/CardRepoImpl.kt +++ b/core/data/src/main/java/com/jetapps/jettaskboard/repo/CardRepoImpl.kt @@ -8,8 +8,9 @@ import com.jetapps.jettaskboard.model.CardModel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.withContext +import javax.inject.Inject -class CardRepoImpl( +class CardRepoImpl @Inject constructor( private val cardDao: CardDao, private val entityMapper: EntityMapper, private val dispatcherProvider: CoroutineDispatcherProvider @@ -28,4 +29,10 @@ class CardRepoImpl( cardEntityList.map { entityMapper.mapToDomain(it) } } } + + override suspend fun fetchCardDetails(cardId: Long): CardModel { + return withContext(dispatcherProvider.io) { + entityMapper.mapToDomain(cardDao.fetchCardDetails(cardId)) + } + } } diff --git a/core/data/src/main/java/com/jetapps/jettaskboard/repo/DashboardRepoImpl.kt b/core/data/src/main/java/com/jetapps/jettaskboard/repo/DashboardRepoImpl.kt index b299dc0..d1889d3 100644 --- a/core/data/src/main/java/com/jetapps/jettaskboard/repo/DashboardRepoImpl.kt +++ b/core/data/src/main/java/com/jetapps/jettaskboard/repo/DashboardRepoImpl.kt @@ -51,7 +51,7 @@ class DashboardRepoImpl @Inject constructor( } } - override suspend fun fetchListsFromRelatedBoard(boardId: Int): List { + override suspend fun fetchListsFromRelatedBoard(boardId: Long): List { return withContext(Dispatchers.IO) { databaseSource.getAllListsRelatedToBoard(boardId).map { entity -> listMapper.mapToData(entity) diff --git a/core/designsystem/src/main/java/com/jetapps/jettaskboard/components/TaskCard.kt b/core/designsystem/src/main/java/com/jetapps/jettaskboard/components/TaskCard.kt index d842eab..9513393 100644 --- a/core/designsystem/src/main/java/com/jetapps/jettaskboard/components/TaskCard.kt +++ b/core/designsystem/src/main/java/com/jetapps/jettaskboard/components/TaskCard.kt @@ -30,6 +30,7 @@ import androidx.compose.ui.unit.sp import coil.compose.rememberAsyncImagePainter import com.jetapps.jettaskboard.core.designsystem.R import com.jetapps.jettaskboard.model.CardModel +import com.jetapps.jettaskboard.model.labelModelList @Composable fun TaskCard( @@ -67,24 +68,42 @@ fun TaskCard( Column( modifier = Modifier.padding(8.dp) ) { - card.labels.let { cardLabels -> - Row( - modifier = Modifier - .fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(4.dp) - ) { - for (label in cardLabels) { - Box( - modifier = Modifier - .width(32.dp) - .height(16.dp) - .clip(RoundedCornerShape(10)) - .background(color = Color(label.labelColor)) - ) - } + // Todo(Niket) : Remove labels later. + // Just for demonstration purpose + Row( + modifier = Modifier + .fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(4.dp) + ) { + for (label in labelModelList) { + Box( + modifier = Modifier + .width(32.dp) + .height(16.dp) + .clip(RoundedCornerShape(10)) + .background(color = Color(label.labelColor)) + ) } } +// card.labels.let { cardLabels -> +// Row( +// modifier = Modifier +// .fillMaxWidth(), +// horizontalArrangement = Arrangement.spacedBy(4.dp) +// ) { +// for (label in cardLabels) { +// Box( +// modifier = Modifier +// .width(32.dp) +// .height(16.dp) +// .clip(RoundedCornerShape(10)) +// .background(color = Color(label.labelColor)) +// ) +// } +// } +// } + Spacer(modifier = Modifier.height(8.dp)) Text( diff --git a/core/domain/src/main/java/com/jetapps/jettaskboard/model/BoardListModel.kt b/core/domain/src/main/java/com/jetapps/jettaskboard/model/BoardListModel.kt index 733ca26..2f27b63 100644 --- a/core/domain/src/main/java/com/jetapps/jettaskboard/model/BoardListModel.kt +++ b/core/domain/src/main/java/com/jetapps/jettaskboard/model/BoardListModel.kt @@ -1,8 +1,20 @@ package com.jetapps.jettaskboard.model +private val randomImageUrls = + listOf( + "https://images.unsplash.com/photo-1508264165352-258db2ebd59b?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=776&q=80", + "https://images.unsplash.com/photo-1506792006437-256b665541e2?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=774&q=80", + "https://images.unsplash.com/photo-1500042600524-37ecb686c775?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1770&q=80", + "https://images.unsplash.com/photo-1514463439976-96c5d33f0d57?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1769&q=80", + "https://images.unsplash.com/photo-1503149779833-1de50ebe5f8a?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=870&q=80", + "https://images.unsplash.com/photo-1531176175280-33e81422832a?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=774&q=80", + "https://images.unsplash.com/photo-1657571484167-9975a442ecbb?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1874&q=80" + ) + + data class Board( val title: String, - val imageUrl: String, + val imageUrl: String = randomImageUrls[3], val isStarred: Boolean = false ) diff --git a/core/domain/src/main/java/com/jetapps/jettaskboard/model/BoardModel.kt b/core/domain/src/main/java/com/jetapps/jettaskboard/model/BoardModel.kt index a22ec3b..a7ef4a3 100644 --- a/core/domain/src/main/java/com/jetapps/jettaskboard/model/BoardModel.kt +++ b/core/domain/src/main/java/com/jetapps/jettaskboard/model/BoardModel.kt @@ -1,15 +1,30 @@ package com.jetapps.jettaskboard.model +import kotlin.random.Random + +private val ImageUrls by lazy { + listOf( + "https://images.unsplash.com/photo-1508264165352-258db2ebd59b?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=776&q=80", + "https://images.unsplash.com/photo-1506792006437-256b665541e2?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=774&q=80", + "https://images.unsplash.com/photo-1500042600524-37ecb686c775?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1770&q=80", + "https://images.unsplash.com/photo-1514463439976-96c5d33f0d57?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1769&q=80", + "https://images.unsplash.com/photo-1503149779833-1de50ebe5f8a?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=870&q=80", + "https://images.unsplash.com/photo-1531176175280-33e81422832a?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=774&q=80", + "https://images.unsplash.com/photo-1657571484167-9975a442ecbb?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1874&q=80" + ) +} + data class BoardModel( - val id: Int? = null, + val id: Long? = null, val title: String = "", val lists: List = emptyList(), val isFav: Boolean = false, + val imageUrl: String? = ImageUrls[Random.nextInt(0, ImageUrls.size - 1)] ) data class BoardWithListAndCard( - val boardId : Int, - val boardTitle : String, - val isFav: Boolean, - val listModel: List, + val boardId: Long?, + val boardTitle: String?, + val isFav: Boolean?, + val listModel: List?, ) \ No newline at end of file diff --git a/core/domain/src/main/java/com/jetapps/jettaskboard/model/CardModel.kt b/core/domain/src/main/java/com/jetapps/jettaskboard/model/CardModel.kt index 3fe9cc7..8a7d610 100644 --- a/core/domain/src/main/java/com/jetapps/jettaskboard/model/CardModel.kt +++ b/core/domain/src/main/java/com/jetapps/jettaskboard/model/CardModel.kt @@ -1,14 +1,45 @@ package com.jetapps.jettaskboard.model + +const val YellowLabel = 0xFFFBC02D +const val BlueLabel = 0xFF03A9F4 +const val RedLabel = 0xFFFF8A80 +const val GreenLabel = 0xFF8BC34A +const val OrangeLabel = 0xFFFFD180 + +val labelModelList = listOf( + LabelModel( + id = "0", + labelName = "Architecture", + labelColor = YellowLabel + ), + LabelModel( + id = "2", + labelName = "Tests", + labelColor = GreenLabel + ), + LabelModel( + id = "3", + labelName = "CI/CD", + labelColor = RedLabel + ), + LabelModel( + id = "4", + labelName = "Library", + labelColor = OrangeLabel + ) +) + data class CardModel( - val id: Int = 0, + val id: Long = 0, val title: String, val description: String? = null, - val coverImageUrl: String? = null, - val labels: List = listOf(), - val boardId: Int, - val listId: Int, + val coverImageUrl: String? = "https://images.unsplash.com/photo-1657571484167-9975a442ecbb?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1874&q=80", + val labels: List = labelModelList, + val boardId: Long, + val listId: Long, val authorId: String? = null, val startDate: String? = null, val dueDate: String? = null ) + diff --git a/core/domain/src/main/java/com/jetapps/jettaskboard/model/ListModel.kt b/core/domain/src/main/java/com/jetapps/jettaskboard/model/ListModel.kt index 6930eb0..f90b433 100644 --- a/core/domain/src/main/java/com/jetapps/jettaskboard/model/ListModel.kt +++ b/core/domain/src/main/java/com/jetapps/jettaskboard/model/ListModel.kt @@ -1,8 +1,8 @@ package com.jetapps.jettaskboard.model data class ListModel( - val listId: Int?, - val boardId : Int, - val title: String, - val cards: MutableList = mutableListOf() + val listId: Long? = null, + val boardId : Long?, + val title: String?, + val cards: MutableList? = mutableListOf() ) diff --git a/core/domain/src/main/java/com/jetapps/jettaskboard/repo/BoardRepo.kt b/core/domain/src/main/java/com/jetapps/jettaskboard/repo/BoardRepo.kt index 1f3f423..b1a50e0 100644 --- a/core/domain/src/main/java/com/jetapps/jettaskboard/repo/BoardRepo.kt +++ b/core/domain/src/main/java/com/jetapps/jettaskboard/repo/BoardRepo.kt @@ -8,7 +8,7 @@ import kotlinx.coroutines.flow.Flow interface BoardRepo { suspend fun getLatestBackgroundImgUri(): Flow suspend fun updateBackgroundImgUri(string: String) - suspend fun getBoardDetails(boardId : Int) : Flow + suspend fun getBoardDetails(boardId : Long) : Flow suspend fun createNewList(listModel: ListModel) suspend fun deleteList(listModel: ListModel) suspend fun updateCard(cardModel: CardModel) diff --git a/core/domain/src/main/java/com/jetapps/jettaskboard/repo/CardRepo.kt b/core/domain/src/main/java/com/jetapps/jettaskboard/repo/CardRepo.kt index d75b2e9..0a6d0d4 100644 --- a/core/domain/src/main/java/com/jetapps/jettaskboard/repo/CardRepo.kt +++ b/core/domain/src/main/java/com/jetapps/jettaskboard/repo/CardRepo.kt @@ -10,4 +10,8 @@ interface CardRepo { suspend fun fetchCards( boardId: String ): Flow> + + suspend fun fetchCardDetails( + cardId : Long + ) : CardModel } diff --git a/core/domain/src/main/java/com/jetapps/jettaskboard/repo/DashboardRepo.kt b/core/domain/src/main/java/com/jetapps/jettaskboard/repo/DashboardRepo.kt index 87fcc95..ea81077 100644 --- a/core/domain/src/main/java/com/jetapps/jettaskboard/repo/DashboardRepo.kt +++ b/core/domain/src/main/java/com/jetapps/jettaskboard/repo/DashboardRepo.kt @@ -12,5 +12,5 @@ interface DashboardRepo { suspend fun createCard(cardModel: CardModel) suspend fun createBoard(boardModel: BoardModel) suspend fun fetchAllLists() : List - suspend fun fetchListsFromRelatedBoard(boardId : Int) : List + suspend fun fetchListsFromRelatedBoard(boardId : Long) : List } \ No newline at end of file diff --git a/core/domain/src/main/java/com/jetapps/jettaskboard/usecase/FetchCardsUseCase.kt b/core/domain/src/main/java/com/jetapps/jettaskboard/usecase/FetchCardsUseCase.kt index 0cf5acd..fbfb299 100644 --- a/core/domain/src/main/java/com/jetapps/jettaskboard/usecase/FetchCardsUseCase.kt +++ b/core/domain/src/main/java/com/jetapps/jettaskboard/usecase/FetchCardsUseCase.kt @@ -4,6 +4,8 @@ import com.jetapps.jettaskboard.model.CardModel import com.jetapps.jettaskboard.repo.CardRepo import javax.inject.Inject -class FetchCardsUseCase @Inject constructor(private val cardRepo: CardRepo) : UseCase, String> { +class FetchCardsUseCase @Inject constructor( + private val cardRepo: CardRepo, +) : UseCase, String> { suspend operator fun invoke(boardId: String) = cardRepo.fetchCards(boardId = boardId) } diff --git a/core/domain/src/main/java/com/jetapps/jettaskboard/usecase/board/FetchCardDetailsUseCase.kt b/core/domain/src/main/java/com/jetapps/jettaskboard/usecase/board/FetchCardDetailsUseCase.kt new file mode 100644 index 0000000..357033c --- /dev/null +++ b/core/domain/src/main/java/com/jetapps/jettaskboard/usecase/board/FetchCardDetailsUseCase.kt @@ -0,0 +1,10 @@ +package com.jetapps.jettaskboard.usecase.board + +import com.jetapps.jettaskboard.repo.CardRepo +import javax.inject.Inject + +class FetchCardDetailsUseCase @Inject constructor( + private val cardRepo: CardRepo +) { + suspend operator fun invoke(cardId: Long) = cardRepo.fetchCardDetails(cardId) +} \ No newline at end of file diff --git a/core/domain/src/main/java/com/jetapps/jettaskboard/usecase/board/GetBoardDetailsUseCase.kt b/core/domain/src/main/java/com/jetapps/jettaskboard/usecase/board/GetBoardDetailsUseCase.kt index 24edecd..87e1e2b 100644 --- a/core/domain/src/main/java/com/jetapps/jettaskboard/usecase/board/GetBoardDetailsUseCase.kt +++ b/core/domain/src/main/java/com/jetapps/jettaskboard/usecase/board/GetBoardDetailsUseCase.kt @@ -1,11 +1,16 @@ package com.jetapps.jettaskboard.usecase.board +import com.jetapps.jettaskboard.model.BoardWithListAndCard import com.jetapps.jettaskboard.repo.BoardRepo +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.flowOn import javax.inject.Inject class GetBoardDetailsUseCase @Inject constructor( private val boardRepo: BoardRepo ) { - suspend operator fun invoke(id: Int) = boardRepo.getBoardDetails(id) + suspend operator fun invoke(id: Long) = boardRepo.getBoardDetails(id) } \ No newline at end of file diff --git a/core/domain/src/main/java/com/jetapps/jettaskboard/usecase/dashboard/FetchAllListsRelatedToBoardUseCase.kt b/core/domain/src/main/java/com/jetapps/jettaskboard/usecase/dashboard/FetchAllListsRelatedToBoardUseCase.kt index d58e724..610838d 100644 --- a/core/domain/src/main/java/com/jetapps/jettaskboard/usecase/dashboard/FetchAllListsRelatedToBoardUseCase.kt +++ b/core/domain/src/main/java/com/jetapps/jettaskboard/usecase/dashboard/FetchAllListsRelatedToBoardUseCase.kt @@ -8,7 +8,7 @@ class FetchAllListsRelatedToBoardUseCase @Inject constructor( private val dashboardRepo: DashboardRepo ) { - suspend operator fun invoke(boardId: Int): List { - return dashboardRepo.fetchAllLists() + suspend operator fun invoke(id : Long): List { + return dashboardRepo.fetchListsFromRelatedBoard(id) } } \ No newline at end of file diff --git a/feature/card/src/main/java/com/jetapps/jettaskboard/CardDetailsScreen.kt b/feature/card/src/main/java/com/jetapps/jettaskboard/CardDetailsScreen.kt index e6710ff..76c53d6 100644 --- a/feature/card/src/main/java/com/jetapps/jettaskboard/CardDetailsScreen.kt +++ b/feature/card/src/main/java/com/jetapps/jettaskboard/CardDetailsScreen.kt @@ -43,7 +43,7 @@ fun CardDetailsRoute( isExpandedScreen: Boolean, modifier: Modifier = Modifier, onCancelClick: () -> Unit, - viewModel: CardViewModel = hiltViewModel() + viewModel: CardViewModel = hiltViewModel(), ) { Surface( modifier = modifier.fillMaxSize(), @@ -83,7 +83,11 @@ fun CardDetailsRoute( isExpandedScreen, onCancelClick, viewModel.cardModel.coverImageUrl, - viewModel.cardModel.title + viewModel.cardModel.title, + updateCard = { + viewModel.updateCard() + onCancelClick() + } ) } ) { diff --git a/feature/card/src/main/java/com/jetapps/jettaskboard/CardViewModel.kt b/feature/card/src/main/java/com/jetapps/jettaskboard/CardViewModel.kt index a419b68..abe0281 100644 --- a/feature/card/src/main/java/com/jetapps/jettaskboard/CardViewModel.kt +++ b/feature/card/src/main/java/com/jetapps/jettaskboard/CardViewModel.kt @@ -1,26 +1,31 @@ package com.jetapps.jettaskboard import android.net.Uri -import android.util.Log import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.toArgb -import androidx.compose.ui.text.input.TextFieldValue +import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.jetapps.jettaskboard.model.BoardModel import com.jetapps.jettaskboard.model.CardModel -import com.jetapps.jettaskboard.model.LabelModel -import com.jetapps.jettaskboard.state.CardDetailState +import com.jetapps.jettaskboard.model.ListModel +import com.jetapps.jettaskboard.model.labelModelList +import com.jetapps.jettaskboard.state.CreateCardStates +import com.jetapps.jettaskboard.theme.DefaultTaskBoardBGColor import com.jetapps.jettaskboard.theme.LabelBlue import com.jetapps.jettaskboard.theme.LabelGreen import com.jetapps.jettaskboard.theme.LabelOrange import com.jetapps.jettaskboard.theme.LabelPeach import com.jetapps.jettaskboard.theme.LabelViolet import com.jetapps.jettaskboard.theme.LabelYellow +import com.jetapps.jettaskboard.theme.SecondaryColor import com.jetapps.jettaskboard.uimodel.CardDetail import com.jetapps.jettaskboard.uimodel.LabelColor +import com.jetapps.jettaskboard.usecase.board.FetchCardDetailsUseCase +import com.jetapps.jettaskboard.usecase.board.UpdateCardUseCase import com.jetapps.jettaskboard.usecase.dashboard.CreateCardUseCase import com.jetapps.jettaskboard.usecase.dashboard.FetchAllBoardsUseCase import com.jetapps.jettaskboard.usecase.dashboard.FetchAllListsRelatedToBoardUseCase @@ -28,23 +33,32 @@ import com.jetapps.jettaskboard.usecase.dashboard.FetchAllListsUseCase import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import timber.log.Timber import javax.inject.Inject +import kotlin.random.Random @HiltViewModel class CardViewModel @Inject constructor( + savedStateHandle: SavedStateHandle, + private val fetchAllBoardsUseCase: FetchAllBoardsUseCase, private val fetchAllListsUseCase: FetchAllListsUseCase, private val fetchAllListsRelatedToBoardUseCase: FetchAllListsRelatedToBoardUseCase, - private val fetchAllBoardsUseCase: FetchAllBoardsUseCase, - private val createCardUseCase: CreateCardUseCase + private val createCardUseCase: CreateCardUseCase, + private val updateCardUseCase: UpdateCardUseCase, + private val fetchCardDetailsUseCase: FetchCardDetailsUseCase, ) : ViewModel() { - private val _cardDetailState: MutableStateFlow = - MutableStateFlow(CardDetailState()) - val cardDetailState: StateFlow = _cardDetailState + private val passedBoardId = savedStateHandle.get("boardId") + private val passedListId = savedStateHandle.get("listId") + private val passedCardId = savedStateHandle.get("cardId") + + private val _createCardStates: MutableStateFlow = + MutableStateFlow(CreateCardStates()) + val createCardStates: StateFlow = _createCardStates - val cardModel by mutableStateOf(CardDetail(coverImageUrl = "fsd")) + var cardModel by mutableStateOf(CardDetail()) val imageAttachmentList = mutableStateListOf() @@ -61,8 +75,6 @@ class CardViewModel @Inject constructor( var isLabelRowClicked = mutableStateOf(false) - var inputValue = mutableStateOf(TextFieldValue(cardModel.description ?: "")) - val isTopText = mutableStateOf(false) val isBottomText = mutableStateOf(false) @@ -71,20 +83,40 @@ class CardViewModel @Inject constructor( val dueDateText = mutableStateOf(cardModel.dueDate ?: "Due Date...") + private val listOfColors = listOf( + LabelGreen, + LabelYellow, + LabelPeach, + LabelOrange, + LabelViolet, + LabelBlue, + DefaultTaskBoardBGColor, + SecondaryColor, + ) + + init { + fetchBoards() + passedCardId?.let { cardId -> + fetchCardDetails(cardId) + } + } + /** * Fetching all the boards when * Creating new Card from dashboard * Else Showing the select boardId */ - fun fetchBoards(boardId: Int?) { + private fun fetchBoards() { viewModelScope.launch { - boardId?.let { id -> - fetchAllBoardsUseCase.invoke().collect { boardList -> - _cardDetailState.value = _cardDetailState.value.copy( - boards = boardList - ) - Timber.tag("TAG").d("BoardLists %s", boardList) + fetchAllBoardsUseCase.invoke().map { list -> + list.associateBy { + listOfColors.provideRandomColorFromTheList() } + }.collect { colorBoardMap -> + Timber.tag("TAG").d("BoardLists %s", colorBoardMap) + _createCardStates.value = _createCardStates.value.copy( + boards = colorBoardMap + ) } } } @@ -94,17 +126,21 @@ class CardViewModel @Inject constructor( * creating a new card from dashboard * else showing the list belongs to the following board only */ - fun fetchLists(boardId: Int?) { + private fun fetchLists(boardId: Long?) { viewModelScope.launch { boardId?.let { id -> - val lists = fetchAllListsRelatedToBoardUseCase.invoke(id) - _cardDetailState.value = _cardDetailState.value.copy( + val lists = fetchAllListsRelatedToBoardUseCase.invoke(id).associateBy { + it.title ?: "" + } + _createCardStates.value = _createCardStates.value.copy( lists = lists ) Timber.tag("TAG").d("Fetch Board related Lists: %s", lists) } ?: run { - val allListsAvailable = fetchAllListsUseCase.invoke() - _cardDetailState.value = _cardDetailState.value.copy( + val allListsAvailable = fetchAllListsUseCase.invoke().associateBy { + it.title ?: "" + } + _createCardStates.value = _createCardStates.value.copy( lists = allListsAvailable ) Timber.tag("TAG").d("Fetch All Lists: %s", allListsAvailable) @@ -116,23 +152,88 @@ class CardViewModel @Inject constructor( // Todo(Niket) : Provide a validator here to check for edge cases fun submitCard() { viewModelScope.launch { - val cardModel = with(cardModel) { - CardModel( - title = title ?: "Card title", - description = description, - coverImageUrl = coverImageUrl, - labels = labels.toList().map { color -> - LabelModel( - labelName = "Name : ${color.color}", - labelColor = color.color.toArgb().toLong() + val newCardModel = CardModel( + title = _createCardStates.value.cardTitle ?: "", + description = _createCardStates.value.cardDescription ?: "", + boardId = _createCardStates.value.selectedBoardModel?.id ?: 0, + listId = _createCardStates.value.selectedListFromBoard?.listId ?: 0, + ) + Timber.tag("TAG").d("CardModel %s", newCardModel) + createCardUseCase.invoke(newCardModel) + } + } + + fun updateCard() { + println("Passing Arguments : Board id -> $passedBoardId, ListId -> $passedListId and Card id -> $passedCardId") + viewModelScope.launch { + passedCardId?.let { safeCardId -> + updateCardUseCase.invoke( + with(cardModel) { + CardModel( + id = safeCardId, + title = title ?: "...", + description = description, + coverImageUrl = coverImageUrl, + labels = labelModelList, + boardId = passedBoardId ?: 0, + authorId = authorName, + listId = passedListId ?: 0, ) }, - boardId = boardId ?: 0, - listId = 0, ) } - Timber.tag("TAG").d("CardModel %s", cardModel) - createCardUseCase.invoke(cardModel) } } + + private fun fetchCardDetails(cardId: Long) { + viewModelScope.launch { + val fetchCardDetails = fetchCardDetailsUseCase.invoke(cardId) + println("Card Details $fetchCardDetails") + val newModel = with(fetchCardDetails) { + CardDetail( + id = id, + boardId = boardId, + title = title, + description = description, + coverImageUrl = coverImageUrl, + boardName = boardId.toString(), + listName = listId.toString(), + authorName = authorId.toString(), + startDate = startDate, + dueDate = dueDate + ) + } + cardModel = newModel + } + } + + private fun List.provideRandomColorFromTheList(): Color { + val random = Random.nextInt(0, size - 1) + return this[random] + } + + fun setupSelectedBoard(boardModel: BoardModel) { + _createCardStates.value = _createCardStates.value.copy( + selectedBoardModel = boardModel + ) + fetchLists(boardId = boardModel.id) + } + + fun setupSelectedList(listModel: ListModel) { + _createCardStates.value = _createCardStates.value.copy( + selectedListFromBoard = listModel + ) + } + + fun setUpNewCardTitle(value: String) { + _createCardStates.value = _createCardStates.value.copy( + cardTitle = value + ) + } + + fun setUpNewCardDescription(value: String) { + _createCardStates.value = _createCardStates.value.copy( + cardDescription = value + ) + } } diff --git a/feature/card/src/main/java/com/jetapps/jettaskboard/CreateCardScreen.kt b/feature/card/src/main/java/com/jetapps/jettaskboard/CreateCardScreen.kt index c88a8de..ad6c62d 100644 --- a/feature/card/src/main/java/com/jetapps/jettaskboard/CreateCardScreen.kt +++ b/feature/card/src/main/java/com/jetapps/jettaskboard/CreateCardScreen.kt @@ -26,7 +26,6 @@ import androidx.compose.material3.adaptive.layout.AnimatedPane import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffold import androidx.compose.material3.adaptive.navigation.rememberListDetailPaneScaffoldNavigator 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 @@ -38,11 +37,12 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.jetapps.jettaskboard.carddetailscomponents.components.ItemRow import com.jetapps.jettaskboard.carddetailscomponents.components.TimeItemRow import com.jetapps.jettaskboard.feature.card.R -import com.jetapps.jettaskboard.theme.DefaultTaskBoardBGColor -import com.jetapps.jettaskboard.theme.LabelOrange +import com.jetapps.jettaskboard.model.BoardModel +import com.jetapps.jettaskboard.model.ListModel import com.jetapps.jettaskboard.theme.SecondaryColor import com.vanpra.composematerialdialogs.MaterialDialog import com.vanpra.composematerialdialogs.rememberMaterialDialogState @@ -54,12 +54,6 @@ fun CreateCardRoute( isExpandedScreen: Boolean, onCancelClick: () -> Unit ) { - - LaunchedEffect(true){ - viewModel.fetchBoards(1) - viewModel.fetchLists(null) - } - Scaffold( topBar = { TopAppBar( @@ -75,6 +69,7 @@ fun CreateCardRoute( actions = { IconButton(onClick = { viewModel.submitCard() + onCancelClick() }) { Icon( Icons.Default.Check, @@ -100,6 +95,7 @@ fun AdaptiveCreateCardContent( viewModel: CardViewModel ) { val navigator = rememberListDetailPaneScaffoldNavigator() + val boardAndListData by viewModel.createCardStates.collectAsStateWithLifecycle() BackHandler(navigator.canNavigateBack()) { navigator.navigateBack() @@ -113,7 +109,9 @@ fun AdaptiveCreateCardContent( AnimatedPane { CardMainPane( viewModel = viewModel, - isExpanded = isExpandedScreen + isExpanded = isExpandedScreen, + boardMapList = boardAndListData.boards, + listMapList = boardAndListData.lists ) } }, @@ -129,7 +127,9 @@ fun AdaptiveCreateCardContent( fun CardMainPane( modifier: Modifier = Modifier, isExpanded: Boolean = false, - viewModel: CardViewModel + viewModel: CardViewModel, + boardMapList: Map, + listMapList: Map ) { Column( modifier = modifier @@ -137,26 +137,20 @@ fun CardMainPane( .fillMaxSize() .padding(16.dp) ) { - val boardList = mapOf( - DefaultTaskBoardBGColor to "Praxis", - SecondaryColor to "Discord Clone", - LabelOrange to "Trello Workspace" - ) - - val visibilityList = mapOf( - "ToDo Items" to "", - "Doing" to "", - "Done" to "" - ) - CreateBoardDropDown( headingText = "Board", - contentMap = boardList + contentMap = boardMapList, + onBoardSelected = { boardModel -> + viewModel.setupSelectedBoard(boardModel) + } ) - CreateFormDropDown( + CreateBoardListFormDropDown( headingText = "List", - contentMap = visibilityList + contentMap = listMapList, + onListSelected = { listModel -> + viewModel.setupSelectedList(listModel) + } ) if (!isExpanded) { @@ -174,7 +168,10 @@ fun CardDetailPane( } @Composable -fun CardInfoBox(viewModel: CardViewModel) { +fun CardInfoBox( + viewModel: CardViewModel, +) { + // Todo(Niket) : Find a better way to pass the text values. var textCardName by remember { mutableStateOf(TextFieldValue("")) } var textDescription by remember { mutableStateOf(TextFieldValue("")) } val dialogState = rememberMaterialDialogState() @@ -202,6 +199,7 @@ fun CardInfoBox(viewModel: CardViewModel) { value = textCardName, onValueChange = { textCardName = it + viewModel.setUpNewCardTitle(it.text) }, label = { Text(text = "Card Name") }, colors = TextFieldDefaults.textFieldColors( @@ -221,6 +219,7 @@ fun CardInfoBox(viewModel: CardViewModel) { value = textDescription, onValueChange = { textDescription = it + viewModel.setUpNewCardDescription(it.text) }, label = { Text(text = "Description") }, colors = TextFieldDefaults.textFieldColors( diff --git a/feature/card/src/main/java/com/jetapps/jettaskboard/carddetailscomponents/CardDetailsMainPane.kt b/feature/card/src/main/java/com/jetapps/jettaskboard/carddetailscomponents/CardDetailsMainPane.kt index d2a911b..04edb49 100644 --- a/feature/card/src/main/java/com/jetapps/jettaskboard/carddetailscomponents/CardDetailsMainPane.kt +++ b/feature/card/src/main/java/com/jetapps/jettaskboard/carddetailscomponents/CardDetailsMainPane.kt @@ -94,15 +94,45 @@ fun CardDetailsMainPane( Divider() Spacer(modifier = Modifier.height(8.dp)) - EditTextCard(viewModel = viewModel, isExpanded = true) + EditTextCard( + viewModel = viewModel, + isExpanded = true, + iconResource = R.drawable.ic_notes, + placeHolderText = "Add a description", + onValue = viewModel.cardModel.description ?: "Description..", + onValueChanged = { newCharSets -> + viewModel.cardModel = viewModel.cardModel.copy( + description = newCharSets + ) + } + ) Divider() Spacer(modifier = Modifier.height(8.dp)) + EditTextCard( + viewModel = viewModel, + isExpanded = true, + iconResource = R.drawable.ic_notes, + placeHolderText = "Add a Title", + onValue = viewModel.cardModel.title ?: "Title..", + onValueChanged = { newCharSets -> + viewModel.cardModel = viewModel.cardModel.copy( + title = newCharSets + ) + } + ) + + Divider() + + Spacer(modifier = Modifier.height(8.dp)) + QuickActionsCard(isExpanded = true) Spacer(modifier = Modifier.height(8.dp)) + Divider() + Spacer(modifier = Modifier.height(8.dp)) } } else { @@ -131,7 +161,37 @@ fun CardDetailsMainPane( Divider() - EditTextCard(viewModel = viewModel) + EditTextCard( + viewModel = viewModel, + isExpanded = true, + iconResource = R.drawable.ic_notes, + placeHolderText = "Add a description", + onValue = viewModel.cardModel.description ?: "Description..", + onValueChanged = { newCharSets -> + viewModel.cardModel = viewModel.cardModel.copy( + description = newCharSets + ) + } + ) + + Divider() + + Spacer(modifier = Modifier.height(8.dp)) + + EditTextCard( + viewModel = viewModel, + isExpanded = true, + iconResource = R.drawable.ic_notes, + placeHolderText = "Add a Title", + onValue = viewModel.cardModel.title ?: "Title..", + onValueChanged = { newCharSets -> + viewModel.cardModel = viewModel.cardModel.copy( + title = newCharSets + ) + } + ) + + Spacer(modifier = Modifier.height(8.dp)) LabelRow(viewModel) diff --git a/feature/card/src/main/java/com/jetapps/jettaskboard/carddetailscomponents/components/EditTextCard.kt b/feature/card/src/main/java/com/jetapps/jettaskboard/carddetailscomponents/components/EditTextCard.kt index 540d1cb..dbb1a50 100644 --- a/feature/card/src/main/java/com/jetapps/jettaskboard/carddetailscomponents/components/EditTextCard.kt +++ b/feature/card/src/main/java/com/jetapps/jettaskboard/carddetailscomponents/components/EditTextCard.kt @@ -13,16 +13,23 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.unit.dp import com.jetapps.jettaskboard.CardViewModel -import com.jetapps.jettaskboard.feature.card.R @Composable -fun EditTextCard(viewModel: CardViewModel, isExpanded: Boolean = false) { +fun EditTextCard( + viewModel: CardViewModel, + isExpanded: Boolean = false, + iconResource: Int, + placeHolderText: String, + onValue: String, + onValueChanged: (String) -> Unit, +) { Row(modifier = Modifier.fillMaxWidth()) { Icon( modifier = Modifier.padding(16.dp), - painter = painterResource(id = R.drawable.ic_notes), + painter = painterResource(id = iconResource), contentDescription = "Notes Icon" ) @@ -30,14 +37,18 @@ fun EditTextCard(viewModel: CardViewModel, isExpanded: Boolean = false) { modifier = Modifier .background(Color.Transparent) .padding(end = 16.dp) - .height(if (isExpanded) { 80.dp } else { 56.dp }) + .height( + if (isExpanded) { + 80.dp + } else { + 56.dp + } + ) .fillMaxWidth(), - value = viewModel.inputValue.value, - onValueChange = { - viewModel.inputValue.value = it - }, + value = onValue, + onValueChange = onValueChanged, placeholder = { - Text(text = "Add card description...") + Text(text = placeHolderText) }, colors = TextFieldDefaults.textFieldColors( backgroundColor = Color.Transparent, diff --git a/feature/card/src/main/java/com/jetapps/jettaskboard/carddetailscomponents/components/MotionTopBar.kt b/feature/card/src/main/java/com/jetapps/jettaskboard/carddetailscomponents/components/MotionTopBar.kt index 62cc683..516dfe0 100644 --- a/feature/card/src/main/java/com/jetapps/jettaskboard/carddetailscomponents/components/MotionTopBar.kt +++ b/feature/card/src/main/java/com/jetapps/jettaskboard/carddetailscomponents/components/MotionTopBar.kt @@ -21,6 +21,7 @@ import androidx.compose.material.Icon import androidx.compose.material.Surface import androidx.compose.material.Text import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.MoreVert import androidx.compose.runtime.Composable @@ -49,7 +50,8 @@ fun MotionTopBar( isExpandedScreen: Boolean, onCancelClick: () -> Unit, coverImageUrl: String?, - title: String? + title: String?, + updateCard: () -> Unit, ) { val context = LocalContext.current val motionScene = remember { @@ -135,11 +137,12 @@ fun MotionTopBar( ) Icon( - imageVector = Icons.Default.MoreVert, - contentDescription = "Open Menu", + imageVector = Icons.Default.Add, + contentDescription = "Add Card", modifier = Modifier .layoutId("more_icon") .clickable { + updateCard() }, tint = Color.White ) diff --git a/feature/card/src/main/java/com/jetapps/jettaskboard/navigation/CardNav.kt b/feature/card/src/main/java/com/jetapps/jettaskboard/navigation/CardNav.kt index d3b496e..b4c6b00 100644 --- a/feature/card/src/main/java/com/jetapps/jettaskboard/navigation/CardNav.kt +++ b/feature/card/src/main/java/com/jetapps/jettaskboard/navigation/CardNav.kt @@ -17,7 +17,9 @@ package com.jetapps.jettaskboard.navigation import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavType import androidx.navigation.compose.composable +import androidx.navigation.navArgument import com.jetapps.jettaskboard.CardDetailsRoute import com.jetapps.jettaskboard.CreateCardRoute import com.jetapps.jettaskboard.JtbNavDestination @@ -34,11 +36,37 @@ object CardDetailsDestination : JtbNavDestination { override val destination = "card_details_destination" } -fun NavGraphBuilder.cardGraph(isExpandedScreen: Boolean, onBackClick: () -> Unit) { +fun NavGraphBuilder.cardGraph( + isExpandedScreen: Boolean, + onBackClick: () -> Unit, +) { composable(route = CreateCardDestination.route) { CreateCardRoute(isExpandedScreen = isExpandedScreen, onCancelClick = onBackClick) } - composable(route = CardDetailsDestination.route) { - CardDetailsRoute(isExpandedScreen, onCancelClick = onBackClick) + composable( + route = CardDetailsDestination.route + "/{boardId}/{listId}/{cardId}", + arguments = listOf( + navArgument("boardId") { + type = NavType.LongType + defaultValue = 0 + }, + navArgument("listId") { + type = NavType.LongType + defaultValue = 0 + }, + navArgument("cardId") { + type = NavType.LongType + defaultValue = 0 + }, + ) + ) { backStackEntry -> + val passedBoardId = backStackEntry.arguments?.getLong("boardId") + val passedListId = backStackEntry.arguments?.getLong("listId") + val passedCardId = backStackEntry.arguments?.getLong("cardId") + println("Passing Arguments : Board id -> $passedBoardId, ListId -> $passedListId and Card id -> $passedCardId") + CardDetailsRoute( + isExpandedScreen, + onCancelClick = onBackClick, + ) } } diff --git a/feature/card/src/main/java/com/jetapps/jettaskboard/state/CardDetailState.kt b/feature/card/src/main/java/com/jetapps/jettaskboard/state/CardDetailState.kt deleted file mode 100644 index d78aa1a..0000000 --- a/feature/card/src/main/java/com/jetapps/jettaskboard/state/CardDetailState.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.jetapps.jettaskboard.state - -import com.jetapps.jettaskboard.model.BoardModel -import com.jetapps.jettaskboard.model.ListModel - -data class CardDetailState( - val boards: List = emptyList(), - val lists: List = emptyList(), - val cardDescription: String = "", - val cardTitle: String = "", -) \ No newline at end of file diff --git a/feature/card/src/main/java/com/jetapps/jettaskboard/state/CreateCardStates.kt b/feature/card/src/main/java/com/jetapps/jettaskboard/state/CreateCardStates.kt new file mode 100644 index 0000000..fc8e19b --- /dev/null +++ b/feature/card/src/main/java/com/jetapps/jettaskboard/state/CreateCardStates.kt @@ -0,0 +1,14 @@ +package com.jetapps.jettaskboard.state + +import androidx.compose.ui.graphics.Color +import com.jetapps.jettaskboard.model.BoardModel +import com.jetapps.jettaskboard.model.ListModel + +data class CreateCardStates( + val boards: Map = emptyMap(), + val lists: Map = emptyMap(), + val selectedBoardModel: BoardModel? = null, + val selectedListFromBoard: ListModel? = null, + val cardTitle: String? = null, + val cardDescription: String? = null +) \ No newline at end of file diff --git a/feature/card/src/main/java/com/jetapps/jettaskboard/uimodel/CardDetail.kt b/feature/card/src/main/java/com/jetapps/jettaskboard/uimodel/CardDetail.kt index f0d35fa..5d4b79b 100644 --- a/feature/card/src/main/java/com/jetapps/jettaskboard/uimodel/CardDetail.kt +++ b/feature/card/src/main/java/com/jetapps/jettaskboard/uimodel/CardDetail.kt @@ -1,11 +1,11 @@ package com.jetapps.jettaskboard.uimodel data class CardDetail( - val id: Int? = null, - val boardId : Int? = null, + val id: Long? = null, + val boardId: Long? = null, val title: String? = null, val description: String? = null, - val coverImageUrl: String? = null, + val coverImageUrl: String? = "https://images.unsplash.com/photo-1574169208507-84376144848b?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=400&q=80", val boardName: String? = null, val listName: String? = null, val authorName: String? = null, diff --git a/feature/dashboard/src/main/java/com/jetapps/jettaskboard/DashboardDetailPane.kt b/feature/dashboard/src/main/java/com/jetapps/jettaskboard/DashboardDetailPane.kt index b35afd6..74902b6 100644 --- a/feature/dashboard/src/main/java/com/jetapps/jettaskboard/DashboardDetailPane.kt +++ b/feature/dashboard/src/main/java/com/jetapps/jettaskboard/DashboardDetailPane.kt @@ -1,22 +1,29 @@ package com.jetapps.jettaskboard import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items +import androidx.compose.material.Button +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 import com.jetapps.jettaskboard.component.Header import com.jetapps.jettaskboard.components.WorkshopCard import com.jetapps.jettaskboard.model.Board +import com.jetapps.jettaskboard.model.BoardModel @Composable fun DashboardDetailPane( navigateToTaskBoard: (String) -> Unit, - boardList: List, + boardList: List, + createCardEvent: () -> Unit, ) { Column { Header( @@ -24,18 +31,31 @@ fun DashboardDetailPane( title = "Trello workspace", showIcon = true ) - LazyColumn( - modifier = Modifier - .fillMaxHeight() - .padding(top = 4.dp) - ) { - items(boardList) { - WorkshopCard( - modifier = Modifier.clickable { navigateToTaskBoard("") }, - title = it.title, - imageUrl = it.imageUrl, - isWorkshopStarred = it.isStarred - ) + if (boardList.isEmpty()) { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center, + ) { + Button( + onClick = createCardEvent + ) { + Text(text = "Create a new Card") + } + } + } else { + LazyColumn( + modifier = Modifier + .fillMaxHeight() + .padding(top = 4.dp) + ) { + items(boardList) { + WorkshopCard( + modifier = Modifier.clickable { navigateToTaskBoard(it.id.toString()) }, + title = it.title, + imageUrl = it.imageUrl ?: "", + isWorkshopStarred = it.isFav + ) + } } } } diff --git a/feature/dashboard/src/main/java/com/jetapps/jettaskboard/DashboardMainPane.kt b/feature/dashboard/src/main/java/com/jetapps/jettaskboard/DashboardMainPane.kt index 3a4df4f..f1d7dcb 100644 --- a/feature/dashboard/src/main/java/com/jetapps/jettaskboard/DashboardMainPane.kt +++ b/feature/dashboard/src/main/java/com/jetapps/jettaskboard/DashboardMainPane.kt @@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row 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 @@ -19,29 +20,33 @@ import androidx.compose.foundation.lazy.grid.items import androidx.compose.foundation.lazy.items import androidx.compose.material.Button import androidx.compose.material.Divider +import androidx.compose.material3.ButtonColors import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import com.jetapps.jettaskboard.component.Header import com.jetapps.jettaskboard.components.BoardCardComponent import com.jetapps.jettaskboard.components.WorkshopCard import com.jetapps.jettaskboard.model.Board +import com.jetapps.jettaskboard.model.BoardModel @Composable fun DashboardMainPaneContent( isExpanded: Boolean, - boardList: List, + boardList: List, navigateToTaskBoard: (String) -> Unit = {}, createBoard: () -> Unit, ) { if (isExpanded) { DashboardMainPaneAtExpandedScreen( boardList = boardList, - navigateToTaskBoard + navigateToTaskBoard, + createBoard ) } else { DashboardMainPaneScreen( @@ -54,8 +59,9 @@ fun DashboardMainPaneContent( @Composable fun DashboardMainPaneAtExpandedScreen( - boardList: List, - navigateToTaskBoard: (String) -> Unit + boardList: List, + navigateToTaskBoard: (String) -> Unit, + createBoard: () -> Unit, ) { Column { Header( @@ -64,20 +70,31 @@ fun DashboardMainPaneAtExpandedScreen( onMenuItemClicked = {} ) Row { - LazyVerticalGrid( - modifier = Modifier - .padding(top = 4.dp, bottom = 8.dp, end = 8.dp) - .fillMaxHeight() - .fillMaxWidth(0.999f), - columns = Fixed(1), - contentPadding = PaddingValues(4.dp) - ) { - if (boardList.isNotEmpty()) { + if (boardList.isEmpty()) { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center, + ) { + Button( + onClick = createBoard + ) { + Text(text = "Create a new Board") + } + } + } else { + LazyVerticalGrid( + modifier = Modifier + .padding(top = 4.dp, bottom = 8.dp, end = 8.dp) + .fillMaxHeight() + .fillMaxWidth(0.999f), + columns = Fixed(1), + contentPadding = PaddingValues(4.dp) + ) { items(boardList) { boardItem -> BoardCardComponent( - modifier = Modifier.clickable { navigateToTaskBoard("") }, + modifier = Modifier.clickable { navigateToTaskBoard(boardItem.id.toString()) }, title = boardItem.title, - backgroundImageUrl = boardItem.imageUrl + backgroundImageUrl = boardItem.imageUrl ?: "" ) } } @@ -94,7 +111,7 @@ fun DashboardMainPaneAtExpandedScreen( @Composable fun DashboardMainPaneScreen( - boardList: List, + boardList: List, createBoard: () -> Unit, navigateToTaskBoard: (String) -> Unit = {} ) { @@ -123,11 +140,11 @@ fun DashboardMainPaneScreen( contentPadding = PaddingValues(4.dp) ) { if (boardList.isNotEmpty()) { - items(boardList.subList(0, 5)) { boardItem -> + items(boardList) { boardItem -> BoardCardComponent( - modifier = Modifier.clickable { navigateToTaskBoard("") }, + modifier = Modifier.clickable { navigateToTaskBoard(boardItem.id.toString()) }, title = boardItem.title, - backgroundImageUrl = boardItem.imageUrl + backgroundImageUrl = boardItem.imageUrl ?: "" ) } } @@ -146,10 +163,10 @@ fun DashboardMainPaneScreen( ) { items(boardList) { WorkshopCard( - modifier = Modifier.clickable { navigateToTaskBoard("") }, + modifier = Modifier.clickable { navigateToTaskBoard(it.id.toString()) }, title = it.title, - imageUrl = it.imageUrl, - isWorkshopStarred = it.isStarred + imageUrl = it.imageUrl ?: "", + isWorkshopStarred = it.isFav ) } } diff --git a/feature/dashboard/src/main/java/com/jetapps/jettaskboard/DashboardScreen.kt b/feature/dashboard/src/main/java/com/jetapps/jettaskboard/DashboardScreen.kt index 76480f8..d03e54c 100644 --- a/feature/dashboard/src/main/java/com/jetapps/jettaskboard/DashboardScreen.kt +++ b/feature/dashboard/src/main/java/com/jetapps/jettaskboard/DashboardScreen.kt @@ -57,7 +57,7 @@ fun DashboardRoute( modifier: Modifier = Modifier, viewModel: DashboardViewModel = hiltViewModel(), navigateToTaskBoard: (String) -> Unit = {}, - navigateToCreateCard: (String) -> Unit = {}, + navigateToCreateCard: () -> Unit = {}, navigateToCreateBoard: () -> Unit = {}, navigateToSearchScreen: (String) -> Unit = {}, isExpandedScreen: Boolean @@ -86,13 +86,6 @@ fun DashboardRoute( // ), label = "nav_drawer_width" // ) - // Todo(Niket): Move this to VM -// LaunchedEffect(Unit) { -// viewModel.apply { -// getBoardListData() -// } -// } - Surface( modifier = modifier.fillMaxSize(), color = MaterialTheme.colors.background @@ -165,6 +158,7 @@ fun DashboardRoute( contentPadding = scaffoldPadding, navigateToTaskBoard = navigateToTaskBoard, createBoard = navigateToCreateBoard, + createCard = navigateToCreateCard ) } }, @@ -179,7 +173,8 @@ fun AdaptiveDashboardContent( contentPadding: PaddingValues, viewModel: DashboardViewModel, navigateToTaskBoard: (String) -> Unit = {}, - createBoard : () -> Unit, + createBoard: () -> Unit, + createCard: () -> Unit, ) { //Todo(Niket): Write a detail blog on PaneScaffold Api // val navigator = rememberSupportingPaneScaffoldNavigator() @@ -209,6 +204,7 @@ fun AdaptiveDashboardContent( DashboardDetailPane( navigateToTaskBoard = navigateToTaskBoard, boardList, + createCard ) } }, @@ -237,7 +233,7 @@ private fun rememberSizeAwareScaffoldState( @Composable private fun MultiFab( - navigateToCreateCard: (String) -> Unit = {}, + navigateToCreateCard: () -> Unit = {}, navigateToCreateBoard: () -> Unit = {} ) { MultiFloatingActionButton( @@ -265,7 +261,7 @@ private fun MultiFab( if (item.id == 1) { navigateToCreateBoard() } else { - navigateToCreateCard("") + navigateToCreateCard() } } ) diff --git a/feature/dashboard/src/main/java/com/jetapps/jettaskboard/DashboardViewModel.kt b/feature/dashboard/src/main/java/com/jetapps/jettaskboard/DashboardViewModel.kt index 95d044d..6297913 100644 --- a/feature/dashboard/src/main/java/com/jetapps/jettaskboard/DashboardViewModel.kt +++ b/feature/dashboard/src/main/java/com/jetapps/jettaskboard/DashboardViewModel.kt @@ -1,17 +1,21 @@ package com.jetapps.jettaskboard +import android.util.Log import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.jetapps.jettaskboard.model.Board +import com.jetapps.jettaskboard.model.BoardModel import com.jetapps.jettaskboard.model.ProfileModel import com.jetapps.jettaskboard.usecase.dashboard.FetchAllBoardsUseCase import com.jetapps.jettaskboard.usecase.dashboard.FetchProfileUseCase import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch +import timber.log.Timber import javax.inject.Inject @HiltViewModel @@ -27,8 +31,8 @@ class DashboardViewModel @Inject constructor( var toggleDrawerContent = mutableStateOf(true) - private val _listOfBoards: MutableStateFlow> = MutableStateFlow(emptyList()) - val listOfBoards: StateFlow> = _listOfBoards + private val _listOfBoards: MutableStateFlow> = MutableStateFlow(emptyList()) + val listOfBoards: StateFlow> = _listOfBoards.asStateFlow() private val _profileFlow: MutableStateFlow = MutableStateFlow(null) val profileFlow: StateFlow = _profileFlow @@ -39,15 +43,6 @@ class DashboardViewModel @Inject constructor( private fun getBoardListData() { viewModelScope.launch { fetchAllBoardsUseCase.invoke() - .map { boardModelList -> - boardModelList.map { boardModel -> - Board( - title = boardModel.title, - imageUrl = "", - isStarred = false - ) - } - } .collect { boardList -> _listOfBoards.emit( boardList diff --git a/feature/dashboard/src/main/java/com/jetapps/jettaskboard/navigation/DashboardNav.kt b/feature/dashboard/src/main/java/com/jetapps/jettaskboard/navigation/DashboardNav.kt index a894b5d..d1e884c 100644 --- a/feature/dashboard/src/main/java/com/jetapps/jettaskboard/navigation/DashboardNav.kt +++ b/feature/dashboard/src/main/java/com/jetapps/jettaskboard/navigation/DashboardNav.kt @@ -29,7 +29,7 @@ object DashboardDestination : JtbNavDestination { fun NavGraphBuilder.dashboardGraph( navigateToTaskBoard: (String) -> Unit, - navigateToCreateCard: (String) -> Unit, + navigateToCreateCard: () -> Unit, navigateToCreateBoard: () -> Unit, navigateToSearchScreen: (String) -> Unit, nestedGraphs: NavGraphBuilder.() -> Unit, diff --git a/feature/taskboard/src/main/java/com/jetapps/jettaskboard/board/Board.kt b/feature/taskboard/src/main/java/com/jetapps/jettaskboard/board/Board.kt index 0d9c38a..4948f74 100644 --- a/feature/taskboard/src/main/java/com/jetapps/jettaskboard/board/Board.kt +++ b/feature/taskboard/src/main/java/com/jetapps/jettaskboard/board/Board.kt @@ -2,6 +2,7 @@ package com.jetapps.jettaskboard.board import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row @@ -16,23 +17,34 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.AlertDialog import androidx.compose.material.ButtonDefaults import androidx.compose.material.Icon import androidx.compose.material.IconButton +import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.material.TextButton +import androidx.compose.material.TextField import androidx.compose.material.icons.Icons.Filled import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.MoreVert +import androidx.compose.material3.Card import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect 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.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 androidx.compose.ui.window.Dialog import com.jetapps.jettaskboard.vm.TaskBoardViewModel import com.jetapps.jettaskboard.components.TaskCard import com.jetapps.jettaskboard.draganddrop.DragAndDropState @@ -45,12 +57,14 @@ import com.jetapps.jettaskboard.theme.SecondaryColor @Composable fun Board( modifier: Modifier = Modifier, - navigateToCreateCard: (String) -> Unit = {}, + navigateToCreateCard: (boardId: Long, listId: Long, cardId: Long) -> Unit = { a, b, c -> }, viewModel: TaskBoardViewModel, - isExpandedScreen: Boolean + isExpandedScreen: Boolean, + boardId: Long, ) { val boardState = remember { DragAndDropState(isExpandedScreen) } val boardList by viewModel.lists.collectAsState() + var showListDialogState by remember { mutableStateOf(false) } LaunchedEffect(key1 = boardState.movingCardData) { if (boardState.hasCardMoved()) { @@ -62,6 +76,16 @@ fun Board( } } + if (showListDialogState) { + CreateListDialog( + onDismissRequest = { showListDialogState = false }, + onConfirmRequest = { title -> + showListDialogState = false + viewModel.addNewList(title) + }, + ) + } + DragAndDropSurface( modifier = modifier.fillMaxSize(), state = boardState @@ -81,14 +105,16 @@ fun Board( list.listId?.let { validId -> viewModel.addNewCardInList(validId) } - } + }, boardId = boardId ) } } item { AddNewListButton( - viewModel = viewModel, - isExpandedScreen = isExpandedScreen + isExpandedScreen = isExpandedScreen, + openListDialog = { + showListDialogState = true + } ) } } @@ -99,9 +125,10 @@ fun Board( fun Lists( boardState: DragAndDropState, listModel: ListModel, - onTaskCardClick: (String) -> Unit, + onTaskCardClick: (boardId: Long, listId: Long, cardId: Long) -> Unit, onAddCardClick: () -> Unit, - isExpandedScreen: Boolean + isExpandedScreen: Boolean, + boardId: Long ) { DropSurface( modifier = Modifier @@ -110,7 +137,7 @@ fun Lists( color = Color(0xFF222222), shape = RoundedCornerShape(2) ), - listId = listModel.listId ?: 0 + listId = listModel.listId?.toInt() ?: 0 ) { isInBound, _ -> Column( modifier = Modifier @@ -121,14 +148,15 @@ fun Lists( .padding(if (isExpandedScreen) 8.dp else 4.dp) ) { ListHeader( - name = listModel.title + name = listModel.title ?: "" ) ListBody( modifier = Modifier, listModel = listModel, onTaskCardClick = onTaskCardClick, onAddCardClick = onAddCardClick, - isExpandedScreen = isExpandedScreen + isExpandedScreen = isExpandedScreen, + boardId = boardId ) } } @@ -139,24 +167,29 @@ fun Lists( fun ListBody( modifier: Modifier, listModel: ListModel, - onTaskCardClick: (String) -> Unit, + onTaskCardClick: (boardId: Long, listId: Long, cardId: Long) -> Unit, onAddCardClick: () -> Unit, - isExpandedScreen: Boolean + isExpandedScreen: Boolean, + boardId: Long, ) { LazyColumn( modifier = Modifier ) { - items(listModel.cards) { card -> + items(listModel.cards ?: emptyList()) { card -> DragSurface( modifier = modifier .fillMaxWidth() .animateItemPlacement(), - cardId = card.id, - cardListId = card.listId ?: 0 + cardId = card.id.toInt(), + cardListId = card.listId.toInt() ?: 0 ) { TaskCard( modifier = Modifier.fillMaxWidth(), - onClick = { onTaskCardClick("1") }, + onClick = { + onTaskCardClick( + boardId, listModel.listId ?: 0, card.id + ) + }, card = card, isExpandedScreen = isExpandedScreen ) @@ -214,8 +247,8 @@ fun ListFooter( @Composable fun AddNewListButton( - viewModel: TaskBoardViewModel, - isExpandedScreen: Boolean + isExpandedScreen: Boolean, + openListDialog: () -> Unit, ) { TextButton( modifier = Modifier @@ -226,7 +259,7 @@ fun AddNewListButton( backgroundColor = Color(0xFF383838) ), contentPadding = PaddingValues(16.dp), - onClick = { viewModel.addNewList() } + onClick = openListDialog ) { Icon(imageVector = Filled.Add, contentDescription = "Add") Spacer(modifier = Modifier.width(8.dp)) @@ -234,6 +267,81 @@ fun AddNewListButton( } } +@Composable +fun CreateListDialog( + modifier: Modifier = Modifier, + onDismissRequest: () -> Unit, + onConfirmRequest: (String) -> Unit, +) { + var listTitle by remember { + mutableStateOf("") + } + Dialog( + onDismissRequest = onDismissRequest + ) { + Card( + modifier = modifier + .fillMaxWidth() + .height(375.dp) + .padding(16.dp), + shape = RoundedCornerShape(16.dp), + ) { + Column( + modifier = Modifier + .fillMaxSize() + .background(MaterialTheme.colors.background), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Text( + text = "Please Provide a name to your new list", + modifier = Modifier.padding(16.dp), + color = MaterialTheme.colors.onBackground + ) + + TextField( + value = listTitle, + onValueChange = { + listTitle = it + }, + textStyle = TextStyle( + color = MaterialTheme.colors.onBackground, + fontWeight = FontWeight.Bold, + textAlign = TextAlign.Center, + ) + ) + + Row( + modifier = Modifier + .fillMaxWidth(), + horizontalArrangement = Arrangement.Center, + ) { + TextButton( + onClick = { onDismissRequest() }, + modifier = Modifier.padding(8.dp), + ) { + Text( + "Dismiss", + modifier = Modifier.padding(16.dp), + color = MaterialTheme.colors.onBackground + ) + } + TextButton( + onClick = { onConfirmRequest(listTitle) }, + modifier = Modifier.padding(8.dp), + ) { + Text( + "Confirm", + modifier = Modifier.padding(16.dp), + color = MaterialTheme.colors.onBackground + ) + } + } + } + } + } +} + /** * Returns the color for background of the drop surface,based on * whether a drop surface is in bounds, when a card is hovered on it. diff --git a/feature/taskboard/src/main/java/com/jetapps/jettaskboard/board/TaskBoardScreen.kt b/feature/taskboard/src/main/java/com/jetapps/jettaskboard/board/TaskBoardScreen.kt index 9b25634..faa566d 100644 --- a/feature/taskboard/src/main/java/com/jetapps/jettaskboard/board/TaskBoardScreen.kt +++ b/feature/taskboard/src/main/java/com/jetapps/jettaskboard/board/TaskBoardScreen.kt @@ -28,6 +28,7 @@ import androidx.compose.material.icons.filled.Menu import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material.rememberScaffoldState 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 @@ -58,10 +59,11 @@ fun TaskBoardRoute( onBackClick: () -> Unit, modifier: Modifier = Modifier, isExpandedScreen: Boolean, - navigateToCreateCard: (String) -> Unit = {}, + navigateToCreateCard: (boardId: Long, listId: Long, cardId: Long) -> Unit, navigateToChangeBackgroundScreen: (String) -> Unit = {}, backgroundColor: Color = MaterialTheme.colors.surface, - viewModel: TaskBoardViewModel = hiltViewModel() + viewModel: TaskBoardViewModel = hiltViewModel(), + boardId: Long? = 0 ) { val expandedScreenState = viewModel.drawerScreenState.value val scaffoldState = rememberScaffoldState() @@ -143,7 +145,8 @@ fun TaskBoardRoute( modifier = Modifier.fillMaxSize(), navigateToCreateCard = navigateToCreateCard, viewModel = viewModel, - isExpandedScreen = isExpandedScreen + isExpandedScreen = isExpandedScreen, + boardId = boardId ?: 0 ) } diff --git a/feature/taskboard/src/main/java/com/jetapps/jettaskboard/createboard/CreateBoardScreen.kt b/feature/taskboard/src/main/java/com/jetapps/jettaskboard/createboard/CreateBoardScreen.kt index 95ff2b2..658f5b0 100644 --- a/feature/taskboard/src/main/java/com/jetapps/jettaskboard/createboard/CreateBoardScreen.kt +++ b/feature/taskboard/src/main/java/com/jetapps/jettaskboard/createboard/CreateBoardScreen.kt @@ -2,7 +2,9 @@ package com.jetapps.jettaskboard.createboard import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.material.MaterialTheme import androidx.compose.material.Scaffold @@ -10,7 +12,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.hilt.navigation.compose.hiltViewModel -import com.jetapps.jettaskboard.CreateFormDropDown import com.jetapps.jettaskboard.createboard.CreateBoardViewModel.Companion.visibilityList import com.jetapps.jettaskboard.createboard.components.CreateBoardTopBar import com.jetapps.jettaskboard.createboard.components.CreateFormEditText @@ -18,31 +19,33 @@ import com.jetapps.jettaskboard.model.BoardModel import androidx.compose.runtime.setValue import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf +import androidx.compose.ui.unit.dp +import com.jetapps.jettaskboard.CreateVisibilityFormDropDown @Composable fun CreateBoardRoute( modifier: Modifier = Modifier, createBoardViewModel: CreateBoardViewModel = hiltViewModel(), onCancelClick: () -> Unit, - navigateToBoardScreen: () -> Unit, + navigateToTaskBoardScreen: (Long) -> Unit, ) { - var boardTitle by remember { - mutableStateOf("") - } + var boardTitle by remember { mutableStateOf("") } Scaffold(topBar = { CreateBoardTopBar( title = "Create Board", onCancelClick = onCancelClick, onCreateBoardClick = { + val timestampAsId = System.currentTimeMillis() if (boardTitle.isBlank().not()) { createBoardViewModel.createNewBoard( BoardModel( + id = timestampAsId, title = boardTitle ) ) boardTitle = "" - navigateToBoardScreen() + navigateToTaskBoardScreen(timestampAsId) } } ) @@ -51,16 +54,19 @@ fun CreateBoardRoute( modifier = modifier .padding(paddingValues) .background(MaterialTheme.colors.background) - .fillMaxSize(), + .fillMaxSize() + .padding(24.dp), ) { CreateFormEditText( - hint = "Board Name", + hint = "New Task Board name", onValueChanged = { value -> boardTitle = value } ) - CreateFormDropDown( + Spacer(modifier = modifier.height(24.dp)) + + CreateVisibilityFormDropDown( headingText = "Visibility", contentMap = visibilityList ) diff --git a/feature/taskboard/src/main/java/com/jetapps/jettaskboard/createboard/components/CreateFormEditText.kt b/feature/taskboard/src/main/java/com/jetapps/jettaskboard/createboard/components/CreateFormEditText.kt index f0c436a..eab8178 100644 --- a/feature/taskboard/src/main/java/com/jetapps/jettaskboard/createboard/components/CreateFormEditText.kt +++ b/feature/taskboard/src/main/java/com/jetapps/jettaskboard/createboard/components/CreateFormEditText.kt @@ -38,7 +38,7 @@ fun CreateFormEditText( onValueChanged(it.text) }, placeholder = { - Text(text = "Board Name") + Text(text = hint) }, colors = TextFieldDefaults.textFieldColors( backgroundColor = Color.Transparent, diff --git a/feature/taskboard/src/main/java/com/jetapps/jettaskboard/navigation/CreateBoardNav.kt b/feature/taskboard/src/main/java/com/jetapps/jettaskboard/navigation/CreateBoardNav.kt index 5307a3f..d52bef6 100644 --- a/feature/taskboard/src/main/java/com/jetapps/jettaskboard/navigation/CreateBoardNav.kt +++ b/feature/taskboard/src/main/java/com/jetapps/jettaskboard/navigation/CreateBoardNav.kt @@ -13,13 +13,13 @@ object CreateBoardDestination : JtbNavDestination { fun NavGraphBuilder.createBoardGraph( onBackClick: () -> Unit, - navigateToBoardRoute: () -> Unit, + navigateToBoardRoute: (Long) -> Unit, ) { composable(route = CreateBoardDestination.route) { CreateBoardRoute( modifier = Modifier, onCancelClick = onBackClick, - navigateToBoardScreen = navigateToBoardRoute, + navigateToTaskBoardScreen = navigateToBoardRoute, ) } } diff --git a/feature/taskboard/src/main/java/com/jetapps/jettaskboard/navigation/TaskBoardNav.kt b/feature/taskboard/src/main/java/com/jetapps/jettaskboard/navigation/TaskBoardNav.kt index ce88fa1..8da1f41 100644 --- a/feature/taskboard/src/main/java/com/jetapps/jettaskboard/navigation/TaskBoardNav.kt +++ b/feature/taskboard/src/main/java/com/jetapps/jettaskboard/navigation/TaskBoardNav.kt @@ -1,7 +1,10 @@ package com.jetapps.jettaskboard.navigation +import androidx.navigation.NavArgument import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavType import androidx.navigation.compose.composable +import androidx.navigation.navArgument import com.jetapps.jettaskboard.JtbNavDestination import com.jetapps.jettaskboard.board.TaskBoardRoute @@ -12,16 +15,25 @@ object TaskBoardDestination : JtbNavDestination { fun NavGraphBuilder.taskBoardGraph( isExpandedScreen: Boolean, - navigateToCreateCard: (String) -> Unit = {}, + navigateToCreateCard: (boardId: Long, listId: Long, cardId: Long) -> Unit, navigateToChangeBackgroundScreen: (String) -> Unit = {}, onBackClick: () -> Unit ) { - composable(route = TaskBoardDestination.route) { + composable( + route = TaskBoardDestination.route + "/{boardId}", + arguments = listOf( + navArgument("boardId") { + type = NavType.LongType + defaultValue = 0 + }, + ) + ) { backStackEntry -> TaskBoardRoute( isExpandedScreen = isExpandedScreen, navigateToCreateCard = navigateToCreateCard, onBackClick = onBackClick, - navigateToChangeBackgroundScreen = navigateToChangeBackgroundScreen + navigateToChangeBackgroundScreen = navigateToChangeBackgroundScreen, + boardId = backStackEntry.arguments?.getLong("boardId") ) } } diff --git a/feature/taskboard/src/main/java/com/jetapps/jettaskboard/vm/TaskBoardViewModel.kt b/feature/taskboard/src/main/java/com/jetapps/jettaskboard/vm/TaskBoardViewModel.kt index 74fd9b8..1d635a2 100644 --- a/feature/taskboard/src/main/java/com/jetapps/jettaskboard/vm/TaskBoardViewModel.kt +++ b/feature/taskboard/src/main/java/com/jetapps/jettaskboard/vm/TaskBoardViewModel.kt @@ -5,6 +5,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue +import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.jetapps.jettaskboard.board.ExpandedBoardDrawerState @@ -23,18 +24,22 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.launch +import timber.log.Timber import javax.inject.Inject @HiltViewModel class TaskBoardViewModel @Inject constructor( + savedStateHandle: SavedStateHandle, private val getLatestBackgroundImgUrlUseCase: GetLatestBackgroundImgUrlUseCase, private val getBoardDetailsUseCase: GetBoardDetailsUseCase, private val createCardUseCase: CreateCardUseCase, - private val updateCardUseCase: UpdateCardUseCase, private val deleteCardUseCase: DeleteCardUseCase, private val createNewListUseCase: CreateNewListUseCase, ) : ViewModel() { + private val passedBoardId = savedStateHandle.get("boardId") + get() = field + /** * Defines a list of [ListModel]s which has a list of [CardModel]s internally. * The list of [ListModel]s is used to setup the row of lists (eg: To-do, InProgress, Completed, etc.) in the [Board]. @@ -43,13 +48,6 @@ class TaskBoardViewModel @Inject constructor( private val _lists: MutableStateFlow> = MutableStateFlow(emptyList()) val lists: StateFlow> = _lists - /** - * A counter of the total number of cards in the board, maintained to assign a unique - * index everytime a new card gets added to the board in a particular list, which in also - * used to run recomposition whenever the new card is added. - */ - private var totalCards by mutableIntStateOf(0) - var boardId by mutableIntStateOf(0) var boardTitle by mutableStateOf("Board Dummy Title") var latestBackgroundImgUri by mutableStateOf("") @@ -78,33 +76,33 @@ class TaskBoardViewModel @Inject constructor( * A new Card has to be inserted in the list Cards of a Board */ private fun getBoardData() { + println("Test Passed Id $passedBoardId") viewModelScope.launch { - getBoardDetailsUseCase.invoke(boardId) - .distinctUntilChanged() - .collect { result -> - println(result) - boardTitle = result.boardTitle - // Executed for once when ui is loaded - _lists.emit( - result.listModel - ) - } + passedBoardId?.let { safeId -> + getBoardDetailsUseCase.invoke(safeId) + .distinctUntilChanged() + .collect { result -> + println("Test getBoardData $result") + Timber.tag("DAO").d("getBoardData: %s", result) + boardTitle = result?.boardTitle ?: "" + result?.listModel?.let { boardLists -> + _lists.emit( + boardLists + ) + } + } + } } } - fun addNewCardInList(listId: Int) { + fun addNewCardInList(listId: Long) { viewModelScope.launch { - totalCards = 0 - updateTheTotalCardCount(_lists.value.size + 1) createCardUseCase.invoke( CardModel( - id = totalCards, title = "New Card", listId = listId, description = "", - coverImageUrl = "", - labels = emptyList(), - boardId = boardId, + boardId = passedBoardId ?: 0, authorId = "" ), ) @@ -119,19 +117,26 @@ class TaskBoardViewModel @Inject constructor( viewModelScope.launch { // Locate the card to be moved val cardToMove = - _lists.value.find { it.listId == oldListId }?.cards?.find { it.id == cardId } + _lists.value.find { it.listId?.toInt() == oldListId }?.cards?.find { it.id.toInt() == cardId } // Removing a card from one list and adding to a new list // Basically, modifying the internal data of two list-items simultaneously cardToMove?.let { safeCard -> - _lists.value.find { it.listId == oldListId }?.cards?.removeIf { it.id == safeCard.id } - _lists.value.find { it.listId == newListId }?.cards?.add(safeCard.copy(listId = newListId)) + _lists.value.find { it.listId?.toInt() == oldListId }?.cards?.removeIf { it.id == safeCard.id } + _lists.value.find { it.listId?.toInt() == newListId }?.cards?.add( + safeCard.copy( + listId = newListId.toLong() + ) + ) } } } - fun addNewList() { - val model = ListModel(listId = _lists.value.size + 1, title = "New List", boardId = boardId) + fun addNewList(listTitle: String) { + val model = ListModel( + title = listTitle, + boardId = passedBoardId + ) viewModelScope.launch { createNewListUseCase.invoke( model @@ -142,8 +147,4 @@ class TaskBoardViewModel @Inject constructor( fun changeExpandedScreenState(newState: ExpandedBoardDrawerState) { _drawerScreenState.value = newState } - - private fun updateTheTotalCardCount(newValue: Int) { - totalCards = newValue - } }