Giter Site home page Giter Site logo

xmartlabs / gong Goto Github PK

View Code? Open in Web Editor NEW
89.0 12.0 5.0 2.21 MB

Xmartlabs' Android Base Project Template

License: MIT License

Kotlin 94.58% Shell 5.42%
android baseproject boilerplate architecture-components kotlin-android hacktoberfest mvi redux-android store jetpack-compose

gong's Introduction

Run lints and compile codebeat badge

Gong is Xmartlabs' official Android template project, written in Kotlin, and focused on providing a solid app architecture. One of the main objectives of this project is to supply a good starting point for all new android apps, which lets you move forward fast using the latest Android Components and libraries. We're using "clean architecture" to structure, decouple, expand, and maintain the code.

Table of content

Architecture

There are 4 layers within the application:

  • Domain layer - contains high-level abstraction of the application domain (like repositories, data access) and the use cases, which contain all of the application's business logic & domain rules.
  • Data layer - implements domain layer abstractions, the DataSources, related to data persistence, REST calls, etc.
  • Device layer - implements domain layer abstractions that are not related to data persistence or user interface but are specific to the android platform: android services, cloud messaging, and many others.
  • Presentation (UI) layer - all the functionality related to the Android user interface: built on top of Jetpack Compose.

Overview

In order to understand how this work together, it's important to talk about each component's role inside the presentation layer.

First of all, the architecture. When jetpack compose is used, it's convenient to use an architecture based on an state. In this case, a combination of MVI and Redux patterns was chosen. The MVI pattern has three main components: Intent, Model, and View. The intent refers to the intention to change the state of the app, so in Gong's case, it would be the actions, delivered then to ViewModel. ViewModel holds the model component of the pattern. It is responsible of creation of a new state, which is an immutable data structure. At any given moment, there is only one state in the app, which represents a single source of truth. The only way to change the state is to create a new one, triggered by the actions. But when and how is the new state created? The Redux pattern comes up at this point. Redux is a pattern and library for managing and updating application state, using events called "actions". More precisely, the main components of Redux are State, Action, and Reducer. In Gong the composables communicate actions to the viewModels so they can manage and emit the state back to view. This ensure state can only be updated in a predictable way. Then, inside the model, the reducer is called with a proper action and the latest state and forward its result as an output value of the model. Reducer is a function that takes the previous state and action and creates a new state, and in Gong this role is played by the function processAction, located in viewModels.

To continue with the insight of the project, let's see how this is done. With the shared flow, actions are broadcast to an unknown number (zero or more) of subscribers. In the absence of a subscriber, any posted action is immediately dropped. It is a design pattern to use for actions that must be processed immediately or not at all.

The ViewModel handles each action in the processAction method. Whenever an action is added to the "contract", it also has to be added here. So all actions can be managed from the same place. With the channel, each event is delivered to a single subscriber. An attempt to post an event without subscribers will suspend as soon as the channel buffer becomes full, waiting for a subscriber to appear. Posted events are never dropped by default. Then to handle this Ui effects and all things that should be displayed only once, "oneShotEvents" are used. Because Channels are hot and it is not necessary to show side effect again when orientation changed or UI become visible again.

Finally, for handling UiState, StateFlow is used. StateFlow is a state-holder observable flow that emits the current and new state updates to its collectors, similar to a LiveData but with an initial value. So a state is always present. It's also a kind of SharedFlow. It's always expected to receive last view state when UI become visible.

Gong's Workflow example:

Layers components and roles

Now, as a way to give you an overview of the other layers and how the interaction with the presentation layer is done, let's review it's components.

To the presentation layer, the UseCases are the ones who resolve each invocation from the ViewModels, and they both interact using coroutines library. A UseCase is a reusable component that might be used from different ViewModels. The same goes for Repositories, a repository can stand on its own without the ViewModel and be re-used from different use cases. All these classes exist with a clear goal and purpose. The logic is split sensibly. It is worth to say that these repositories refer to those of the repository pattern. Repository design pattern facilitates de-coupling of the business logic and the data access layers in your application with the former not having to have any knowledge on how data persistence would actually take place. Repositories have the function of communication between Domain Layer and Data Layer. More precisely, with coroutines help, they have to implement the necessary logic so they can call Remote and Local sources methods.

