Skip to content
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@
.externalNativeBuild
.cxx
local.properties
/app/src/main/java/com/example/listifyjetapp/utils/constants/Constants.kt
10 changes: 7 additions & 3 deletions app/src/main/java/com/example/listifyjetapp/model/ListModel.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package com.example.listifyjetapp.model

import java.time.LocalDateTime
import com.google.gson.annotations.SerializedName

data class ListModel(
val id: Int,
val name: String,
val share: Boolean,
val shareCode: String, // can be UUID or String
val createdAt: LocalDateTime
//val sharedCode: String, // can be UUID or String
//val createdAt: LocalDateTime
@SerializedName("shared_code") val sharedCode: String,
@SerializedName("created_at") val createdAt: String,
@SerializedName("item_count") val itemCount: Int,
@SerializedName("shared_with") val sharedWith: List<SharedUsers>
)
17 changes: 17 additions & 0 deletions app/src/main/java/com/example/listifyjetapp/model/User.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.example.listifyjetapp.model

import com.google.gson.annotations.SerializedName

data class User(
val id: Int,
val username: String,
val email: String,
val password: String,
@SerializedName("created_at") val createdAt: String
)

data class SharedUsers(
@SerializedName("user_id") val userId: Int,
val username: String,
)

102 changes: 102 additions & 0 deletions app/src/main/java/com/example/listifyjetapp/screens/lists/ListRow.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package com.example.listifyjetapp.screens.lists

import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
import androidx.compose.material.icons.filled.Share
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.listifyjetapp.model.ListModel
import com.example.listifyjetapp.ui.theme.ListifyColor

@Composable
fun ListRow(
list: ListModel,
//viewModel: User
) {
Row(
modifier = Modifier
.clickable { }
.padding(vertical = 16.dp)
.fillMaxWidth()
.background(Color.Transparent)
) {
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
// List info
Column(
modifier = Modifier.padding(horizontal = 8.dp),

) {
Text(
text = list.name,
color = ListifyColor.TextBlack,
fontSize = 20.sp,
//fontWeight = FontWeight.SemiBold
)

if (list.share) {
Row(
verticalAlignment = Alignment.CenterVertically
) {
Icon(
modifier = Modifier.size(16.dp),
tint = ListifyColor.IconGreen,
imageVector = Icons.Default.Share,
contentDescription = "Shared with"
)
Text(
text = list.sharedWith.take(3).joinToString(", ") { it.username },
maxLines = 1,
overflow = TextOverflow.Ellipsis,
color = ListifyColor.TextGrey,
fontSize = 16.sp
)
}
}

Text(
text = list.createdAt,
color = ListifyColor.TextGrey,
fontSize = 16.sp
)
}
// List setting menu

Row() {
Text(
text = list.itemCount.toString(),
color = ListifyColor.TextGrey,
fontSize = 16.sp
)

Icon(
imageVector = Icons.AutoMirrored.Filled.KeyboardArrowRight,
contentDescription = "Forward icon"
)

}

}

}
HorizontalDivider()
}
Original file line number Diff line number Diff line change
@@ -1,40 +1,92 @@
package com.example.listifyjetapp.screens.lists

import android.util.Log
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
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.foundation.text.KeyboardActions
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import com.example.listifyjetapp.widgets.ListifySearchBar
import com.example.listifyjetapp.widgets.ListifyTopBar

