Skip to content

Commit

Permalink
Merge pull request #1124 from kul3r4/screenshottesting
Browse files Browse the repository at this point in the history
Adds Compose preview to OAuth device grant
  • Loading branch information
kul3r4 authored Jun 13, 2024
2 parents 5814e65 + b3f7117 commit d30e10c
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.ListHeader
import androidx.wear.compose.material3.Text
import androidx.wear.compose.ui.tooling.preview.WearPreviewDevices
import androidx.wear.compose.ui.tooling.preview.WearPreviewFontScales
import com.google.android.horologist.annotations.ExperimentalHorologistApi
import com.google.android.horologist.compose.layout.AppScaffold
import com.google.android.horologist.compose.layout.ScalingLazyColumn
Expand Down Expand Up @@ -59,42 +60,76 @@ class AuthDeviceGrantActivity : ComponentActivity() {
}
}

@OptIn(ExperimentalHorologistApi::class)
@Composable
fun AuthenticateApp(deviceGrantViewModel: AuthDeviceGrantViewModel) {
AppScaffold {
val uiState = deviceGrantViewModel.uiState.collectAsState()
val localContext = LocalContext.current
val columnState = rememberResponsiveColumnState(
contentPadding = ScalingLazyColumnDefaults.padding(
first = ItemType.Text,
last = ItemType.Text
)
AuthenticateScreen(
uiState.value.statusCode,
uiState.value.resultMessage,
deviceGrantViewModel::startAuthFlow
)
}
}

@OptIn(ExperimentalHorologistApi::class)
@Composable
fun AuthenticateScreen(
statusCode: Int,
resultMessage: String,
startAuthFlow: () -> Unit
) {
val columnState = rememberResponsiveColumnState(
contentPadding = ScalingLazyColumnDefaults.padding(
first = ItemType.Text,
last = ItemType.Text
)
ScreenScaffold(scrollState = columnState) {
ScalingLazyColumn(columnState = columnState) {
item {
ListHeader {
Text(
stringResource(R.string.oauth_device_auth_grant),
textAlign = TextAlign.Center
)
}
)
ScreenScaffold(scrollState = columnState) {
ScalingLazyColumn(columnState = columnState) {
item {
ListHeader {
Text(
stringResource(R.string.oauth_device_auth_grant),
textAlign = TextAlign.Center
)
}
item {
Button(
onClick = { deviceGrantViewModel.startAuthFlow(localContext) },
modifier = Modifier.fillMaxSize()
) {
Text(
text = stringResource(R.string.get_grant_from_phone),
modifier = Modifier.align(Alignment.CenterVertically)
)
}
}
item {
Button(
onClick = { startAuthFlow() },
modifier = Modifier.fillMaxSize()
) {
Text(
text = stringResource(R.string.get_grant_from_phone),
modifier = Modifier.align(Alignment.CenterVertically)
)
}
item { Text(uiState.value.statusCode.toString()) }
item { Text(uiState.value.resultMessage) }
}
item { Text(stringResource(id = statusCode)) }
item { Text(resultMessage) }
}
}
}

@WearPreviewDevices
@WearPreviewFontScales
@Composable
fun AuthenticateScreenPreview() {
AuthenticateScreen(
statusCode = R.string.status_retrieved,
resultMessage = "User name",
startAuthFlow = {}
)
}

@WearPreviewDevices
@WearPreviewFontScales
@Composable
fun AuthenticateScreenFailedPreview() {
AuthenticateScreen(
statusCode = R.string.status_failed,
resultMessage = "",
startAuthFlow = {}
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@
*/
package com.example.android.wearable.oauth.devicegrant

import android.app.Application
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import androidx.wear.remote.interactions.RemoteActivityHelper
import com.example.android.wearable.oauth.util.doGetRequest
Expand All @@ -29,6 +30,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch

private const val TAG = "AuthDeviceGrantViewModel"
Expand All @@ -38,7 +40,7 @@ private const val CLIENT_ID = ""
private const val CLIENT_SECRET = ""

data class DeviceGrantState(
val statusCode: Int = 0,
val statusCode: Int = R.string.oauth_device_authorization_default,
val resultMessage: String = ""
)

Expand All @@ -48,16 +50,19 @@ data class DeviceGrantState(
* different steps of the flow. It first retrieves the URL that should be opened on the paired
* device, then polls for the access token, and uses it to retrieve the user's name.
*/
class AuthDeviceGrantViewModel : ViewModel() {
class AuthDeviceGrantViewModel(application: Application) : AndroidViewModel(application) {
private val context = getApplication<Application>().applicationContext
private val _uiState = MutableStateFlow(DeviceGrantState())

val uiState: StateFlow<DeviceGrantState> = _uiState.asStateFlow()

private fun showStatus(statusString: Int = 0, resultString: String = "") {
_uiState.value =
_uiState.value.copy(statusCode = statusString, resultMessage = resultString)
_uiState.update {
DeviceGrantState(statusString, resultString)
}
}

fun startAuthFlow(context: Context) {
fun startAuthFlow() {
viewModelScope.launch {
// Step 1: Retrieve the verification URI
showStatus(statusString = R.string.status_switch_to_phone)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<resources>
<string name="start_auth_flow">Authenticate</string>
<string name="oauth_device_authorization_grant">OAuth Device Authorization Grant</string>
<string name="oauth_device_authorization_default">Not authorized</string>
<string name="status_switch_to_phone">Starting authorization… Switch to your phone to authenticate.</string>
<string name="status_failed">Authorization failed</string>
<string name="status_code">"Code: "</string>
Expand Down

0 comments on commit d30e10c

Please sign in to comment.