ONLY FUNCTIONAL STUFF MISSING!

This commit is contained in:
AlbYoda 2025-03-13 03:33:12 +01:00
parent e202eeafeb
commit 0a2de2cd06
Signed by untrusted user who does not match committer: AlbYoda
GPG key ID: A539D876452F16FF
12 changed files with 198 additions and 147 deletions

View file

@ -2,6 +2,7 @@ plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
kotlin("plugin.serialization")
}
android {

View file

@ -2,7 +2,6 @@ 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
@ -26,36 +25,18 @@ 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 {
@ -66,19 +47,14 @@ class HomeNotAuthActivity : ComponentActivity() {
caption = "DeNa Drive",
buttonText = "Log in",
modifier = Modifier.padding(innerPadding)
) { handleAuthStuff(preferences) }
) { handleAuthStuff() }
}
}
}
}
private fun handleAuthStuff(preferences: SharedPreferences) {
private fun handleAuthStuff() {
val serviceConfig = retrieveAuthServConf()
val authState = AuthState(serviceConfig)
with (preferences.edit()) {
this.putString("authState", authState.jsonSerializeString())
this.apply()
}
val authRequestBuilder = AuthorizationRequest.Builder(
serviceConfig,
"722393551256-pum20gbvb1es723kt3ek9lmtrdimr0os.apps.googleusercontent.com",

View file

@ -2,7 +2,6 @@ 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
@ -13,14 +12,15 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.core.net.toUri
import androidx.lifecycle.LiveData
import androidx.navigation.compose.rememberNavController
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey
import com.bbc.denadrive.apihandlers.DriveResponseBody
import com.bbc.denadrive.apihandlers.ResponsesHandler
import com.bbc.denadrive.apihandlers.makeDriveApiCall
import com.bbc.denadrive.home.ScaffoldWithSidebar
import com.bbc.denadrive.oauth.AuthStatePersistence
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
@ -29,62 +29,33 @@ import net.openid.appauth.ResponseTypeValues
class MainActivity : ComponentActivity() {
private lateinit var masterKey: MasterKey
private lateinit var preferences: SharedPreferences
private lateinit var responsesHandler: ResponsesHandler
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
masterKey = MasterKey.Builder(this)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build()
val authPersistence = AuthStatePersistence
val authState = authPersistence.retrieveAuthState(this)
responsesHandler = ResponsesHandler()
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")
}
val myUrl = "https://www.googleapis.com/drive/v3/files?trashed=false&orderBy=folder"
makeDriveApiCall(this, authState, myUrl, "root") {
response, exception ->
if (exception != null) {
Log.e("ECCOLO", "${exception.cause}")
Log.e("ECCOLO", "${exception.message}")
}
with(preferences.edit()) {
this.remove("authState")
this.putString("authState", it.jsonSerializeString())
this.apply()
else {
Log.e("UOOOO", "$response")
responsesHandler.newResponseArrived(response)
}
}
authPersistence.putAuthState(this, authState)
setContent {
val navController = rememberNavController()
ScaffoldWithSidebar(navController) {
Log.e("LETTINGYOUKNOW", "authstate: ${authState?.jsonSerializeString()}")
ScaffoldWithSidebar(navController, responsesHandler) {
Log.e("LETTINGYOUKNOW", "authstate: ${authState.jsonSerializeString()}")
}
}
}

View file

@ -1,15 +1,19 @@
package com.bbc.denadrive
import androidx.compose.runtime.Composable
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import com.bbc.denadrive.apihandlers.DriveResponseBody
import com.bbc.denadrive.apihandlers.ResponsesHandler
import com.bbc.denadrive.home.DetailsScreen
import com.bbc.denadrive.home.HomeScreen
import com.bbc.denadrive.home.MyListVisualizer
@Composable
fun NavigationGraph(navController: NavHostController) {
fun NavigationGraph(navController: NavHostController, responsesHandler: ResponsesHandler) {
// Create a NavHost that defines the navigation graph
NavHost(navController = navController, startDestination = "prova") {
// Define the home screen destination
@ -23,6 +27,6 @@ fun NavigationGraph(navController: NavHostController) {
DetailsScreen(itemId, navController)
}
composable("prova") { MyListVisualizer() }
composable("prova") { MyListVisualizer(responsesHandler) }
}
}

View file

@ -1,8 +1,15 @@
package com.bbc.denadrive.apihandlers
import kotlinx.serialization.Serializable
@Serializable
data class DriveResponseBody(
val nextPageToken: String?,
// val nextPageToken: String?,
val kind: String,
val incompleteSearch: Boolean,
val files: List<MyFile>
)
) {
fun toList(): List<String> {
return files.map { it.name }
}
}

View file

@ -1,5 +1,8 @@
package com.bbc.denadrive.apihandlers
import kotlinx.serialization.Serializable
@Serializable
data class MyFile(
val kind: String,
val mimeType: String,

View file

@ -1,31 +1,45 @@
package com.bbc.denadrive.apihandlers
import android.util.Log
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
//import androidx.lifecycle.LiveData
//import androidx.lifecycle.MutableLiveData
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
// private val _lastResponseBody = MutableLiveData<DriveResponseBody?>(null)
// val lastResponseBody: LiveData<DriveResponseBody?> get() = _lastResponseBody
val lastResponseBody: MutableState<DriveResponseBody?> = mutableStateOf(null)
fun newResponseArrived(response: Response) {
if (isComplete) {
respBuilder = StringBuilder("$response")
private var lastResponse: String = ""
private var isComplete: Boolean = true
private lateinit var respBuilder: StringBuilder
fun newResponseArrived(response: String?) {
if (isComplete && response != null) {
respBuilder = StringBuilder(response)
updateCompleteness()
Log.e("OLE", "newResponseArrived: $response")
}
else {
respBuilder.append("$response")
else if (response != null) {
respBuilder.append(response)
Log.e("OLE2", "newResponseArrived: $response")
updateCompleteness()
}
}
private fun checkForCompleteness(): Pair<Boolean, DriveResponseBody?> {
return try {
Log.e("ASSURDO", "newResponseArrived: $respBuilder")
Pair(true, Json.decodeFromString<DriveResponseBody>(respBuilder.toString()))
} catch (e: SerializationException) {
Log.e("EDECCOCE", "newResponseArrived: $respBuilder")
Log.e("EDECCOCE", "errore: ${e.cause}")
Log.e("EDECCOCE", "errore: ${e.message}")
Pair(false, null)
}
}
@ -35,7 +49,8 @@ class ResponsesHandler: ViewModel() {
isComplete = pair.first
if (isComplete) {
lastResponse = respBuilder.toString()
lastResponseBody = pair.second!!
Log.e("NONSOCHESUCCEDA", "${pair.second}", )
lastResponseBody.value = pair.second
}
}

View file

@ -1,5 +1,7 @@
package com.bbc.denadrive.home
import android.media.tv.TvContract.Channels.Logo
import android.util.Log
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.background
import androidx.compose.material3.Button
@ -23,7 +25,13 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import kotlinx.coroutines.launch
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.foundation.Image
import androidx.compose.ui.res.painterResource
import com.bbc.denadrive.NavigationGraph
import com.bbc.denadrive.R
import com.bbc.denadrive.apihandlers.ResponsesHandler
@Composable
fun HomeScreen(navController: NavHostController) {
@ -42,6 +50,7 @@ fun DetailsScreen(itemId: String?, navController: NavHostController) {
@Composable
fun ScaffoldWithSidebar(
navController: NavHostController,
responsesHandler: ResponsesHandler,
doIt: () -> Unit,
// toBeDisplayed: @Composable () -> Unit
) {
@ -97,9 +106,9 @@ fun ScaffoldWithSidebar(
.fillMaxSize()
.padding(innerPadding)
.padding(16.dp),
contentAlignment = Alignment.Center
contentAlignment = Alignment.TopCenter,
) {
NavigationGraph(navController)
NavigationGraph(navController, responsesHandler)
// toBeDisplayed()
// Text("Main Content", fontSize = 24.sp)
}
@ -144,10 +153,66 @@ fun RectangularButton(
}
@Composable
fun MyListVisualizer () {
val lista = listOf("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z")
fun MyListVisualizer(responsesHandler: ResponsesHandler) {
Log.e("CHECKING", "MyListVisualizer: REDRAWN", )
val fileList = mutableListOf<String>()
if (responsesHandler.lastResponseBody.value == null) {
fileList.clear()
fileList.addAll(
listOf("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n",
"o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z")
)
} else {
fileList.clear()
fileList.addAll(
responsesHandler.lastResponseBody.value!!.toList()
)
}
// val fileList = driveResponseBody.value?.toList()
// ?: listOf("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n",
// "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z")
// LazyColumn {
// items(fileList) { name -> Text(text=name, fontSize = 30.sp) }
// }
LazyColumn {
items(lista) { messaggio -> Text(text=messaggio, fontSize = 30.sp) }
items(fileList) { name ->
val logo = painterResource(id = R.drawable.vecchiaicona_)
LogoTextBox(logo, name)
}
}
}
@Composable
fun LogoTextBox(logoPainter: Painter, text: String) {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
shape = RoundedCornerShape(8.dp),
elevation = CardDefaults.cardElevation(defaultElevation = 4.dp)
) {
Row(
modifier = Modifier
.padding(16.dp)
.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
// Logo on the left
Image(
painter = logoPainter,
contentDescription = "Logo",
modifier = Modifier
.size(40.dp) // Adjust size as needed
.padding(end = 16.dp) // Space between logo and text
)
// Text to the right of the logo
Text(
text = text,
fontSize = 20.sp,
color = Color.Black
)
}
}
}

View file

@ -20,36 +20,22 @@ import androidx.security.crypto.MasterKey
import com.bbc.denadrive.HomeNotAuthActivity
import com.bbc.denadrive.MainActivity
import com.bbc.denadrive.home.ui.theme.DeNaDriveTheme
import com.bbc.denadrive.oauth.AuthStatePersistence
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 authPersistence = AuthStatePersistence
val intent: Intent
if (authStateString == "unset") {
if (!authPersistence.isAuthStateSet(this)) {
intent = Intent(this, HomeNotAuthActivity::class.java)
} else {
val authState = authStateString?.let { AuthState.jsonDeserialize(it) }
intent = if (authState?.isAuthorized == true) {
val authState = authPersistence.retrieveAuthState(this)
intent = if (authState.isAuthorized) {
Intent(this, MainActivity::class.java)
}
else {
@ -59,7 +45,6 @@ class NeverLoggedInLogic : ComponentActivity() {
}
}
startActivity(intent)
// Toast.makeText(this, "should not make it here", Toast.LENGTH_SHORT).show()
enableEdgeToEdge()
setContent {

View file

@ -1,29 +1,76 @@
package com.bbc.denadrive.oauth
import android.content.Context
import android.content.SharedPreferences
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey
import net.openid.appauth.AuthState
import net.openid.appauth.AuthorizationException
import net.openid.appauth.AuthorizationResponse
import net.openid.appauth.RegistrationResponse
import net.openid.appauth.TokenResponse
object AuthStatePersistence {
fun retrieveAuthState(context: Context): AuthState {
private fun getAuthStatePrefs(context: Context): SharedPreferences {
val masterKey = MasterKey.Builder(context)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build()
val preferences = EncryptedSharedPreferences.create(
return EncryptedSharedPreferences.create(
context,
"authState",
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
}
fun isAuthStateSet(context: Context): Boolean {
return getAuthStatePrefs(context).getString("authState", null) != null
}
fun retrieveAuthState(context: Context): AuthState {
val preferences = getAuthStatePrefs(context)
preferences.getString("authState", null)?.let {
return AuthState.jsonDeserialize(it)
}
return AuthState(retrieveAuthServConf())
val newAuthState = AuthState(retrieveAuthServConf())
putAuthState(preferences, newAuthState)
return newAuthState
}
fun putAuthState(context: Context, authState: AuthState) {
val preferences = getAuthStatePrefs(context)
putAuthState(preferences, authState)
}
private fun putAuthState(preferences: SharedPreferences, authState: AuthState) {
with (preferences.edit()) {
this.remove("authState")
this.putString("authState", authState.jsonSerializeString())
this.apply()
}
}
fun update(context: Context, authState: AuthState,
authorizationResponse: AuthorizationResponse?,
authorizationException: AuthorizationException?) {
authState.update(authorizationResponse, authorizationException)
putAuthState(context, authState)
}
fun update(context: Context, authState: AuthState,
tokenResponse: TokenResponse?,
authorizationException: AuthorizationException?) {
authState.update(tokenResponse, authorizationException)
putAuthState(context, authState)
}
fun update(context: Context, authState: AuthState,
registrationResponse: RegistrationResponse?) {
authState.update(registrationResponse)
putAuthState(context, authState)
}
}

View file

@ -44,9 +44,6 @@ 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)
@ -59,32 +56,16 @@ class LoadingActivity : ComponentActivity() {
}
}
masterKey = MasterKey.Builder(this)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build()
val authPersistence = AuthStatePersistence
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 authState = authPersistence.retrieveAuthState(this)
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()
}
authPersistence.update(this, authState, response, exception)
Log.e("MainActivity", "authState: ${authState.jsonSerializeString()}", )
} else {
Toast.makeText(this, "Not done :( ${exception?.error}", Toast.LENGTH_SHORT).show()
}
@ -95,12 +76,7 @@ class LoadingActivity : ComponentActivity() {
it
) { resp, ex ->
if (resp != null) {
authState?.update(resp, ex)
with(preferences.edit()) {
this.remove("authState")
this.putString("authState", "${authState?.jsonSerializeString()}")
this.apply()
}
authPersistence.update(this, authState, resp, ex)
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
} else {

View file

@ -3,4 +3,5 @@ plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.kotlin.android) apply false
alias(libs.plugins.kotlin.compose) apply false
kotlin("plugin.serialization") version "1.8.0"
}