At the end of the chain, as mentioned, Data Layer is found. It is responsible for persisting and obtaining all the data required for the model using different sources. Repositories use the store library to combine those different sources. The remote sources are the ones who manage interaction with the different endpoints. The local sources manage data base logic.

The core library for the communication between layer components is: Coroutines, used to perform all background tasks.

Core Libraries

The main libraries that we are using are:

  • Android Architecture Components - Jetpack:
    • Jetpack Compose which is the library used by the UI with all its composables.
    • ViewModel which allows you navigate between composables while taking advantage of the Navigation component’s infrastructure and features.
    • Android Navigation Component used to navigate across different pieces of content within your app.
    • Room, a SQLite object mapping library.
  • Coroutines for asynchronous programming
  • Coil, an image loading library for Android backed by Kotlin Coroutines.
  • Koin, a lightweight dependency injection framework for Kotlin.
  • OkHttp and Retrofit for network communication.
  • Store, helps to manage the loading of data from different sources.
  • AndroidSwissKnife a set of extensions, helpers, and useful classes.
  • Timber one of the most popular loggers on Android.
  • Stetho, a sophisticated debug bridge for Android applications.
  • LeakCanary, a memory leak detection library for Android.
  • AndroidSnapshotPublisher, one of the most important tools used in the QA process, it's a Gradle plugin that prepares and distributes deliverable versions easily when they are ready to test.

Setup

To use this template, you can use the gong_setup.sh script that automatizes the setup process. You can run it remotely executing the following command:

bash <(curl -s https://raw.githubusercontent.com/xmartlabs/gong/main/gong_setup.sh)

It will clone and setup all variables that you need. If you prefer to do it manually, you have to follow these steps:

  • Clone the project
  • Update the applicationId in the app's build gradle file.
  • Change the package structure based on your application id.

Configuration and secrets

The app's version name is defined in the project's Gradle file. The app's version code is autogenerated based on the app's version name.

You have two files to define your constants: config.properties which stores all of the app's configuration, like the backend's base URL, for example. secrets/keys.properties which contains all of the secrets in your app, like a given API key for a third party service. That environment's variables are injected in the app's build.gradle, and they are accessible via the BuildConfig generated file. The app access to that variables using the Config file.

The keystores are stored in the secrets folder, which is not tracked in git.

The library versions are managed in a versions Gradle file

Product Flavors

The app uses two flavors, one for production (prod) and another for development (dev) build.

Each flavor defines and application class (App.kt), that is used to define custom configurations in each one. For example, the navigation logger listener is defined only for development builds.

What's next?

For an answer to this question you can check the current project status and if you happen to come up with a new idea you can always open a new issue!

About

Made with ❤️ by XMARTLABS

gong's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gong's Issues

Signin error toast not shown in jetpack compose (main-v2)

Signin error toast not shown in jetpack compose, intentionally been trying to put invalid username/pwd but toast never appears on screen

private fun showSignInError(throwable: Throwable, context: Context) {
  if (throwable is SecurityException) {
    // In a real project, the string should be defined as a string resource.
    Toast.makeText(
        context,
        "password or username is wrong, try with userId = 'xmartlabs', password 'xmartlabs'",
        Toast.LENGTH_SHORT
    ).show()
  }
}

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Rate-Limited

These updates are currently rate-limited. Click on a checkbox below to force their creation now.

  • fix(deps): update dependency androidx.compose.compiler:compiler to v1.5.15
  • fix(deps): update dependency androidx.lifecycle:lifecycle-viewmodel-compose to v2.8.4
  • fix(deps): update dependency com.google.firebase:firebase-crashlytics-gradle to v3.0.2
  • fix(deps): update accompanist (com.google.accompanist:accompanist-insets, com.google.accompanist:accompanist-systemuicontroller)
  • fix(deps): update dependency androidx.test.espresso:espresso-core to v3.6.1
  • fix(deps): update dependency com.android.tools.build:gradle to v8.6.0
  • fix(deps): update dependency com.facebook.soloader:soloader to v0.11.0
  • fix(deps): update dependency com.github.ben-manes:gradle-versions-plugin to v0.51.0
  • fix(deps): update dependency com.github.mrmike:ok2curl to v0.8.0
  • fix(deps): update dependency com.google.firebase:firebase-bom to v33.2.0
  • fix(deps): update dependency com.squareup.leakcanary:leakcanary-android to v2.14
  • fix(deps): update dependency com.squareup.okhttp3:okhttp to v4.12.0
  • fix(deps): update dependency com.squareup.okio:okio to v3.9.0
  • fix(deps): update dependency com.squareup.retrofit2:retrofit to v2.11.0
  • fix(deps): update dependency io.gitlab.arturbosch.detekt:detekt-gradle-plugin to v1.23.6
  • fix(deps): update dependency io.insert-koin:koin-androidx-compose to v3.5.6
  • fix(deps): update dependency org.jetbrains.kotlinx:kotlinx-coroutines-android to v1.8.1
  • fix(deps): update dependency org.jetbrains.kotlinx:kotlinx-serialization-json to v1.7.2
  • fix(deps): update flipper to v0.264.0 (com.facebook.flipper:flipper-network-plugin, com.facebook.flipper:flipper-leakcanary2-plugin, com.facebook.flipper:flipper)
  • chore(deps): update actions/cache action to v4
  • chore(deps): update actions/checkout action to v4
  • chore(deps): update actions/upload-artifact action to v4
  • fix(deps): update dependency com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter to v1
  • fix(deps): update dependency io.coil-kt:coil to v2
  • fix(deps): update kotlin monorepo to v2 (major) (org.jetbrains.kotlin:kotlin-serialization, org.jetbrains.kotlin:kotlin-stdlib-jdk8)
  • 🔐 Create all rate-limited PRs at once 🔐

Warning

Renovate failed to look up the following dependencies: Failed to look up maven package com.github.xmartlabs.AndroidSwissKnife:swissknife-core.

Files affected: gradle/libs.versions.toml


Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

github-actions
.github/workflows/check_compile.yml
  • actions/checkout v2
  • actions/cache v2
  • actions/setup-java v4
  • actions/upload-artifact v2
  • actions/upload-artifact v2
  • actions/checkout v2
  • actions/cache v2
  • actions/setup-java v4
  • actions/upload-artifact v2
.github/workflows/check_setup_script.yml
  • actions/checkout v2
  • actions/cache v2
gradle
gradle.properties
settings.gradle
build.gradle
app/build.gradle
  • composeOptions 1.5.13
gradle/libs.versions.toml
  • com.github.xmartlabs.AndroidSwissKnife:swissknife-core 44f27ec213
  • com.google.accompanist:accompanist-systemuicontroller 0.20.3
  • com.google.accompanist:accompanist-insets 0.20.3
  • androidx.core:core-splashscreen 1.1.0-rc01
  • androidx.datastore:datastore-preferences 1.1.1
  • androidx.room:room-compiler 2.6.1
  • androidx.room:room-ktx 2.6.1
  • androidx.test.espresso:espresso-core 3.5.1
  • androidx.test.ext:junit 1.1.5
  • io.coil-kt:coil 1.4.0
  • com.squareup.okio:okio 3.4.0
  • com.jonathanfinerty.once:once 1.3.1
  • com.jakewharton.timber:timber 5.0.1
  • androidx.compose.compiler:compiler 1.5.14
  • androidx.constraintlayout:constraintlayout-compose 1.0.1
  • androidx.navigation:navigation-compose 2.7.7
  • androidx.lifecycle:lifecycle-viewmodel-compose 2.8.2
  • com.facebook.flipper:flipper 0.131.1
  • com.facebook.flipper:flipper-leakcanary2-plugin 0.131.1
  • com.facebook.flipper:flipper-network-plugin 0.131.1
  • com.facebook.soloader:soloader 0.10.3
  • com.google.firebase:firebase-bom 33.1.0
  • junit:junit 4.13.2
  • io.insert-koin:koin-androidx-compose 3.1.5
  • org.jetbrains.kotlin:kotlin-stdlib-jdk8 1.9.23
  • org.jetbrains.kotlinx:kotlinx-coroutines-android 1.7.3
  • org.jetbrains.kotlinx:kotlinx-serialization-json 1.3.1
  • com.squareup.leakcanary:leakcanary-android 2.8.1
  • com.squareup.okhttp3:okhttp 4.9.3
  • com.github.mrmike:ok2curl 0.7.0
  • com.squareup.retrofit2:retrofit 2.9.0
  • com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter 0.8.0
  • com.dropbox.mobile.store:store4 4.0.5
  • com.android.tools.build:gradle 8.4.0
  • com.github.ben-manes:gradle-versions-plugin 0.41.0
  • io.gitlab.arturbosch.detekt:detekt-gradle-plugin 1.19.0
  • com.google.firebase:firebase-crashlytics-gradle 3.0.1
  • com.google.gms:google-services 4.4.2
  • org.jetbrains.kotlin:kotlin-serialization 1.9.23
  • com.github.xmartlabs:android-snapshot-publisher 2.4.1
  • com.starter.easylauncher 6.3.0
scripts/dependency_updates.gradle
scripts/read_properties.gradle
scripts/snapshot_publish.gradle
scripts/stop_ship_check_xmls.gradle.kts
scripts/versioning.gradle
gradle-wrapper
gradle/wrapper/gradle-wrapper.properties
  • gradle 8.6

  • Check this box to trigger a request for Renovate to run again on this repository

Action Required: Fix Renovate Configuration

There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.

File: renovate.json
Error type: Invalid JSON (parsing failed)
Message: Syntax error: expecting end of expression or separator near "org.

Available depedency updates are not shown in AS

Android studio doesn't show any hint for available dependency updates e.g. in main-v2

versions.compose = "1.0.0-beta08"
compose.ui = "androidx.compose.ui:ui:$versions.compose"

implementation deps.compose.ui

no hint for available update 1.0.0-rc02 is shown

lint.xml missing?

shouldn't lint.xml be included in repo? when building warning can be seen that lint.xml not found

Setup CI

Gh actions cannot be used due to the paid plan
Alternatives:

  • CircleCi
  • Bitrise
  • Travis

Statusbar color / insets in jetpack compose (main-v2)

Status bar color should be set for app theme ?

https://google.github.io/accompanist/systemuicontroller/

// Remember a SystemUiController
val systemUiController = rememberSystemUiController()
val useDarkIcons = MaterialTheme.colors.isLight

SideEffect {
    // Update all of the system bar colors to be transparent, and use
    // dark icons if we're in light theme
    systemUiController.setSystemBarsColor(
        color = Color.Transparent,
        darkIcons = useDarkIcons
    )

    // setStatusBarsColor() and setNavigationBarsColor() also exist
}

And maybe its worth consideing insets/insets-ui apis in template?

https://google.github.io/accompanist/insets/#inset-aware-layouts-insets-ui
https://google.github.io/accompanist/insets/

https://google.github.io/accompanist/api/insets-ui/insets-ui/com.google.accompanist.insets.ui/

Thanks!

modularization support?

is there any plan for modularization support (refactor template into separate modules)?

Thanks!

Rename master branch

I took the idea from leak canay library.

The branch name master comes from the master / slave terminology. We renamed the default branch to main, a small step towards making the LeakCanary community a safer space. Here’s a good thread on this topic.

I agree on that, maybe we can do the same 😄

AGP upgrade fails

Gradle upgrade wizard is shown but auto upgrade fails.

Works only when changing

buildscript {
    apply from: 'versions.gradle'
    addRepos(repositories)
    dependencies {
        classpath buildscriptDeps.androidGradle
        classpath buildscriptDeps.dependencyUpdates
        classpath buildscriptDeps.detekt
        classpath buildscriptDeps.googleServices
        classpath buildscriptDeps.kotlin
        classpath buildscriptDeps.kotlinSerialization
    }
}

to

buildscript {
    apply from: 'versions.gradle'
    addRepos(repositories)
    dependencies {
        // Keep this here so that AGP auto upgrade works
        classpath 'com.android.tools.build:gradle:7.0.0-rc01'
        classpath buildscriptDeps.dependencyUpdates
        classpath buildscriptDeps.detekt
        classpath buildscriptDeps.googleServices
        classpath buildscriptDeps.kotlin
        classpath buildscriptDeps.kotlinSerialization
    }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.