wip: wiring network client
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
<uses-permission android:name="android.provider.Telephony.SMS_RECEIVED" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:enableOnBackInvokedCallback="true"
|
||||
|
||||
@@ -32,19 +32,24 @@ import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.viewinterop.AndroidViewBinding
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.builtins.serializer
|
||||
import kotlinx.serialization.json.Json
|
||||
import xyz.magicalbits.smsremote.components.JetchatDrawer
|
||||
import xyz.magicalbits.smsremote.databinding.ContentMainBinding
|
||||
import xyz.magicalbits.smsremote.network.NetworkClient
|
||||
|
||||
/**
|
||||
* Main activity for the app.
|
||||
*/
|
||||
class NavActivity : AppCompatActivity() {
|
||||
|
||||
private val viewModel: MainViewModel by viewModels()
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@@ -53,6 +58,12 @@ class NavActivity : AppCompatActivity() {
|
||||
super.onCreate(savedInstanceState)
|
||||
ViewCompat.setOnApplyWindowInsetsListener(window.decorView) { _, insets -> insets }
|
||||
|
||||
var deviceDtoList: List<NetworkClient.DeviceDto> = 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)
|
||||
|
||||
@@ -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<NetworkClient.DeviceDto> = 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")
|
||||
|
||||
for (deviceDto in deviceDtoList) {
|
||||
DeviceItem(deviceDto.name, selectedMenu == deviceDto.access_key) {
|
||||
onChatClicked(deviceDto)
|
||||
}
|
||||
DeviceItem("iPhone XYZ", selectedMenu == "iPhone XYZ") {
|
||||
onChatClicked("iPhone XYZ")
|
||||
}
|
||||
|
||||
// DividerItem(modifier = Modifier.padding(horizontal = 28.dp))
|
||||
if (widgetAddingIsSupported(LocalContext.current)) {
|
||||
DividerItem(modifier = Modifier.padding(horizontal = 28.dp))
|
||||
|
||||
@@ -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<NetworkClient.DeviceDto>,
|
||||
onChatClicked: (NetworkClient.DeviceDto) -> Unit,
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
JetchatTheme {
|
||||
@@ -44,6 +46,7 @@ fun JetchatDrawer(
|
||||
JetchatDrawerContent(
|
||||
onChatClicked = onChatClicked,
|
||||
selectedMenu = selectedMenu,
|
||||
deviceDtoList = deviceDtoList,
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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")
|
||||
)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -4,25 +4,38 @@ 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<DeviceScreenState>()
|
||||
val deviceData: LiveData<DeviceScreenState> = _deviceData
|
||||
|
||||
fun setDeviceId(newDeviceId: String?) {
|
||||
if (newDeviceId != null) {
|
||||
fun setDeviceData(newDeviceId: String?, name: String?, type: String?) {
|
||||
if (newDeviceId != null && name != null) {
|
||||
deviceId = newDeviceId
|
||||
}
|
||||
|
||||
var simCardDtoList: List<NetworkClient.SimCardDto> = 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 =
|
||||
if (deviceId == "Samsung A14") {
|
||||
a14Device
|
||||
} else {
|
||||
iPhoneDevice
|
||||
DeviceScreenState(
|
||||
deviceId = deviceId,
|
||||
name = name,
|
||||
phoneNumbers = simCardDtoList.map { it.phone_number },
|
||||
)
|
||||
println("sims live: ${_deviceData.value!!.phoneNumbers}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,12 @@
|
||||
<argument
|
||||
android:name="deviceId"
|
||||
app:argType="string" />
|
||||
<argument
|
||||
android:name="name"
|
||||
app:argType="string" />
|
||||
<argument
|
||||
android:name="type"
|
||||
app:argType="string" />
|
||||
<action
|
||||
android:id="@+id/action_device_to_conversation"
|
||||
app:destination="@id/nav_conversation"
|
||||
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
uv run gunicorn app:app \
|
||||
uv run gunicorn -b 0.0.0.0:5000 app:app \
|
||||
--reload
|
||||
|
||||
@@ -37,6 +37,7 @@ gradle-versions = "0.54.0"
|
||||
hilt = "2.59.2"
|
||||
hiltExt = "1.3.0"
|
||||
horologist = "0.7.15"
|
||||
ktor-client = "3.5.0"
|
||||
jdkDesugar = "2.1.5"
|
||||
junit = "4.13.2"
|
||||
kotlin = "2.3.21"
|
||||
@@ -147,6 +148,9 @@ kotlinx-collections-immutable = { module = "org.jetbrains.kotlinx:kotlinx-collec
|
||||
kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "coroutines" }
|
||||
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "coroutines" }
|
||||
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization-json" }
|
||||
ktor-client-auth = { module = "io.ktor:ktor-client-auth", version.ref = "ktor-client"}
|
||||
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor-client"}
|
||||
ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor-client"}
|
||||
okhttp-logging = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttp" }
|
||||
okhttp3 = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
|
||||
play-services-wearable = { module = "com.google.android.gms:play-services-wearable", version.ref = "play-services-wearable" }
|
||||
|
||||
Reference in New Issue
Block a user