Skip to content

Commit

Permalink
feat: done all functionalities
Browse files Browse the repository at this point in the history
  • Loading branch information
Agung-Krisna committed Jul 10, 2024
1 parent 6687341 commit d47e5cb
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 60 deletions.
6 changes: 6 additions & 0 deletions .idea/appInsightsSettings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 1 addition & 12 deletions .idea/deploymentTargetSelector.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import id.my.kaorikizuna.incu8tor.ui.home.HomeScreen
import id.my.kaorikizuna.incu8tor.ui.theme.Incu8torTheme
import id.my.kaorikizuna.incu8tor.viewmodel.DeviceViewModel

// TODO add the search functionality on home screen
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ data class DeviceDetail(
var settings: DeviceSettings,
var sensors: DeviceSensors,
) {
// computed property
val insensitiveName: String
get() = deviceName.lowercase()

constructor() : this(
false,
0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@ fun AddDeviceScreen(onSave: (DeviceDetail) -> Unit, onBackClicked: () -> Unit) {
value = deviceDetail.deviceName,
onValueChange = {
setDeviceDetail(deviceDetail.copy(deviceName = it))
// deviceDetail.deviceName = it
},
label = { Text("Input Device Name") },
modifier = Modifier.fillMaxWidth()
Expand All @@ -115,7 +114,6 @@ fun AddDeviceScreen(onSave: (DeviceDetail) -> Unit, onBackClicked: () -> Unit) {
value = deviceDetail.macAddress,
onValueChange = {
setDeviceDetail(deviceDetail.copy(macAddress = it))
// deviceDetail.macAddress = it
},
label = { Text("Input MAC Address") },
modifier = Modifier.fillMaxWidth()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,42 +27,55 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import id.my.kaorikizuna.incu8tor.R


// title changed if searching or not
// TODO implement this
fun onSearchClicked(searchTitle: String) {
println("Searched for $searchTitle")
}
//fun onSearchClicked(
// searchQuery: String,
// onSuccess: (List<DeviceDetail>) -> Unit,
// onFailure: (Exception) -> Unit
//) {
// val viewModel = DeviceViewModel()
// viewModel.searchDevices(query = searchQuery, onSuccess = onSuccess, onFailure = onFailure)
//}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun Incu8torSearchBar(onSearchClicked: (String) -> Unit) {
fun Incu8torSearchBar(
onSearchInitiated: (String) -> Unit,
onSearchClicked: () -> Unit,
onBackClicked: () -> Unit
) {
var showSearchField by remember { mutableStateOf(false) }
TopAppBar(title = {
if (showSearchField) {
Surface(
modifier = Modifier.fillMaxWidth(),
) {
SearchField(onSearchClicked)
SearchField(onSearchInitiated)
}
SearchField(onSearchClicked)
} else {
Text(stringResource(id = R.string.app_name))
}
}, actions = {
if (!showSearchField) {
IconButton(onClick = { showSearchField = true }) {
IconButton(onClick = {
showSearchField = true
onSearchClicked()
}) {
Icon(imageVector = Icons.Filled.Search, contentDescription = "Search")
}
}
}, modifier = Modifier.fillMaxWidth(),
// this is quite handy
navigationIcon = {
if (showSearchField) {
IconButton(onClick = { showSearchField = false }) {
IconButton(onClick = {
showSearchField = false
onBackClicked()
}) {
Icon(imageVector = Icons.Filled.ArrowBack, contentDescription = "Back")
}
}
Expand All @@ -89,12 +102,12 @@ fun Incu8torModifiableTopBar(
)
}

@Preview
@Composable
fun Incu8torSearchBarPreview() {
// function reference (::) is used to pass the function as a parameter
Incu8torSearchBar(::onSearchClicked)
}
//@Preview
//@Composable
//fun Incu8torSearchBarPreview() {
// // function reference (::) is used to pass the function as a parameter
// Incu8torSearchBar(::onSearchClicked)
//}

@Composable
fun SearchField(
Expand Down
59 changes: 29 additions & 30 deletions app/src/main/java/id/my/kaorikizuna/incu8tor/ui/home/HomeScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,29 +30,18 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import id.my.kaorikizuna.incu8tor.R
import id.my.kaorikizuna.incu8tor.model.Device
import id.my.kaorikizuna.incu8tor.model.DeviceDetail
import id.my.kaorikizuna.incu8tor.ui.components.Incu8torSearchBar
import id.my.kaorikizuna.incu8tor.ui.components.ErrorToast
import id.my.kaorikizuna.incu8tor.ui.components.onSearchClicked
import id.my.kaorikizuna.incu8tor.viewmodel.DeviceViewModel

// dummy devices
val devices = listOf(
Device(
name = "Incubator Kandang Timur", macAddress = "77:63:74:8B:62:E8", isConnected = true
),
Device(
name = "Incubator Kandang Barat", macAddress = "41:00:FB:64:82:BA", isConnected = false
),
)

@Composable
fun HomeScreen(navController: NavController, onDeviceClicked: (DeviceDetail) -> Unit) {
val viewModel = DeviceViewModel()

// turns out that the second positional argument of remember is the setter function,
val (devices, setDevices) = remember { mutableStateOf(emptyList<DeviceDetail>()) }
val showSearchedDevices = remember { mutableStateOf(false) }

// declaring error toast
val errorToast = remember { ErrorToast() }
Expand All @@ -63,7 +52,23 @@ fun HomeScreen(navController: NavController, onDeviceClicked: (DeviceDetail) ->
}

Scaffold(topBar = {
Incu8torSearchBar(::onSearchClicked)
Incu8torSearchBar(onSearchInitiated = { query ->
viewModel.searchDevices(query,
onSuccess = { devices ->
setDevices(devices)
Log.d("device", "$devices")
},
onFailure = { exception -> errorToast.show(exception.message.toString()) })
},
// on search, empty the devices first
onSearchClicked = {
showSearchedDevices.value = true
setDevices(emptyList())
},
// on back, repopulate the devices
onBackClicked = {
showSearchedDevices.value = false
})
}, floatingActionButton = {
FloatingActionButton(
onClick = { navController.navigate("addDevice") },
Expand All @@ -75,25 +80,21 @@ fun HomeScreen(navController: NavController, onDeviceClicked: (DeviceDetail) ->
}
}) { innerPadding ->
Column {

viewModel.getAllDevices(onSuccess = {
setDevices(it)
Log.d("devices", "$devices ${it.size}")
}, onFailure = { exception ->
errorToast.show(exception.message.toString())
})

if (!showSearchedDevices.value) {
viewModel.getAllDevices(onSuccess = {
setDevices(it)
Log.d("devices", "$devices ${it.size}")
}, onFailure = { exception ->
errorToast.show(exception.message.toString())
})
}
Spacer(modifier = Modifier.height(10.dp))

LazyColumn(
modifier = Modifier.padding(innerPadding),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
items(devices) { device ->
DeviceCard(
device,
onClick = { onDeviceClicked(device) }
)
DeviceCard(device, onClick = { onDeviceClicked(device) })
}
}
}
Expand All @@ -113,12 +114,10 @@ fun DeviceCard(deviceDetail: DeviceDetail, onClick: () -> Unit) {
) {
Column(verticalArrangement = Arrangement.spacedBy(4.dp)) {
Text(
text = deviceDetail.deviceName,
style = MaterialTheme.typography.titleMedium
text = deviceDetail.deviceName, style = MaterialTheme.typography.titleMedium
)
Text(
text = deviceDetail.macAddress,
style = MaterialTheme.typography.bodySmall
text = deviceDetail.macAddress, style = MaterialTheme.typography.bodySmall
)
}
// the icon needs to be within a container (box or row) to be able to be centered vertically
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,32 @@ class DeviceViewModel : ViewModel() {
val deactivatedDevice = mapOf("active" to false)
devicesReference.child(device.macAddress).updateChildren(deactivatedDevice)
}

fun searchDevices(
query: String,
onSuccess: (List<DeviceDetail>) -> Unit,
onFailure: (Exception) -> Unit
) {
val devices = mutableListOf<DeviceDetail>()

// endAt is tricking the firebase to search all possible permutations of the query
devicesReference.orderByChild("deviceName").startAt(query).endAt("$query\uf8ff")
.addValueEventListener(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
for (snapshot in dataSnapshot.children) {
val device = snapshot.getValue(DeviceDetail::class.java)!!
device.macAddress = snapshot.key.toString()
if (device.active) {
devices.add(device)
}
}
return onSuccess(devices)
}

override fun onCancelled(error: DatabaseError) {
Log.w(TAG, "Failed to read value.", error.toException())
return onFailure(error.toException())
}
})
}
}

0 comments on commit d47e5cb

Please sign in to comment.