Receiving response, still have to handle it.
This commit is contained in:
parent
a218600761
commit
e202eeafeb
19 changed files with 733 additions and 46 deletions
|
@ -39,7 +39,7 @@ android {
|
|||
compose = true
|
||||
}
|
||||
packaging {
|
||||
resources.excludes.add("META-INF-DEPENDENCIES")
|
||||
resources.pickFirsts.add("META-INF/DEPENDENCIES")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,11 +69,7 @@ dependencies {
|
|||
implementation(libs.appauth)
|
||||
implementation(libs.androidx.security.crypto)
|
||||
|
||||
|
||||
|
||||
// implementation(libs.google.api.client.android)
|
||||
// implementation(libs.google.api.services.drive)
|
||||
// implementation(libs.google.oauth.client.jetty)
|
||||
|
||||
implementation(libs.google.auth.library.oauth2.http)
|
||||
implementation(libs.kotlinx.serialization.json)
|
||||
|
||||
}
|
|
@ -15,16 +15,26 @@
|
|||
android:theme="@style/Theme.DeNaDrive"
|
||||
tools:targetApi="31">
|
||||
<activity
|
||||
android:name=".HomeNotAuthActivity"
|
||||
android:name=".oauth.LoadingActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/title_activity_loading"
|
||||
android:theme="@style/Theme.DeNaDrive" />
|
||||
<activity
|
||||
android:name=".home.NeverLoggedInLogic"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.DeNaDrive" >
|
||||
android:theme="@style/Theme.DeNaDrive">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".HomeNotAuthActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.DeNaDrive" />
|
||||
<activity
|
||||
android:name=".TestBah"
|
||||
android:exported="false"
|
||||
|
@ -32,14 +42,16 @@
|
|||
android:theme="@style/Theme.DeNaDrive" />
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:exported="false"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.DeNaDrive">
|
||||
<!-- <intent-filter>-->
|
||||
<!-- <action android:name="android.intent.action.MAIN" />-->
|
||||
|
||||
<!-- <category android:name="android.intent.category.LAUNCHER" />-->
|
||||
<!-- </intent-filter>-->
|
||||
<!-- <intent-filter> -->
|
||||
<!-- <action android:name="android.intent.action.MAIN" /> -->
|
||||
|
||||
|
||||
<!-- <category android:name="android.intent.category.LAUNCHER" /> -->
|
||||
<!-- </intent-filter> -->
|
||||
<!-- <intent-filter android:autoVerify="true"> -->
|
||||
<!-- <action android:name="android.intent.action.VIEW" /> -->
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.bbc.denadrive
|
|||
|
||||
import android.app.PendingIntent
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
|
@ -25,16 +26,36 @@ import androidx.compose.ui.res.painterResource
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.net.toUri
|
||||
import androidx.security.crypto.EncryptedSharedPreferences
|
||||
import androidx.security.crypto.MasterKey
|
||||
import com.bbc.denadrive.oauth.LoadingActivity
|
||||
import com.bbc.denadrive.oauth.retrieveAuthServConf
|
||||
import com.bbc.denadrive.ui.theme.DeNaDriveTheme
|
||||
import net.openid.appauth.AuthState
|
||||
import net.openid.appauth.AuthorizationRequest
|
||||
import net.openid.appauth.AuthorizationService
|
||||
import net.openid.appauth.ResponseTypeValues
|
||||
|
||||
class HomeNotAuthActivity : ComponentActivity() {
|
||||
|
||||
private lateinit var preferences: SharedPreferences
|
||||
private lateinit var masterKey: MasterKey
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
masterKey = MasterKey.Builder(this)
|
||||
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
|
||||
.build()
|
||||
|
||||
preferences = EncryptedSharedPreferences.create(
|
||||
this,
|
||||
"authState",
|
||||
masterKey,
|
||||
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
|
||||
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
|
||||
)
|
||||
|
||||
enableEdgeToEdge()
|
||||
setContent {
|
||||
DeNaDriveTheme {
|
||||
|
@ -42,18 +63,22 @@ class HomeNotAuthActivity : ComponentActivity() {
|
|||
val logo = painterResource(id = R.drawable.vecchiaicona_)
|
||||
LogoWithCaptionAndButton (
|
||||
logo = logo,
|
||||
caption = "Android",
|
||||
buttonText = "PressMe",
|
||||
caption = "DeNa Drive",
|
||||
buttonText = "Log in",
|
||||
modifier = Modifier.padding(innerPadding)
|
||||
) { handleAuthStuff() }
|
||||
) { handleAuthStuff(preferences) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleAuthStuff() {
|
||||
private fun handleAuthStuff(preferences: SharedPreferences) {
|
||||
val serviceConfig = retrieveAuthServConf()
|
||||
// val authState = AuthState(serviceConfig)
|
||||
val authState = AuthState(serviceConfig)
|
||||
with (preferences.edit()) {
|
||||
this.putString("authState", authState.jsonSerializeString())
|
||||
this.apply()
|
||||
}
|
||||
val authRequestBuilder = AuthorizationRequest.Builder(
|
||||
serviceConfig,
|
||||
"722393551256-pum20gbvb1es723kt3ek9lmtrdimr0os.apps.googleusercontent.com",
|
||||
|
@ -67,7 +92,7 @@ class HomeNotAuthActivity : ComponentActivity() {
|
|||
val authService = AuthorizationService(this)
|
||||
authService.performAuthorizationRequest(
|
||||
authRequest,
|
||||
PendingIntent.getActivity(this, 0, Intent(this, MainActivity::class.java),
|
||||
PendingIntent.getActivity(this, 0, Intent(this, LoadingActivity::class.java),
|
||||
PendingIntent.FLAG_MUTABLE),
|
||||
PendingIntent.getActivity(this, 0, Intent(this, HomeNotAuthActivity::class.java),
|
||||
PendingIntent.FLAG_MUTABLE)
|
||||
|
@ -110,7 +135,7 @@ fun LogoWithCaptionAndButton(
|
|||
Image(
|
||||
painter = logo,
|
||||
contentDescription = "Logo",
|
||||
modifier = Modifier.size(100.dp) // Adjust size as needed
|
||||
modifier = Modifier.size(200.dp) // Adjust size as needed
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp)) // Space between logo and caption
|
||||
|
|
|
@ -2,7 +2,9 @@ package com.bbc.denadrive
|
|||
|
||||
import android.app.PendingIntent
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
|
@ -12,9 +14,13 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.core.net.toUri
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import androidx.security.crypto.EncryptedSharedPreferences
|
||||
import androidx.security.crypto.MasterKey
|
||||
import com.bbc.denadrive.apihandlers.makeDriveApiCall
|
||||
import com.bbc.denadrive.home.ScaffoldWithSidebar
|
||||
import com.bbc.denadrive.oauth.retrieveAuthServConf
|
||||
import com.bbc.denadrive.ui.theme.DeNaDriveTheme
|
||||
import net.openid.appauth.AuthState
|
||||
import net.openid.appauth.AuthorizationException
|
||||
import net.openid.appauth.AuthorizationRequest
|
||||
import net.openid.appauth.AuthorizationResponse
|
||||
|
@ -22,27 +28,65 @@ import net.openid.appauth.AuthorizationService
|
|||
import net.openid.appauth.ResponseTypeValues
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
||||
private lateinit var masterKey: MasterKey
|
||||
private lateinit var preferences: SharedPreferences
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
// handleAuthStuff()
|
||||
masterKey = MasterKey.Builder(this)
|
||||
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
|
||||
.build()
|
||||
|
||||
preferences = EncryptedSharedPreferences.create(
|
||||
this,
|
||||
"authState",
|
||||
masterKey,
|
||||
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
|
||||
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
|
||||
)
|
||||
|
||||
val authState = preferences.getString("authState", "bah")
|
||||
?.let { AuthState.jsonDeserialize(it) }
|
||||
|
||||
val authService = AuthorizationService(this)
|
||||
|
||||
// authState?.let {
|
||||
// it.performActionWithFreshTokens(authService) { accessToken, idToken, ex ->
|
||||
// if (ex != null) {
|
||||
// Log.e("TELLINGYA", "${ex.error}")
|
||||
// return@performActionWithFreshTokens
|
||||
// }
|
||||
// Log.e("TOLD", "okay I guess")
|
||||
// }
|
||||
// }
|
||||
|
||||
authState?.let {
|
||||
val myUrl = "https://www.googleapis.com/drive/v3/files?trashed=false&orderBy=folder"
|
||||
makeDriveApiCall(this, it, myUrl, "root") {
|
||||
response, exception ->
|
||||
if (exception != null) {
|
||||
Log.e("ECCOLO", "${exception.cause}")
|
||||
Log.e("ECCOLO", "${exception.message}")
|
||||
}
|
||||
else {
|
||||
Log.e("UOOOO", "$response")
|
||||
}
|
||||
}
|
||||
with(preferences.edit()) {
|
||||
this.remove("authState")
|
||||
this.putString("authState", it.jsonSerializeString())
|
||||
this.apply()
|
||||
}
|
||||
}
|
||||
|
||||
setContent {
|
||||
val navController = rememberNavController()
|
||||
ScaffoldWithSidebar(navController) { }
|
||||
// NavigationGraph(navController)
|
||||
ScaffoldWithSidebar(navController) {
|
||||
Log.e("LETTINGYOUKNOW", "authstate: ${authState?.jsonSerializeString()}")
|
||||
}
|
||||
}
|
||||
// enableEdgeToEdge()
|
||||
// setContent {
|
||||
// DeNaDriveTheme {
|
||||
// Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
|
||||
// Greeting(
|
||||
// name = "Android",
|
||||
// modifier = Modifier.padding(innerPadding)
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
|
@ -62,10 +106,10 @@ override fun onCreate(savedInstanceState: Bundle?) {
|
|||
val authService = AuthorizationService(this)
|
||||
authService.performAuthorizationRequest(
|
||||
authRequest,
|
||||
PendingIntent.getActivity(this, 0, Intent(this, TestActivity::class.java),
|
||||
PendingIntent.FLAG_MUTABLE),
|
||||
PendingIntent.getActivity(this, 0, Intent(this, TestBah::class.java),
|
||||
PendingIntent.FLAG_MUTABLE)
|
||||
PendingIntent.getActivity(this, 0, Intent(this,
|
||||
TestActivity::class.java), PendingIntent.FLAG_MUTABLE),
|
||||
PendingIntent.getActivity(this, 0, Intent(this,
|
||||
TestBah::class.java), PendingIntent.FLAG_MUTABLE)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -83,8 +127,9 @@ override fun onCreate(savedInstanceState: Bundle?) {
|
|||
}
|
||||
|
||||
setContent {
|
||||
val navController = rememberNavController()
|
||||
ScaffoldWithSidebar(navController) { }
|
||||
// val navController = rememberNavController()
|
||||
// ScaffoldWithSidebar(navController) { }
|
||||
Greeting("bah")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
45
app/src/main/java/com/bbc/denadrive/apihandlers/ApiCalls.kt
Normal file
45
app/src/main/java/com/bbc/denadrive/apihandlers/ApiCalls.kt
Normal file
|
@ -0,0 +1,45 @@
|
|||
package com.bbc.denadrive.apihandlers
|
||||
|
||||
import android.content.Context
|
||||
import net.openid.appauth.AuthState
|
||||
import net.openid.appauth.AuthorizationService
|
||||
import okhttp3.Call
|
||||
import okhttp3.Callback
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import java.io.IOException
|
||||
|
||||
fun makeDriveApiCall(context: Context, authState: AuthState, url: String, folderId: String,
|
||||
callback: (String?, Exception?) -> Unit) {
|
||||
val authService = AuthorizationService(context)
|
||||
// _ = idToken
|
||||
authState.performActionWithFreshTokens(authService) { accessToken, _, ex ->
|
||||
authService.dispose()
|
||||
if (ex != null) {
|
||||
callback(null, ex)
|
||||
return@performActionWithFreshTokens
|
||||
}
|
||||
|
||||
val urlBuilder = url.toHttpUrl().newBuilder()
|
||||
urlBuilder.addQueryParameter("q", "'$folderId' in parents")
|
||||
val updatedUrl = urlBuilder.build()
|
||||
|
||||
val request = Request.Builder()
|
||||
.url(updatedUrl)
|
||||
.header("Authorization", "Bearer $accessToken")
|
||||
.build()
|
||||
|
||||
OkHttpClient().newCall(request).enqueue(object : Callback {
|
||||
override fun onFailure(call: Call, e: IOException) {
|
||||
callback(null, e)
|
||||
}
|
||||
|
||||
override fun onResponse(call: Call, response: Response) {
|
||||
val responseBody = response.body?.string()
|
||||
callback(responseBody, null)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package com.bbc.denadrive.apihandlers
|
||||
|
||||
data class DriveResponseBody(
|
||||
val nextPageToken: String?,
|
||||
val kind: String,
|
||||
val incompleteSearch: Boolean,
|
||||
val files: List<MyFile>
|
||||
)
|
|
@ -0,0 +1,8 @@
|
|||
package com.bbc.denadrive.apihandlers
|
||||
|
||||
data class MyFile(
|
||||
val kind: String,
|
||||
val mimeType: String,
|
||||
val id: String,
|
||||
val name: String
|
||||
)
|
|
@ -0,0 +1,42 @@
|
|||
package com.bbc.denadrive.apihandlers
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import kotlinx.serialization.SerializationException
|
||||
import kotlinx.serialization.json.Json
|
||||
import okhttp3.Response
|
||||
|
||||
class ResponsesHandler: ViewModel() {
|
||||
|
||||
var lastResponse: String = ""
|
||||
var isComplete: Boolean = true
|
||||
private lateinit var respBuilder: StringBuilder
|
||||
private lateinit var lastResponseBody: DriveResponseBody
|
||||
|
||||
fun newResponseArrived(response: Response) {
|
||||
if (isComplete) {
|
||||
respBuilder = StringBuilder("$response")
|
||||
}
|
||||
else {
|
||||
respBuilder.append("$response")
|
||||
updateCompleteness()
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkForCompleteness(): Pair<Boolean, DriveResponseBody?> {
|
||||
return try {
|
||||
Pair(true, Json.decodeFromString<DriveResponseBody>(respBuilder.toString()))
|
||||
} catch (e: SerializationException) {
|
||||
Pair(false, null)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateCompleteness() {
|
||||
val pair = checkForCompleteness()
|
||||
isComplete = pair.first
|
||||
if (isComplete) {
|
||||
lastResponse = respBuilder.toString()
|
||||
lastResponseBody = pair.second!!
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
package com.bbc.denadrive.home
|
||||
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.security.crypto.EncryptedSharedPreferences
|
||||
import androidx.security.crypto.MasterKey
|
||||
import com.bbc.denadrive.HomeNotAuthActivity
|
||||
import com.bbc.denadrive.MainActivity
|
||||
import com.bbc.denadrive.home.ui.theme.DeNaDriveTheme
|
||||
import net.openid.appauth.AuthState
|
||||
|
||||
class NeverLoggedInLogic : ComponentActivity() {
|
||||
|
||||
private lateinit var preferences: SharedPreferences
|
||||
private lateinit var masterKey: MasterKey
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
masterKey = MasterKey.Builder(this)
|
||||
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
|
||||
.build()
|
||||
|
||||
preferences = EncryptedSharedPreferences.create(
|
||||
this,
|
||||
"authState",
|
||||
masterKey,
|
||||
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
|
||||
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
|
||||
)
|
||||
|
||||
val authStateString = preferences.getString("authState", "unset")
|
||||
|
||||
val intent: Intent
|
||||
if (authStateString == "unset") {
|
||||
intent = Intent(this, HomeNotAuthActivity::class.java)
|
||||
} else {
|
||||
val authState = authStateString?.let { AuthState.jsonDeserialize(it) }
|
||||
intent = if (authState?.isAuthorized == true) {
|
||||
Intent(this, MainActivity::class.java)
|
||||
}
|
||||
else {
|
||||
Toast.makeText(this, "Session expired, please log in again",
|
||||
Toast.LENGTH_SHORT).show()
|
||||
Intent(this, HomeNotAuthActivity::class.java)
|
||||
}
|
||||
}
|
||||
startActivity(intent)
|
||||
// Toast.makeText(this, "should not make it here", Toast.LENGTH_SHORT).show()
|
||||
|
||||
enableEdgeToEdge()
|
||||
setContent {
|
||||
DeNaDriveTheme {
|
||||
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
|
||||
Greeting5(
|
||||
name = "Android",
|
||||
modifier = Modifier.padding(innerPadding)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Greeting5(name: String, modifier: Modifier = Modifier) {
|
||||
Text(
|
||||
text = "Hello $name!",
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
fun GreetingPreview5() {
|
||||
DeNaDriveTheme {
|
||||
Greeting5("Android")
|
||||
}
|
||||
}
|
11
app/src/main/java/com/bbc/denadrive/home/ui/theme/Color.kt
Normal file
11
app/src/main/java/com/bbc/denadrive/home/ui/theme/Color.kt
Normal file
|
@ -0,0 +1,11 @@
|
|||
package com.bbc.denadrive.home.ui.theme
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
val Purple80 = Color(0xFFD0BCFF)
|
||||
val PurpleGrey80 = Color(0xFFCCC2DC)
|
||||
val Pink80 = Color(0xFFEFB8C8)
|
||||
|
||||
val Purple40 = Color(0xFF6650a4)
|
||||
val PurpleGrey40 = Color(0xFF625b71)
|
||||
val Pink40 = Color(0xFF7D5260)
|
58
app/src/main/java/com/bbc/denadrive/home/ui/theme/Theme.kt
Normal file
58
app/src/main/java/com/bbc/denadrive/home/ui/theme/Theme.kt
Normal file
|
@ -0,0 +1,58 @@
|
|||
package com.bbc.denadrive.home.ui.theme
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Build
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.darkColorScheme
|
||||
import androidx.compose.material3.dynamicDarkColorScheme
|
||||
import androidx.compose.material3.dynamicLightColorScheme
|
||||
import androidx.compose.material3.lightColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
|
||||
private val DarkColorScheme = darkColorScheme(
|
||||
primary = Purple80,
|
||||
secondary = PurpleGrey80,
|
||||
tertiary = Pink80
|
||||
)
|
||||
|
||||
private val LightColorScheme = lightColorScheme(
|
||||
primary = Purple40,
|
||||
secondary = PurpleGrey40,
|
||||
tertiary = Pink40
|
||||
|
||||
/* Other default colors to override
|
||||
background = Color(0xFFFFFBFE),
|
||||
surface = Color(0xFFFFFBFE),
|
||||
onPrimary = Color.White,
|
||||
onSecondary = Color.White,
|
||||
onTertiary = Color.White,
|
||||
onBackground = Color(0xFF1C1B1F),
|
||||
onSurface = Color(0xFF1C1B1F),
|
||||
*/
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun DeNaDriveTheme(
|
||||
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||
// Dynamic color is available on Android 12+
|
||||
dynamicColor: Boolean = true,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
val colorScheme = when {
|
||||
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
|
||||
val context = LocalContext.current
|
||||
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
|
||||
}
|
||||
|
||||
darkTheme -> DarkColorScheme
|
||||
else -> LightColorScheme
|
||||
}
|
||||
|
||||
MaterialTheme(
|
||||
colorScheme = colorScheme,
|
||||
typography = Typography,
|
||||
content = content
|
||||
)
|
||||
}
|
34
app/src/main/java/com/bbc/denadrive/home/ui/theme/Type.kt
Normal file
34
app/src/main/java/com/bbc/denadrive/home/ui/theme/Type.kt
Normal file
|
@ -0,0 +1,34 @@
|
|||
package com.bbc.denadrive.home.ui.theme
|
||||
|
||||
import androidx.compose.material3.Typography
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.sp
|
||||
|
||||
// Set of Material typography styles to start with
|
||||
val Typography = Typography(
|
||||
bodyLarge = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 16.sp,
|
||||
lineHeight = 24.sp,
|
||||
letterSpacing = 0.5.sp
|
||||
)
|
||||
/* Other default text styles to override
|
||||
titleLarge = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 22.sp,
|
||||
lineHeight = 28.sp,
|
||||
letterSpacing = 0.sp
|
||||
),
|
||||
labelSmall = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 11.sp,
|
||||
lineHeight = 16.sp,
|
||||
letterSpacing = 0.5.sp
|
||||
)
|
||||
*/
|
||||
)
|
|
@ -1,2 +1,29 @@
|
|||
package com.bbc.denadrive.oauth
|
||||
|
||||
import android.content.Context
|
||||
import androidx.security.crypto.EncryptedSharedPreferences
|
||||
import androidx.security.crypto.MasterKey
|
||||
import net.openid.appauth.AuthState
|
||||
|
||||
object AuthStatePersistence {
|
||||
|
||||
fun retrieveAuthState(context: Context): AuthState {
|
||||
val masterKey = MasterKey.Builder(context)
|
||||
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
|
||||
.build()
|
||||
|
||||
val preferences = EncryptedSharedPreferences.create(
|
||||
context,
|
||||
"authState",
|
||||
masterKey,
|
||||
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
|
||||
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
|
||||
)
|
||||
|
||||
preferences.getString("authState", null)?.let {
|
||||
return AuthState.jsonDeserialize(it)
|
||||
}
|
||||
return AuthState(retrieveAuthServConf())
|
||||
}
|
||||
|
||||
}
|
175
app/src/main/java/com/bbc/denadrive/oauth/LoadingActivity.kt
Normal file
175
app/src/main/java/com/bbc/denadrive/oauth/LoadingActivity.kt
Normal file
|
@ -0,0 +1,175 @@
|
|||
package com.bbc.denadrive.oauth
|
||||
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.mutableFloatStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.security.crypto.EncryptedSharedPreferences
|
||||
import androidx.security.crypto.MasterKey
|
||||
import com.bbc.denadrive.HomeNotAuthActivity
|
||||
import com.bbc.denadrive.MainActivity
|
||||
import com.bbc.denadrive.oauth.ui.theme.DeNaDriveTheme
|
||||
import net.openid.appauth.AuthState
|
||||
import net.openid.appauth.AuthorizationException
|
||||
import net.openid.appauth.AuthorizationResponse
|
||||
import net.openid.appauth.AuthorizationService
|
||||
|
||||
class LoadingActivity : ComponentActivity() {
|
||||
|
||||
private lateinit var masterKey: MasterKey
|
||||
private lateinit var preferences: SharedPreferences
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
enableEdgeToEdge()
|
||||
setContent {
|
||||
DeNaDriveTheme {
|
||||
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
|
||||
LoadingScreen(modifier = Modifier.padding(innerPadding))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
masterKey = MasterKey.Builder(this)
|
||||
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
|
||||
.build()
|
||||
|
||||
preferences = EncryptedSharedPreferences.create(
|
||||
this,
|
||||
"authState",
|
||||
masterKey,
|
||||
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
|
||||
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
|
||||
)
|
||||
|
||||
val authState = preferences.getString("authState", "bah")
|
||||
?.let { AuthState.jsonDeserialize(it) }
|
||||
|
||||
val response = AuthorizationResponse.fromIntent(intent)
|
||||
val exception = AuthorizationException.fromIntent(intent)
|
||||
if (response != null) {
|
||||
Toast.makeText(this, "Done!", Toast.LENGTH_SHORT).show()
|
||||
authState?.update(response, exception)
|
||||
Log.e("MainActivity", "authState: ${authState?.jsonSerializeString()}", )
|
||||
with (preferences.edit()) {
|
||||
this.remove("authState")
|
||||
this.putString("authState", "${authState?.jsonSerializeString()}")
|
||||
this.apply()
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(this, "Not done :( ${exception?.error}", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
val authService = AuthorizationService(this)
|
||||
response?.createTokenExchangeRequest()?.let {
|
||||
authService.performTokenRequest(
|
||||
it
|
||||
) { resp, ex ->
|
||||
if (resp != null) {
|
||||
authState?.update(resp, ex)
|
||||
with(preferences.edit()) {
|
||||
this.remove("authState")
|
||||
this.putString("authState", "${authState?.jsonSerializeString()}")
|
||||
this.apply()
|
||||
}
|
||||
val intent = Intent(this, MainActivity::class.java)
|
||||
startActivity(intent)
|
||||
} else {
|
||||
val intent = Intent(this, HomeNotAuthActivity::class.java)
|
||||
startActivity(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun LoadingScreen(
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
// State to control the rotation animation
|
||||
val rotation = remember { mutableFloatStateOf(0f) }
|
||||
|
||||
// Animate the rotation
|
||||
LaunchedEffect(Unit) {
|
||||
while (true) {
|
||||
rotation.floatValue += 10f
|
||||
if (rotation.floatValue >= 360f) rotation.floatValue = 0f
|
||||
kotlinx.coroutines.delay(16) // Approximately 60 FPS
|
||||
}
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.padding(16.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
// Rotating Circular Progress Indicator
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier
|
||||
.size(64.dp)
|
||||
.graphicsLayer(rotationZ = rotation.floatValue),
|
||||
color = Color.Blue
|
||||
)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
// Loading text
|
||||
Text(
|
||||
text = "Loading",
|
||||
fontSize = 20.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = Color.Black
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Greeting6(name: String, modifier: Modifier = Modifier) {
|
||||
Text(
|
||||
text = "Hello $name!",
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
fun GreetingPreview6() {
|
||||
DeNaDriveTheme {
|
||||
Greeting6("Android")
|
||||
}
|
||||
}
|
11
app/src/main/java/com/bbc/denadrive/oauth/ui/theme/Color.kt
Normal file
11
app/src/main/java/com/bbc/denadrive/oauth/ui/theme/Color.kt
Normal file
|
@ -0,0 +1,11 @@
|
|||
package com.bbc.denadrive.oauth.ui.theme
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
val Purple80 = Color(0xFFD0BCFF)
|
||||
val PurpleGrey80 = Color(0xFFCCC2DC)
|
||||
val Pink80 = Color(0xFFEFB8C8)
|
||||
|
||||
val Purple40 = Color(0xFF6650a4)
|
||||
val PurpleGrey40 = Color(0xFF625b71)
|
||||
val Pink40 = Color(0xFF7D5260)
|
58
app/src/main/java/com/bbc/denadrive/oauth/ui/theme/Theme.kt
Normal file
58
app/src/main/java/com/bbc/denadrive/oauth/ui/theme/Theme.kt
Normal file
|
@ -0,0 +1,58 @@
|
|||
package com.bbc.denadrive.oauth.ui.theme
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Build
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.darkColorScheme
|
||||
import androidx.compose.material3.dynamicDarkColorScheme
|
||||
import androidx.compose.material3.dynamicLightColorScheme
|
||||
import androidx.compose.material3.lightColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
|
||||
private val DarkColorScheme = darkColorScheme(
|
||||
primary = Purple80,
|
||||
secondary = PurpleGrey80,
|
||||
tertiary = Pink80
|
||||
)
|
||||
|
||||
private val LightColorScheme = lightColorScheme(
|
||||
primary = Purple40,
|
||||
secondary = PurpleGrey40,
|
||||
tertiary = Pink40
|
||||
|
||||
/* Other default colors to override
|
||||
background = Color(0xFFFFFBFE),
|
||||
surface = Color(0xFFFFFBFE),
|
||||
onPrimary = Color.White,
|
||||
onSecondary = Color.White,
|
||||
onTertiary = Color.White,
|
||||
onBackground = Color(0xFF1C1B1F),
|
||||
onSurface = Color(0xFF1C1B1F),
|
||||
*/
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun DeNaDriveTheme(
|
||||
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||
// Dynamic color is available on Android 12+
|
||||
dynamicColor: Boolean = true,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
val colorScheme = when {
|
||||
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
|
||||
val context = LocalContext.current
|
||||
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
|
||||
}
|
||||
|
||||
darkTheme -> DarkColorScheme
|
||||
else -> LightColorScheme
|
||||
}
|
||||
|
||||
MaterialTheme(
|
||||
colorScheme = colorScheme,
|
||||
typography = Typography,
|
||||
content = content
|
||||
)
|
||||
}
|
34
app/src/main/java/com/bbc/denadrive/oauth/ui/theme/Type.kt
Normal file
34
app/src/main/java/com/bbc/denadrive/oauth/ui/theme/Type.kt
Normal file
|
@ -0,0 +1,34 @@
|
|||
package com.bbc.denadrive.oauth.ui.theme
|
||||
|
||||
import androidx.compose.material3.Typography
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.sp
|
||||
|
||||
// Set of Material typography styles to start with
|
||||
val Typography = Typography(
|
||||
bodyLarge = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 16.sp,
|
||||
lineHeight = 24.sp,
|
||||
letterSpacing = 0.5.sp
|
||||
)
|
||||
/* Other default text styles to override
|
||||
titleLarge = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 22.sp,
|
||||
lineHeight = 28.sp,
|
||||
letterSpacing = 0.sp
|
||||
),
|
||||
labelSmall = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 11.sp,
|
||||
lineHeight = 16.sp,
|
||||
letterSpacing = 0.5.sp
|
||||
)
|
||||
*/
|
||||
)
|
|
@ -4,4 +4,6 @@
|
|||
<string name="title_activity_test_bah">TestBah</string>
|
||||
<string name="title_activity_speremm">Speremm</string>
|
||||
<string name="title_activity_home_not_auth">HomeNotAuthActivity</string>
|
||||
<string name="title_activity_never_logged_in_logic">NeverLoggedInLogic</string>
|
||||
<string name="title_activity_loading">LoadingActivity</string>
|
||||
</resources>
|
|
@ -2,11 +2,13 @@
|
|||
agp = "8.9.0"
|
||||
appauth = "0.11.1"
|
||||
converterGson = "2.9.0"
|
||||
googleAuthLibraryOauth2Http = "1.15.0"
|
||||
kotlin = "2.0.21"
|
||||
coreKtx = "1.15.0"
|
||||
junit = "4.13.2"
|
||||
junitVersion = "1.2.1"
|
||||
espressoCore = "3.6.1"
|
||||
kotlinxSerializationJson = "1.5.0"
|
||||
lifecycleRuntimeKtx = "2.8.7"
|
||||
activityCompose = "1.10.1"
|
||||
composeBom = "2025.02.00"
|
||||
|
@ -20,6 +22,7 @@ androidx-navigation-compose = { module = "androidx.navigation:navigation-compose
|
|||
androidx-security-crypto = { module = "androidx.security:security-crypto", version.ref = "securityCrypto" }
|
||||
appauth = { module = "net.openid:appauth", version.ref = "appauth" }
|
||||
converter-gson = { module = "com.squareup.retrofit2:converter-gson", version.ref = "converterGson" }
|
||||
google-auth-library-oauth2-http = { module = "com.google.auth:google-auth-library-oauth2-http", version.ref = "googleAuthLibraryOauth2Http" }
|
||||
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
||||
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
|
||||
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
|
||||
|
@ -33,6 +36,7 @@ androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-toolin
|
|||
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
|
||||
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
|
||||
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
|
||||
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
|
||||
okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
|
||||
retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "converterGson" }
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue