diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..7a5fc94 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,45 @@ +This template outlines the recommended format for creating pull requests within this project. Please fill out all sections before submitting your PR + +## Branch Naming: + +- Use a descriptive branch name that reflects the change and follows the format: [type]/[brief-description] +- Replace [type] with feature, fix, refactor, hotfix, or other relevant categories +- Keep the description concise and clear + +## Commit Guidelines: + +- Adhere to the "scope:subject" commit message structure +- Scope can be feat, fix, docs, test, refactor, build, format, etc. +- Use imperative tense (e.g., "fix: User unable to login") +## Pull Request Checklist: + +[ ] **Read the contributing guidelines**
+[ ] **Branch is up-to-date with the base branch: main (or other designated branch)**
+[ ] **Changes pass all tests: npm test or yarn test (or equivalent command)**
+[ ] **Documentation has been updated (if applicable)**
+## Description: +- Start your pull request summary with a clear and informative heading. Use the Markdown syntax `##` for the heading, like `## Your Heading Here`. +- For the section detailing the changes introduced by this pull request, use the Markdown heading `## Changes`. +- Briefly describe the changes introduced in this pull request.Ensure that the changelog has been updated accordingly +- Explain the motivation and the problem it solves +- Mention any breaking changes +- Link to related issues or internal tickets +## Additional Notes: + +- Include any other relevant information, such as limitations, known issues, or future improvements. +## Screenshots (if applicable): + +- Add screenshots or GIFs to help visualize your changes. +## Testing Instructions: + +- Provide step-by-step instructions on how to test your changes +## Checklist for Reviewers: + +[ ] **Code follows project conventions and style guidelines**
+[ ] **Changes do not introduce new warnings or errors**
+[ ] **Unit tests cover the changes adequately**
+[ ] **Documentation is updated correctly and reflects the changes**
+Additional Information: + +By submitting this pull request, I confirm that my contribution is made under the terms of the MIT License. + diff --git a/.github/workflows/test-and-build.yml b/.github/workflows/test-and-build.yml new file mode 100644 index 0000000..51348b2 --- /dev/null +++ b/.github/workflows/test-and-build.yml @@ -0,0 +1,48 @@ +name: test-and-build + +env: + # The name of the main module repository + main_project_module: app + +on: + + pull_request: + branches: [master, develop] + + # # Allows you to run this workflow manually from the Actions tab + # workflow_dispatch: + +jobs: + test-and-build: + + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + with: + ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: 0 + + - name: Set Up JDK + uses: actions/setup-java@v3 + with: + distribution: 'zulu' # See 'Supported distributions' for available options + java-version: '17' + cache: 'gradle' + + - name: Change wrapper permissions + run: chmod +x ./gradlew + + # Run ktlint checks + - name: Run ktlint checks + run: ./gradlew ktlintCheck + + # Run Build Project + - name: Build gradle project + run: ./gradlew build + + # Create Bundle AAB Release + # Noted for main module build [main_project_module]:bundleRelease + - name: Build app bundle release + run: ./gradlew ${{ env.main_project_module }}:bundleRelease diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..fde9511 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,56 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +## [Unreleased] + +### Added + +- New feature or enhancement. + +### Changed + +- Updates to existing features. + +### Deprecated + +- Features or functionalities to be removed in future releases. + +### Removed + +- Features or functionalities that have been removed. + +### Fixed + +- Bug fixes. + +### Security + +- Security-related changes. + +## [Version] - YYYY-MM-DD + +### Added + +- New feature or enhancement. + +### Changed + +- Updates to existing features. + +### Deprecated + +- Features or functionalities to be removed in future releases. + +### Removed + +- Features or functionalities that have been removed. + +### Fixed + +- Bug fixes. + +### Security + +- Security-related changes + diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..b9a6c7f --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +- The use of sexualized language or imagery and unwelcome sexual attention or + advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic + address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at it.team@keyvalue.systems. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..c8b26f7 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,13 @@ +# Contributing + +When contributing to this repository, please first discuss the change you wish to make via issue, +email, or any other method with the owners of this repository before working on a change. + +Please note we have a code of conduct, please follow it in all your interactions with the project. + +## Pull Request Guidelines + +1. Please ensure your proposal will not radically change current functionality or bring along breaking changes. +2. PRs only consisting of typo fixes (or other automated contributions), will not be accepted. +4. Document your changes thoroughly. +6. Be reactive to any comments, reviews or change requests entered in your pull request. diff --git a/README.md b/README.md new file mode 100644 index 0000000..6e23815 --- /dev/null +++ b/README.md @@ -0,0 +1,575 @@ +
+ +

