diff --git a/android/build.gradle.kts b/android/build.gradle.kts index 43414fb..7bb08ca 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -20,6 +20,8 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget plugins { alias(libs.plugins.android.application) alias(libs.plugins.compose) + // necessary for using T.serializer() on a data class + alias(libs.plugins.kotlin.serialization) } android { @@ -96,6 +98,7 @@ dependencies { implementation(libs.androidx.glance.material3) implementation(libs.kotlin.stdlib) implementation(libs.kotlinx.coroutines.android) + implementation(libs.kotlinx.serialization.json) implementation(libs.androidx.activity.compose) @@ -115,6 +118,10 @@ dependencies { implementation(libs.androidx.compose.ui.viewbinding) implementation(libs.androidx.compose.ui.googlefonts) + implementation(libs.ktor.client.auth) + implementation(libs.ktor.client.core) + implementation(libs.ktor.client.cio) + debugImplementation(libs.androidx.compose.ui.test.manifest) androidTestImplementation(libs.junit) diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index 676ce5b..6f87e86 100644 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -9,6 +9,8 @@ + + insets } + var deviceDtoList: List = listOf() + viewModel.viewModelScope.launch { + val networkClient = NetworkClient() + deviceDtoList = networkClient.getDevices() + } + setContentView( ComposeView(this).apply { consumeWindowInsets = false @@ -79,15 +90,18 @@ class NavActivity : AppCompatActivity() { JetchatDrawer( drawerState = drawerState, selectedMenu = selectedMenu, + deviceDtoList = deviceDtoList, onChatClicked = { findNavController().popBackStack(R.id.nav_device, false) val args = Bundle(1) - args.putString("deviceName", it) + args.putString("deviceId", it.access_key) + args.putString("name", it.name) + args.putString("type", it.type) findNavController().navigate(R.id.nav_device, args) scope.launch { drawerState.close() } - selectedMenu = it + selectedMenu = it.access_key }, ) { AndroidViewBinding(ContentMainBinding::inflate) diff --git a/android/src/main/kotlin/xyz/magicalbits/smsremote/components/JetchatDrawer.kt b/android/src/main/kotlin/xyz/magicalbits/smsremote/components/JetchatDrawer.kt index d46e26a..490bfd9 100644 --- a/android/src/main/kotlin/xyz/magicalbits/smsremote/components/JetchatDrawer.kt +++ b/android/src/main/kotlin/xyz/magicalbits/smsremote/components/JetchatDrawer.kt @@ -56,11 +56,12 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import xyz.magicalbits.smsremote.R +import xyz.magicalbits.smsremote.network.NetworkClient import xyz.magicalbits.smsremote.theme.JetchatTheme import xyz.magicalbits.smsremote.widget.WidgetReceiver @Composable -fun JetchatDrawerContent(onChatClicked: (String) -> Unit, selectedMenu: String = "iPhone XYZ") { +fun JetchatDrawerContent(onChatClicked: (NetworkClient.DeviceDto) -> Unit, selectedMenu: String = "", deviceDtoList: List = listOf()) { // Use windowInsetsTopHeight() to add a spacer which pushes the drawer content // below the status bar (y-axis) Column { @@ -68,12 +69,13 @@ fun JetchatDrawerContent(onChatClicked: (String) -> Unit, selectedMenu: String = DrawerHeader() DividerItem() DrawerItemHeader("Devices") - DeviceItem("Samsung A14", selectedMenu == "Samsung A14") { - onChatClicked("Samsung A14") - } - DeviceItem("iPhone XYZ", selectedMenu == "iPhone XYZ") { - onChatClicked("iPhone XYZ") + + for (deviceDto in deviceDtoList) { + DeviceItem(deviceDto.name, selectedMenu == deviceDto.access_key) { + onChatClicked(deviceDto) + } } + // DividerItem(modifier = Modifier.padding(horizontal = 28.dp)) if (widgetAddingIsSupported(LocalContext.current)) { DividerItem(modifier = Modifier.padding(horizontal = 28.dp)) diff --git a/android/src/main/kotlin/xyz/magicalbits/smsremote/components/JetchatScaffold.kt b/android/src/main/kotlin/xyz/magicalbits/smsremote/components/JetchatScaffold.kt index 257ab78..7cf827f 100644 --- a/android/src/main/kotlin/xyz/magicalbits/smsremote/components/JetchatScaffold.kt +++ b/android/src/main/kotlin/xyz/magicalbits/smsremote/components/JetchatScaffold.kt @@ -23,13 +23,15 @@ import androidx.compose.material3.ModalDrawerSheet import androidx.compose.material3.ModalNavigationDrawer import androidx.compose.material3.rememberDrawerState import androidx.compose.runtime.Composable +import xyz.magicalbits.smsremote.network.NetworkClient import xyz.magicalbits.smsremote.theme.JetchatTheme @Composable fun JetchatDrawer( drawerState: DrawerState = rememberDrawerState(initialValue = Closed), selectedMenu: String, - onChatClicked: (String) -> Unit, + deviceDtoList: List, + onChatClicked: (NetworkClient.DeviceDto) -> Unit, content: @Composable () -> Unit, ) { JetchatTheme { @@ -44,6 +46,7 @@ fun JetchatDrawer( JetchatDrawerContent( onChatClicked = onChatClicked, selectedMenu = selectedMenu, + deviceDtoList = deviceDtoList, ) } }, diff --git a/android/src/main/kotlin/xyz/magicalbits/smsremote/data/FakeData.kt b/android/src/main/kotlin/xyz/magicalbits/smsremote/data/FakeData.kt index defc460..d8a7d86 100644 --- a/android/src/main/kotlin/xyz/magicalbits/smsremote/data/FakeData.kt +++ b/android/src/main/kotlin/xyz/magicalbits/smsremote/data/FakeData.kt @@ -87,17 +87,3 @@ val meProfile = timeZone = "In your timezone", commonChannels = null, ) - -val a14Device = - DeviceScreenState( - deviceId = "012345", - name = "Samsung A14", - phoneNumbers = listOf("+420123456789", "+420777444111") - ) - -val iPhoneDevice = - DeviceScreenState( - deviceId = "012345", - name = "iPhone XYZ", - phoneNumbers = listOf("+15558881111") - ) diff --git a/android/src/main/kotlin/xyz/magicalbits/smsremote/device/DeviceFragment.kt b/android/src/main/kotlin/xyz/magicalbits/smsremote/device/DeviceFragment.kt index d1a6c5c..297d523 100644 --- a/android/src/main/kotlin/xyz/magicalbits/smsremote/device/DeviceFragment.kt +++ b/android/src/main/kotlin/xyz/magicalbits/smsremote/device/DeviceFragment.kt @@ -9,7 +9,6 @@ import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.platform.ComposeView @@ -24,7 +23,6 @@ import xyz.magicalbits.smsremote.components.JetchatAppBar import xyz.magicalbits.smsremote.theme.JetchatTheme import kotlin.getValue import androidx.navigation.findNavController -import kotlinx.coroutines.launch class DeviceFragment : Fragment() { private val viewModel: DeviceViewModel by viewModels() @@ -33,8 +31,10 @@ class DeviceFragment : Fragment() { override fun onAttach(context: Context) { super.onAttach(context) // Consider using safe args plugin - val deviceName = arguments?.getString("deviceName") - viewModel.setDeviceId(deviceName) + val deviceId = arguments?.getString("deviceId") + val name = arguments?.getString("name") + val type = arguments?.getString("type") + viewModel.setDeviceData(deviceId, name, type) } @OptIn(ExperimentalComposeUiApi::class, ExperimentalMaterial3Api::class) @@ -65,6 +65,7 @@ class DeviceFragment : Fragment() { JetchatTheme { if (deviceData == null) { + println("calling device error") DeviceError() } else { val navController: NavController = rootView.findNavController() diff --git a/android/src/main/kotlin/xyz/magicalbits/smsremote/device/DeviceViewModel.kt b/android/src/main/kotlin/xyz/magicalbits/smsremote/device/DeviceViewModel.kt index 179cada..0eb277e 100644 --- a/android/src/main/kotlin/xyz/magicalbits/smsremote/device/DeviceViewModel.kt +++ b/android/src/main/kotlin/xyz/magicalbits/smsremote/device/DeviceViewModel.kt @@ -4,26 +4,39 @@ import androidx.compose.runtime.Immutable import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel -import xyz.magicalbits.smsremote.data.a14Device -import xyz.magicalbits.smsremote.data.iPhoneDevice +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.launch +import xyz.magicalbits.smsremote.network.NetworkClient class DeviceViewModel : ViewModel() { private var deviceId: String = "" private val _deviceData = MutableLiveData() val deviceData: LiveData = _deviceData - fun setDeviceId(newDeviceId: String?) { - if (newDeviceId != null) { + fun setDeviceData(newDeviceId: String?, name: String?, type: String?) { + if (newDeviceId != null && name != null) { deviceId = newDeviceId - } - // placeholder since there's no API reading logic yet - _deviceData.value = - if (deviceId == "Samsung A14") { - a14Device - } else { - iPhoneDevice + var simCardDtoList: List = listOf() + viewModelScope.launch { + val networkClient = NetworkClient() + simCardDtoList = networkClient.getSimCardsByAccessKey(deviceId) + println("sims: $simCardDtoList") + }.invokeOnCompletion { + // FIXME waiting for the response causes brief moment of DeviceError() before _deviceData is updated ... + // a solution: caching SIM phone numbers of all discovered devices locally on startup and updating them + // only on startup (implicit behavior) or with a pull-down refresh action (not done yet) + + // placeholder since there's no API reading logic yet + _deviceData.value = + DeviceScreenState( + deviceId = deviceId, + name = name, + phoneNumbers = simCardDtoList.map { it.phone_number }, + ) + println("sims live: ${_deviceData.value!!.phoneNumbers}") } + } } } diff --git a/android/src/main/res/navigation/mobile_navigation.xml b/android/src/main/res/navigation/mobile_navigation.xml index 84b650c..eac44a3 100644 --- a/android/src/main/res/navigation/mobile_navigation.xml +++ b/android/src/main/res/navigation/mobile_navigation.xml @@ -43,6 +43,12 @@ + +