Updated Proper User Api

This commit is contained in:
Chandresh Kerkar 2025-12-21 02:18:00 +05:30
parent 1277ae09b6
commit 80cc72bb9d
2 changed files with 196 additions and 18 deletions

View File

@ -217,6 +217,55 @@ class AuthApiClient(private val context: Context) {
response response
} }
// Test API: Get user by ID from BuySellService (port 3200)
suspend fun getUserById(userId: String, baseUrl: String = "http://10.0.2.2:3200"): Result<String> = runCatching {
android.util.Log.d("AuthApiClient", "getUserById: Calling $baseUrl/users/$userId")
// Create a separate client for this external service call
HttpClient(CIO) {
install(ContentNegotiation) {
json(Json {
prettyPrint = true
isLenient = true
ignoreUnknownKeys = true
})
}
install(Auth) {
bearer {
loadTokens {
val accessToken = tokenManager.getAccessToken()
if (accessToken != null) {
BearerTokens(accessToken, "")
} else {
null
}
}
}
}
defaultRequest {
url(baseUrl)
}
}.use { testClient ->
val response = testClient.get("users/$userId")
android.util.Log.d("AuthApiClient", "getUserById: Response status=${response.status}")
if (response.status.isSuccess()) {
// Get raw JSON string
val jsonString = response.bodyAsText()
android.util.Log.d("AuthApiClient", "getUserById: Success - JSON=${jsonString.take(200)}...")
jsonString
} else {
val errorText = try {
response.bodyAsText()
} catch (e: Exception) {
"Error reading response body"
}
android.util.Log.e("AuthApiClient", "getUserById: Error - status=${response.status}, body=$errorText")
throw Exception("API call failed: ${response.status} - $errorText")
}
}
}
private fun getDeviceInfo(): DeviceInfo { private fun getDeviceInfo(): DeviceInfo {
return DeviceInfo( return DeviceInfo(
platform = "android", platform = "android",

View File

@ -4,28 +4,24 @@ import android.widget.Toast
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.automirrored.filled.Logout import androidx.compose.material.icons.automirrored.filled.Logout
import androidx.compose.material.icons.filled.Construction import androidx.compose.material.icons.filled.Construction
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.*
import androidx.compose.material3.Icon import androidx.compose.runtime.*
import androidx.compose.material3.IconButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.Dialog
import com.example.livingai_lg.api.AuthApiClient import com.example.livingai_lg.api.AuthApiClient
import com.example.livingai_lg.api.AuthManager import com.example.livingai_lg.api.AuthManager
import com.example.livingai_lg.api.TokenManager import com.example.livingai_lg.api.TokenManager
@ -41,6 +37,12 @@ fun AccountsScreen(
val context = LocalContext.current val context = LocalContext.current
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val authManager = remember { AuthManager(context, AuthApiClient(context), TokenManager(context)) } val authManager = remember { AuthManager(context, AuthApiClient(context), TokenManager(context)) }
val apiClient = remember { AuthApiClient(context) }
// State for API test dialog
var showApiResultDialog by remember { mutableStateOf(false) }
var apiResultJson by remember { mutableStateOf<String?>(null) }
var isLoading by remember { mutableStateOf(false) }
Column( Column(
modifier = Modifier modifier = Modifier
@ -130,7 +132,44 @@ fun AccountsScreen(
modifier = Modifier modifier = Modifier
.fillMaxWidth().padding(vertical = 12.dp) .fillMaxWidth().padding(vertical = 12.dp)
.clickable { .clickable {
onApiTest() // Call API test directly instead of navigating
scope.launch {
isLoading = true
try {
// First get current user's ID
val userDetails = apiClient.getUserDetails().getOrNull()
if (userDetails != null) {
// Call GET /users/:userId on port 3200
val result = apiClient.getUserById(userDetails.id, "http://10.0.2.2:3200")
result.onSuccess { jsonString ->
apiResultJson = jsonString
showApiResultDialog = true
isLoading = false
}.onFailure { error ->
Toast.makeText(
context,
"API Test Failed: ${error.message}",
Toast.LENGTH_LONG
).show()
isLoading = false
}
} else {
Toast.makeText(
context,
"Failed to get user details",
Toast.LENGTH_SHORT
).show()
isLoading = false
}
} catch (e: Exception) {
Toast.makeText(
context,
"Error: ${e.message}",
Toast.LENGTH_LONG
).show()
isLoading = false
}
}
}, },
shape = RoundedCornerShape(12.dp), shape = RoundedCornerShape(12.dp),
color = Color.White, color = Color.White,
@ -147,14 +186,21 @@ fun AccountsScreen(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(16.dp) horizontalArrangement = Arrangement.spacedBy(16.dp)
) { ) {
Icon( if (isLoading) {
imageVector = Icons.Default.Construction, CircularProgressIndicator(
contentDescription = "Api test", modifier = Modifier.size(24.dp),
tint = Color.Gray, strokeWidth = 2.dp
modifier = Modifier.size(24.dp) )
) } else {
Icon(
imageVector = Icons.Default.Construction,
contentDescription = "Api test",
tint = Color.Gray,
modifier = Modifier.size(24.dp)
)
}
Text( Text(
text = "Test API", text = if (isLoading) "Testing API..." else "Test API",
fontSize = 16.sp, fontSize = 16.sp,
fontWeight = FontWeight.Medium, fontWeight = FontWeight.Medium,
color = Color.Gray color = Color.Gray
@ -164,5 +210,88 @@ fun AccountsScreen(
} }
} }
} }
// API Result Dialog
if (showApiResultDialog) {
Dialog(onDismissRequest = { showApiResultDialog = false }) {
Surface(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(0.8f)
.padding(16.dp),
shape = RoundedCornerShape(16.dp),
color = Color.White
) {
Column(
modifier = Modifier.fillMaxSize()
) {
// Dialog Header
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = "API Test Result",
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
color = Color.Black
)
IconButton(onClick = { showApiResultDialog = false }) {
Text(
text = "",
fontSize = 20.sp,
color = Color.Gray
)
}
}
Divider()
// JSON Content
apiResultJson?.let { json ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
.verticalScroll(rememberScrollState())
) {
Text(
text = json,
fontFamily = FontFamily.Monospace,
fontSize = 12.sp,
color = Color.Black,
modifier = Modifier.fillMaxWidth()
)
}
} ?: run {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text(
text = "No result",
color = Color.Gray
)
}
}
// Close Button
Spacer(modifier = Modifier.weight(1f))
Button(
onClick = { showApiResultDialog = false },
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
shape = RoundedCornerShape(8.dp)
) {
Text("Close")
}
}
}
}
}
} }