Siren Android Inbox

+
+ +## Table of Contents + + + +- [Overview](#overview) +- [Quick Start Guide](#quick-start-guide) + - [Install Siren SDK](#install-siren-sdk) + - [Using Android Studio](#using-android-studio) + - [Siren Inbox Icon](#siren-inbox-icon) + - [Siren Inbox](#siren-inbox) + - [Error Codes](#error-codes) + - [Complete Code Example](#complete-code-example) +- [I want to know more!](#i-want-to-know-more) + + + + + + +## Overview + +The siren-android-inbox sdk is a comprehensive and customizable android UI kit for displaying and managing notifications. This documentation provides comprehensive information on how to install, configure, and use the sdk effectively. + +## Quick Start Guide + +### Install Siren SDK + +You will need your sdk token for initializing your library. + +### Using Android Studio + +1. If this is your first time using Android Studio, Install Android Studio and dependencies + from [Android Studio's Website](https://developer.android.com/studio). And start a new project. +2. Add the JitPack repository to your build file + +```kotlin +allprojects { + repositories { + ... + maven { url 'https://jitpack.io' } + } +} +``` + +3. Add the dependency + +```kotlin +dependencies { + implementation 'com.github.keyvalue:siren-android-inbox:1.0.0' +} +``` + +## Initialize SirenSDK + +Import and initialize `SirenSDK` in `MainActivity`, passing the context, token, recipientId and errorCallback + +```kotlin +import com.keyvalue.siren.androidsdk.helper.client.SirenSDK + +class MainActivity { + ... + + val sirenSDK = + SirenSDK.getInstance( + context = applicationContext, + token = "USER_TOKEN", + recipientId = "RECIPIENT_ID", + object : ErrorCallback { + override fun onError(jsonObject: JSONObject) { + } + }, + ) + ... +} +``` + +### Siren Inbox Icon + +This composable function includes a customizable notification iconĀ and a badge for indicating the number of un-viewed notifications in the user interface. + +```kotlin +import com.keyvalue.siren.androidsdk.helper.customization.SirenInboxIconProps + +sirenSDK.SirenInboxIcon( + SirenInboxIconProps( + theme = customTheme, + darkMode = true, + customStyles = customStyles, + notificationIcon = CustomIcon(), + ), + object : SirenInboxIconCallback { + override fun onError(jsonObject: JSONObject) { + } + + override fun onClick() { + } + }, +) + +``` + +#### Siren Inbox Icon Props + +Given below are the list of parameters of Icon composable function. + +Parameter | Description | Type | Default value | +--- | --- | --- | --- | +theme | Theme Data class defining the theme configuration options | Theme | null | +customStyles | Custom style Props Data class defining the customizable styling options | CustomStyles | null | +notificationIcon | Option to use custom notification Icon | @Composable (() -> Unit)? | null | +darkMode | Flag to enable dark mode | Boolean | false | +disabled | Flag to disable click handler of icon | Boolean | false | + +### Siren Inbox + +Siren Inbox is a paginated list view for displaying notifications. + +```kotlin +import com.keyvalue.siren.androidsdk.helper.customization.SirenInboxProps +import com.keyvalue.siren.androidsdk.data.model.AllNotificationResponseData + +sirenSDK.SirenInbox( + SirenInboxProps( + theme = customTheme, + title = "Notifications", + hideHeader = false, + darkMode = true, + ), + object : SirenInboxCallback { + override fun onCardClick(notificationItem: AllNotificationResponseData) { + } + + override fun onError(jsonObject: JSONObject) { + } + }, +) + +``` + +#### Siren Inbox Props + +Given below are the list of parameters of the Siren inbox composable function. + +Parameter | Description | Type | Default value | +--- | --- | --- | --- | +theme | Theme Data class defining the theme configuration options | Theme | null | +customStyles | Custom styling configuration options | Theme | null | +title | Title of the notification window | String | "Notifications" | +hideHeader | Flag to hide or show the header | Boolean | false | +hideClearAll | Flag to hide or show the clear all button in header | Boolean | false | +darkMode | Flag to enable dark mode | Boolean | false | +cardProps | Props for customizing the notification cards | CardProps | null | +listEmptyComponent | Custom composable function to display when the notification list is empty | (@Composable () -> Unit) | null | +customHeader | Custom header component | (@Composable () -> Unit) | null | +customFooter | Custom footer component | (@Composable () -> Unit) | null | +customNotificationCard | Custom function for rendering notification cards | (@Composable (AllNotificationResponseData) -> Unit) | null | +customLoader | Custom composable function for displaying loader | (@Composable () -> Unit) | null | +customErrorWindow | Custom composable function for displaying error window | (@Composable () -> Unit) | null | +itemsPerFetch | Number of notifications to be fetched each time | Int | 20 + +#### Theming options + +Customize the theme configuration consisting of various theme properties such as colors, badge styles, window header styles, window container styles, and notification card styles. + +```kotlin +import androidx.compose.ui.graphics.Color + +data class Theme( + val dark: ThemeProps? = null, + val light: ThemeProps? = null, +) + +data class ThemeProps( + val colors: ThemeColors? = null, + val badgeStyle: BadgeThemeProps? = null, + val windowHeader: WindowHeaderThemeProps? = null, + val windowContainer: WindowContainerThemeProps? = null, + val notificationCard: NotificationCardThemeProps? = null, +) + +data class ThemeColors( + val primaryColor: Color? = null, + val textColor: Color? = null, + val neutralColor: Color? = null, + val borderColor: Color? = null, + val highlightedCardColor: Color? = null, + val dateColor: Color? = null, + val deleteIcon: Color? = null, + val timerIcon: Color? = null, + val clearAllIcon: Color? = null, + val infiniteLoader: Color? = null, +) + +data class BadgeThemeProps( + val color: Color? = null, + val textColor: Color? = null, +) + +data class WindowHeaderThemeProps( + val background: Color? = null, + val titleColor: Color? = null, + val headerActionColor: Color? = null, + val borderColor: Color? = null, +) + +data class WindowContainerThemeProps( + val background: Color? = null, +) + +data class NotificationCardThemeProps( + val borderColor: Color? = null, + val background: Color? = null, + val titleColor: Color? = null, + val descriptionColor: Color? = null, +) +``` + +#### Styling options + +Customize the styling configurations for various UI elements such as notification icons, windows, window headers, window containers, notification cards, badges, delete icon, date icon, and clear all icon. + +```js +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.TextUnit +import androidx.compose.ui.graphics.Shape + +data class CustomStyles( + val notificationIcon: NotificationIconStyle? = null, + val window: WindowStyle? = null, + val windowHeader: WindowHeaderStyle? = null, + val windowContainer: WindowContainerStyle? = null, + val notificationCard: NotificationCardStyle? = null, + val badgeStyle: BadgeStyle? = null, + val deleteIcon: DeleteIconStyle? = null, + val dateIcon: DateIconStyle? = null, + val clearAllIcon: ClearAllIconStyle? = null, +) + +data class NotificationIconStyle( + val size: Dp? = null, +) + +data class WindowStyle( + val width: Dp? = null, + val height: Dp? = null, +) + +data class WindowHeaderStyle( + val height: Dp? = null, + val titleFontWeight: FontWeight? = null, + val titleSize: TextUnit? = null, + val closeIconSize: Dp? = null, + val titlePadding: Dp? = null, +) + +data class WindowContainerStyle( + val padding: Dp? = null, +) + +data class NotificationCardStyle( + val padding: Dp? = null, + val borderWidth: Dp? = null, + val avatarSize: Dp? = null, + val titleFontWeight: FontWeight? = null, + val titleSize: TextUnit? = null, + val descriptionSize: TextUnit? = null, + val dateSize: TextUnit? = null, +) + +data class BadgeStyle( + val size: Dp? = null, + val textSize: TextUnit? = null, + val borderShape: Shape? = null, + val top: Int? = null, + val right: Int? = null, +) + +data class DeleteIconStyle( + val size: Dp? = null, +) + +data class DateIconStyle( + val size: Dp? = null, +) + +data class ClearAllIconStyle( + val size: Dp? = null, +) + +``` + +### Functions + +These are the functions for modifying notifications. + +Function | Parameters | +--- | --- | +markAsRead | notificationId, callback | +markNotificationsAsReadByDate | untilDate, callback | +markNotificationsAsViewed | untilDate, callback | +deleteNotificationsByDate | untilDate, callback | +deleteNotification | notificationId, callback | +updateToken | userToken, recipientId + +### Error codes + +Given below are all possible error codes thrown by sdk. + +Error code | Message | Description | +--- | --- | --- | +TIMED_OUT | Timed out | Request timed out| +INVALID_TOKEN | Invalid token | Invalid token | +INVALID_RECIPIENT_ID | Invalid recipient id | Invalid recipient id | +TOKEN_VERIFICATION_FAILED | Token verification failed | This operation requires a valid token | +GENERIC_API_ERROR | Generic api error | Service is not available | + +### Complete Code Example + +Here's a runnable code example that covers everything in this quick start guide. + +```kotlin + +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.runtime.Composable +import androidx.compose.ui.Modifier +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.data.model.DataStatus +import com.keyvalue.siren.androidsdk.data.model.MarkAsReadByIdResponseData +import com.keyvalue.siren.androidsdk.data.model.MarkAsViewedResponseData +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.MarkAsReadByIdCallback +import com.keyvalue.siren.androidsdk.helper.client.callbacks.MarkAsViewedCallback +import com.keyvalue.siren.androidsdk.helper.client.callbacks.SirenAllNotificationUpdateCallback +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 { + Surface( + color = MaterialTheme.colorScheme.background, + ) { + Box( + modifier = Modifier.fillMaxSize(), + ) { + MyApp(sirenSDK) + } + } + } + } + + fun markAsRead() { + sirenSDK.markAsRead( + notificationId = "notificationId", + callback = object : MarkAsReadByIdCallback { + override fun onSuccess(responseData: MarkAsReadByIdResponseData?) { + // onSuccess + } + + override fun onError(jsonObject: JSONObject) { + // onError + } + } + ) + } + + fun markNotificationsAsReadByDate() { + sirenSDK.markNotificationsAsReadByDate( + startDate = "startDate", + callback = object : SirenAllNotificationUpdateCallback { + override fun onSuccess(dataStatus: DataStatus?) { + // onSuccess + } + + override fun onError(jsonObject: JSONObject) { + // onError + } + + } + ) + } + + fun markNotificationsAsViewed() { + sirenSDK.markNotificationsAsViewed( + startDate = "startDate", + callback = object : MarkAsViewedCallback { + override fun onSuccess(responseData: MarkAsViewedResponseData) { + // onSuccess + } + + override fun onError(jsonObject: JSONObject) { + // onError + } + + } + ) + } + + fun deleteNotificationsByDate() { + sirenSDK.deleteNotificationsByDate( + startDate = "startDate", + callback = object : SirenAllNotificationUpdateCallback { + override fun onSuccess(dataStatus: DataStatus?) { + // onSuccess + } + + override fun onError(jsonObject: JSONObject) { + // onError + } + + } + ) + } + + fun deleteNotification() { + sirenSDK.deleteNotification( + notificationId = "notificationId", + callback = object : SirenAllNotificationUpdateCallback { + override fun onSuccess(dataStatus: DataStatus?) { + // onSuccess + } + + override fun onError(jsonObject: JSONObject) { + // onError + } + + } + ) + } + + fun updateToken() { + sirenSDK.updateToken( + userToken = "userToken", + recipientId = "recipientId" + ) + } + + + } +} + + +``` + +### I want to know more! + +No worries, here are some links that you will find useful: + +* **[Advanced Kotlin-Android Guide](https://developer.android.com/kotlin)** \ No newline at end of file