Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Initial UI implementation #12

Merged
merged 1 commit into from
Mar 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,15 @@ dependencies {
implementation("androidx.compose.ui:ui-graphics")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.compose.material3:material3")
implementation(project(":siren-sdk"))
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
androidTestImplementation(platform("androidx.compose:compose-bom:2023.08.00"))
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest")

// Navigation
implementation("androidx.navigation:navigation-compose:2.7.7")
}
141 changes: 119 additions & 22 deletions app/src/main/java/com/keyvalue/sirensampleapp/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,45 +3,142 @@ package com.keyvalue.sirensampleapp
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Notifications
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.keyvalue.siren.androidsdk.data.model.AllNotificationResponseData
import com.keyvalue.siren.androidsdk.helper.client.BadgeThemeProps
import com.keyvalue.siren.androidsdk.helper.client.SirenSDK
import com.keyvalue.siren.androidsdk.helper.client.SirenSDKClient
import com.keyvalue.siren.androidsdk.helper.client.callbacks.ErrorCallback
import com.keyvalue.siren.androidsdk.helper.client.callbacks.SirenInboxCallback
import com.keyvalue.siren.androidsdk.helper.client.callbacks.SirenInboxIconCallback
import com.keyvalue.siren.androidsdk.helper.customization.SirenInboxIconProps
import com.keyvalue.siren.androidsdk.helper.customization.SirenInboxProps
import com.keyvalue.siren.androidsdk.helper.customization.Theme
import com.keyvalue.siren.androidsdk.helper.customization.ThemeProps
import com.keyvalue.sirensampleapp.ui.theme.SirenSampleAppTheme
import org.json.JSONObject

@Composable
fun NotificationIcon(
sirenSDK: SirenSDKClient,
navController: NavController,
) {
Surface(
color = MaterialTheme.colorScheme.background,
) {
sirenSDK.SirenInboxIcon(
SirenInboxIconProps(
theme =
Theme(
dark =
ThemeProps(
badgeStyle =
BadgeThemeProps(
color = Color.Red,
textColor = Color.White,
),
),
),
darkMode = true,
notificationIcon = {
Icon(
imageVector = Icons.Default.Notifications,
contentDescription = "notification icon with unread notifications indicator",
tint = Color(236, 155, 112, 255),
modifier = Modifier.size(100.dp),
)
},
),
object : SirenInboxIconCallback {
override fun onError(jsonObject: JSONObject) {
}

override fun onClick() {
navController.navigate("notification_window")
}
},
)
}
}

@Composable
fun NotificationWindow(
sirenSDK: SirenSDKClient,
navController: NavController,
) {
Surface(
color = MaterialTheme.colorScheme.background,
) {
sirenSDK.SirenInbox(
SirenInboxProps(),
object : SirenInboxCallback {
override fun onCardClick(notificationItem: AllNotificationResponseData) {
}

override fun onError(jsonObject: JSONObject) {
}
},
)
}
}

@Composable
fun MyApp(sirenSDK: SirenSDKClient) {
val navController = rememberNavController()

NavHost(navController, startDestination = "notification_icon") {
composable("notification_icon") {
NotificationIcon(sirenSDK, navController)
}
composable("notification_window") {
NotificationWindow(sirenSDK, navController)
}
}
}

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

// replace with userToken and recipientId

val sirenSDK =
SirenSDK.getInstance(
this,
"userToken",
"recipientId",
object : ErrorCallback {
override fun onError(jsonObject: JSONObject) {
}
},
)
setContent {
SirenSampleAppTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background,
) {
Greeting("Android")
Box(
modifier = Modifier.fillMaxSize(),
) {
MyApp(sirenSDK)
}
}
}
}
}
}

@Composable
fun Greeting(
name: String,
modifier: Modifier = Modifier,
) {
Text(
text = "Hello $name!",
modifier = modifier,
)
}

@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
Greeting("Android")
}
1 change: 0 additions & 1 deletion siren-sdk/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

<!-- TODO Remove the application tag -->
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.keyvalue.siren.androidsdk.data.model

import androidx.annotation.Keep
import com.keyvalue.siren.androidsdk.utils.constants.BulkUpdateType

