Skip to content

Commit

Permalink
Quiltthub example app wip
Browse files Browse the repository at this point in the history
  • Loading branch information
tom-quiltt committed Feb 15, 2024
1 parent 66daaf6 commit 21cac33
Show file tree
Hide file tree
Showing 10 changed files with 222 additions and 48 deletions.
23 changes: 16 additions & 7 deletions app_jetpack_compose/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.INTERNET" />

Expand All @@ -10,36 +11,44 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.App.First">
<activity
android:name=".QuilttHubActivity"
android:exported="true"
android:label="@string/title_activity_quiltt_hub"
android:theme="@style/Theme.App.First">

</activity>
<activity
android:name=".QuilttConnectorActivity"
android:launchMode="singleTop"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/Theme.QuilttConnector">
<tools:validation testUrl="https://quiltt.app/mobile/hub/connect" />

<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data android:scheme="quilttandroidexample"
android:host="open.kotlin.app" />
<data android:scheme="https" />
<data android:host="quiltt.app" />
<data android:pathPattern="/mobile/hub/connect" />
</intent-filter>
</activity>
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:label="@string/app_name"
android:launchMode="singleTop"
android:theme="@style/Theme.App.First">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.intent.action.VIEW" />


<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>


</manifest>
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package app.quiltt.app_jetpack_compose

import android.app.Activity
import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
Expand All @@ -16,15 +17,10 @@ import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import androidx.activity.viewModels
import androidx.compose.material3.Button
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Text
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.viewinterop.AndroidView
import app.quiltt.connector.QuilttConnector
import app.quiltt.connector.QuilttConnectorConnectConfiguration

class MainActivity : ComponentActivity() {
private val viewModel: MainViewModel by viewModels()
Expand All @@ -38,7 +34,7 @@ class MainActivity : ComponentActivity() {
}

setContent {
MainContent()
IngressConnector()
}
}
}
Expand All @@ -56,31 +52,23 @@ class MainViewModel : ViewModel() {
}

@Composable
fun MainContent() {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
LaunchConnectorButton()
}
}

@Composable
fun LaunchConnectorButton() {
fun IngressConnector() {
val context = LocalContext.current
Button(
onClick = {
val intent = Intent(context, QuilttConnectorActivity::class.java)
val quilttConnector = QuilttConnector(context)
val config = QuilttConnectorConnectConfiguration(connectorId = "8eopdcftmz")
val connectorWebView = quilttConnector.connect(config = config, onExitSuccess = { metadata ->
val token: String? = metadata.token
if (token != null) {
SharedPreferencesHelper(context).saveData("token", token)
val intent = Intent(context, QuilttHubActivity::class.java)
context.startActivity(intent)
},
colors = ButtonDefaults.buttonColors(containerColor = Color(0xFF800080))
) {
Text("Launch Connector")
}
}
})
AndroidView(factory = { connectorWebView } )
}

@Preview(showBackground = true)
@Composable
fun QuilttHubPreview() {
MainContent()
IngressConnector()
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,16 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.viewinterop.AndroidView
import app.quiltt.connector.QuilttConnector
import app.quiltt.connector.QuilttConnectorConnectConfiguration
import android.content.Intent
import android.net.Uri

class QuilttConnectorActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val config = QuilttConnectorConnectConfiguration(
connectorId = "<CONNECTOR_ID>",
oauthRedirectUrl = "<YOUR_HTTP_APP_LINK")
val token = "<ACCESS_TOKEN>"
connectorId = "zpwvwel08q",
oauthRedirectUrl = "https://quiltt.app/mobile/hub/connect")
val token = SharedPreferencesHelper(context = this).getData("token")
setContent {
QuilttConnectorContent(config = config, token = token)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package app.quiltt.app_jetpack_compose

import android.os.Bundle
import android.view.ViewGroup
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.viewinterop.AndroidView

class QuilttHubActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
QuilttHubContent()
}
}
}

@Composable
fun QuilttHubContent() {
val token = SharedPreferencesHelper(context = LocalContext.current).getData("token")
val url = "https://www.quiltthub.com/login?token=$token"
println(url)
WebViewComposable(url = url)
}

@Composable
fun WebViewComposable(url: String) {
AndroidView(factory = { context ->
WebView(context).apply {
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
settings.javaScriptEnabled = true
settings.domStorageEnabled = true
webViewClient = WebViewClient()
loadUrl(url)
}
}, update = { webView ->
webView.loadUrl(url)
})
}

@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
QuilttHubContent()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package app.quiltt.app_jetpack_compose

import android.content.Context
import android.content.SharedPreferences

class SharedPreferencesHelper(context: Context) {
private val sharedPreferences: SharedPreferences =
context.getSharedPreferences("MyAppPreferences", Context.MODE_PRIVATE)

fun saveData(key: String, value: String) {
val editor = sharedPreferences.edit()
editor.putString(key, value)
editor.apply()
}

fun getData(key: String): String? {
return sharedPreferences.getString(key, null)
}
}
1 change: 1 addition & 0 deletions app_jetpack_compose/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<resources>
<string name="app_name">App Jetpack Compose</string>
<string name="title_activity_quiltt_connector">QuilttConnectorActivity</string>
<string name="title_activity_quiltt_hub">QuilttHubActivity</string>
</resources>
96 changes: 96 additions & 0 deletions connector/src/main/java/app/quiltt/connector/QuilttAuthApi.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package app.quiltt.connector

import java.io.BufferedReader
import java.io.InputStreamReader
import java.io.OutputStreamWriter
import java.net.HttpURLConnection
import java.net.URL
import org.json.JSONObject

data class EmailInput(val email: String)
data class PhoneInput(val phone: String)

sealed class UsernamePayload {
data class Email(val email: String) : UsernamePayload()
data class Phone(val phone: String) : UsernamePayload()
}

data class PasscodePayload(val usernamePayload: UsernamePayload, val passcode: String)

data class SessionData(val token: String)
data class UnauthorizedData(val message: String, val instruction: String)
data class UnprocessableData(val attribute: Map<String, List<String>>)

class QuilttAuthApi(private val clientId: String?) {
private val endpointAuth = "https://www.quiltt.dev/api-reference/rest/auth"

fun ping(token: String): SessionData {
val url = URL(endpointAuth)
val connection = url.openConnection() as HttpURLConnection
connection.requestMethod = "GET"
connection.setRequestProperty("Authorization", "Bearer $token")

val reader = BufferedReader(InputStreamReader(connection.inputStream))
val response = reader.readLine()
reader.close()

val jsonObject = JSONObject(response)
return SessionData(jsonObject.getString("token"))
}

fun identify(payload: UsernamePayload): SessionData {
val url = URL(endpointAuth)
val connection = url.openConnection() as HttpURLConnection
connection.requestMethod = "POST"
connection.setRequestProperty("Content-Type", "application/json; utf-8")
connection.doOutput = true

val jsonPayload = JSONObject()
jsonPayload.put("clientId", clientId)
jsonPayload.put("payload", payload)

val writer = OutputStreamWriter(connection.outputStream)
writer.write(jsonPayload.toString())
writer.flush()
writer.close()

val reader = BufferedReader(InputStreamReader(connection.inputStream))
val response = reader.readLine()
reader.close()

val jsonObject = JSONObject(response)
return SessionData(jsonObject.getString("token"))
}

fun authenticate(payload: PasscodePayload): SessionData {
val url = URL(endpointAuth)
val connection = url.openConnection() as HttpURLConnection
connection.requestMethod = "PUT"
connection.setRequestProperty("Content-Type", "application/json; utf-8")
connection.doOutput = true

val jsonPayload = JSONObject()
jsonPayload.put("clientId", clientId)
jsonPayload.put("payload", payload)

val writer = OutputStreamWriter(connection.outputStream)
writer.write(jsonPayload.toString())
writer.flush()
writer.close()

val reader = BufferedReader(InputStreamReader(connection.inputStream))
val response = reader.readLine()
reader.close()

val jsonObject = JSONObject(response)
return SessionData(jsonObject.getString("token"))
}

fun revoke(token: String) {
val url = URL(endpointAuth)
val connection = url.openConnection() as HttpURLConnection
connection.requestMethod = "DELETE"
connection.setRequestProperty("Authorization", "Bearer $token")
connection.connect()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ package app.quiltt.connector

interface QuilttConnectorConfiguration {
val connectorId: String
val oauthRedirectUrl: String
val oauthRedirectUrl: String?
val connectionId: String?
}

data class QuilttConnectorConnectConfiguration(
override val connectorId: String,
override val oauthRedirectUrl: String,
override val oauthRedirectUrl: String? = null
) : QuilttConnectorConfiguration {
override val connectionId: String? = null // always null for connect, cannot be set
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ package app.quiltt.connector
data class ConnectorSDKCallbackMetadata(
val connectorId: String,
val profileId: String?,
val connectionId: String?
val connectionId: String?,
val token: String?
)

typealias ConnectorSDKOnEventCallback = (ConnectorSDKEventType, ConnectorSDKCallbackMetadata) -> Unit
Expand Down
Loading

0 comments on commit 21cac33

Please sign in to comment.