@Composable
fun ListifyListsScreen(
viewModel: ListsViewModel = hiltViewModel()
) {
LaunchedEffect(Unit) { viewModel.getUserLists(4) }

Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Scaffold(
modifier = Modifier.fillMaxSize(),
topBar = { ListifyTopBar(
title = "Lists",
isListsScreen = true,
) }
) { innerPadding ->

Surface(
modifier = Modifier.fillMaxSize().padding(innerPadding)
) {
Column(
modifier = Modifier.padding(horizontal = 16.dp),
verticalArrangement = Arrangement.Top,
horizontalAlignment = Alignment.CenterHorizontally
) {
//val lists =viewModel.lists
//Log.d("Lists", lists.toString())
val searchTextState = rememberSaveable { mutableStateOf("") }
val keyboardController = LocalSoftwareKeyboardController.current

if (viewModel.lists.isEmpty()) {
Text(text = "You don't have any lists yet.")
} else {
LazyColumn {
items(viewModel.lists) {list ->
Text(text = list.name)
ListifySearchBar(
searchTextValue = searchTextState,
onValueChange = {searchTextState.value = it},
keyboardAction = KeyboardActions{
// Trigger search logic or hide keyboard
searchTextState.value.trim() // perform the search
searchTextState.value = "" // clear text field when click Done, Next, etc
keyboardController?.hide() // hide keyboard
}
)
//Text(text = "You don't have any lists yet.")

if (viewModel.isLoading.value) {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
CircularProgressIndicator()
}
} else if (viewModel.lists.isEmpty()) {
Text(text = "You don't have any lists yet.")
} else {
LazyColumn(modifier = Modifier.padding(
vertical = 16.dp,
horizontal = 8.dp
)){

items(viewModel.lists) {list ->

ListRow(list)

}
}
}
}
}
}

}
Original file line number Diff line number Diff line change
@@ -1,29 +1,35 @@
package com.example.listifyjetapp.screens.lists

import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.listifyjetapp.data.ListifyResult
import com.example.listifyjetapp.model.ListModel
import com.example.listifyjetapp.repository.ListsRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class ListsViewModel @Inject constructor(private val repository: ListsRepository): ViewModel() {
val lists = mutableStateListOf<ListModel>()
var isLoading = mutableStateOf(false)

fun getUserLists(userId: Int) {
viewModelScope.launch {
val result = repository.getUserLists(userId = userId)
when(result) {
is ListifyResult.Success -> {
lists.clear()
lists.addAll(result.data)
isLoading.value = true
val result = repository.getUserLists(userId = userId)
when (result) {
is ListifyResult.Success -> {
lists.clear()
lists.addAll(result.data)
}

is ListifyResult.Failure -> Unit
}
is ListifyResult.Failure -> Unit
}
isLoading.value = false
}
}
}
2 changes: 2 additions & 0 deletions app/src/main/java/com/example/listifyjetapp/ui/theme/Color.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ val Pink40 = Color(0xFF7D5260)

object ListifyColor {
val SplashYellow = Color(0xFFFFCA3A)
val TextBlack = Color(0xff000000)
val TextDark = Color(0xff3e4e50)
val TextGrey = Color(0xff858585)
val IconGreen = Color(0xff0cc25f)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.example.listifyjetapp.widgets


import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.text.input.InputTransformation.Companion.keyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Search
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import com.example.listifyjetapp.ui.theme.ListifyColor


@Composable
fun ListifySearchBar(
searchTextValue: MutableState<String>,
onValueChange: (String) -> Unit,
imeAction: ImeAction = ImeAction.Next, // what happen when you press "Next"
keyboardAction: KeyboardActions = KeyboardActions.Default // what to do when an action is triggered
) {
TextField(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(12.dp),
colors = TextFieldDefaults.colors(
unfocusedIndicatorColor = Color.Transparent,
focusedIndicatorColor = Color.Transparent,
disabledIndicatorColor = Color.Transparent,

unfocusedLabelColor = ListifyColor.TextDark.copy(0.1f),
focusedContainerColor = ListifyColor.TextDark.copy(0.1f),
cursorColor = ListifyColor.TextDark,
),
singleLine = true,
maxLines = 1,
leadingIcon = {
Icon(
imageVector = Icons.Default.Search,
contentDescription = "Search icon",
)
},

value = searchTextValue.value,
onValueChange = onValueChange,
placeholder = { Text(text="Search") },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text), // Sets the keyboard to normal text input.
keyboardActions = keyboardAction,
)
}
Loading