@Keep
data class BulkUpdateBody(
val until: String?,
val operation: BulkUpdateType?,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.keyvalue.siren.androidsdk.data.model

import androidx.annotation.Keep

@Keep
data class DataStatus(
val status: String,
)
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.keyvalue.siren.androidsdk.data.model

import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName

@Keep
data class InAppRecipient(
@SerializedName("id")
val id: String,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.keyvalue.siren.androidsdk.data.model

import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName

@Keep
data class MarkAllAsReadResponse(
@SerializedName("data")
val markAllAsReadResponse: DataStatus?,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.keyvalue.siren.androidsdk.data.model

import androidx.annotation.Keep

@Keep
data class MarkAsReadBody(
val isRead: Boolean?,
val isDelivered: Boolean?,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.keyvalue.siren.androidsdk.data.model

import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName

@Keep
data class MarkAsReadByIdResponse(
@SerializedName("data")
val markAsReadByIdResponse: MarkAsReadByIdResponseData,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.keyvalue.siren.androidsdk.data.model

import androidx.annotation.Keep

@Keep
data class MarkAsViewedBody(
val lastOpenedAt: String,
)
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.keyvalue.siren.androidsdk.data.model

import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName

@Keep
data class MarkAsViewedResponse(
@SerializedName("data")
val markAsViewedResponse: MarkAsViewedResponseData?,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.keyvalue.siren.androidsdk.data.model

import androidx.annotation.Keep

@Keep
data class MarkAsViewedResponseData(
val createdAt: String,
val createdBy: String,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.keyvalue.siren.androidsdk.data.model

import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName

@Keep
data class UnViewedNotificationResponse(
@SerializedName("data")
val unViewedNotificationResponse: UnViewedNotificationResponseData?,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.keyvalue.siren.androidsdk.data.model

import androidx.annotation.Keep

@Keep
data class UnViewedNotificationResponseData(
val id: String,
val createdAt: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import com.keyvalue.siren.androidsdk.data.model.AuthenticationResponse
import com.keyvalue.siren.androidsdk.data.networkcallbacks.NetworkCallback
import com.keyvalue.siren.androidsdk.data.retrofit.RetrofitClient
import com.keyvalue.siren.androidsdk.data.service.AuthenticationApiService
import com.keyvalue.siren.androidsdk.utils.constants.CODE_GENERIC_API_ERROR
import com.keyvalue.siren.androidsdk.utils.constants.CODE_TIMED_OUT
import com.keyvalue.siren.androidsdk.utils.constants.ERROR_MESSAGE_SERVICE_NOT_AVAILABLE
import com.keyvalue.siren.androidsdk.utils.constants.ERROR_MESSAGE_TIMED_OUT
import com.keyvalue.siren.androidsdk.utils.constants.GENERIC_API_ERROR
import com.keyvalue.siren.androidsdk.utils.constants.SirenErrorTypes
import com.keyvalue.siren.androidsdk.utils.constants.TIMED_OUT
import org.json.JSONObject
import java.net.SocketTimeoutException

Expand Down Expand Up @@ -40,17 +40,17 @@ class AuthenticationRepositoryImplementation(baseURL: String) : AuthenticationRe
networkCallback.onError(
JSONObject()
.put("type", SirenErrorTypes.ERROR)
.put("code", errors.error?.errorCode ?: CODE_GENERIC_API_ERROR)
.put("code", errors.error?.errorCode ?: GENERIC_API_ERROR)
.put("message", errors.error?.message ?: "HTTP error! status: ${parentResponse.raw().code} ${parentResponse.raw().message}"),
)
}
}
} catch (e: SocketTimeoutException) {
networkCallback.onError(
JSONObject().put("code", CODE_TIMED_OUT).put("message", ERROR_MESSAGE_TIMED_OUT),
JSONObject().put("code", TIMED_OUT).put("message", ERROR_MESSAGE_TIMED_OUT),
)
} catch (e: Exception) {
networkCallback.onError(JSONObject().put("code", CODE_GENERIC_API_ERROR).put("message", ERROR_MESSAGE_SERVICE_NOT_AVAILABLE))
networkCallback.onError(JSONObject().put("code", GENERIC_API_ERROR).put("message", ERROR_MESSAGE_SERVICE_NOT_AVAILABLE))
}
}
}
Loading