Skip to content

Commit

Permalink
stocks app
Browse files Browse the repository at this point in the history
  • Loading branch information
tinacious committed Sep 11, 2024
0 parents commit d8f9668
Show file tree
Hide file tree
Showing 101 changed files with 3,230 additions and 0 deletions.
9 changes: 9 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
root = true

[*]
indent_size = 4
indent_style = space
insert_final_newline = true

[*.yml]
indent_size = 2
19 changes: 19 additions & 0 deletions .github/workflows/android.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: Android CI

on:
push:
jobs:
build-test:

runs-on: ubuntu-latest
timeout-minutes: 30

steps:
- uses: actions/checkout@v4
- name: set up JDK 11
uses: actions/setup-java@v4
with:
java-version: 17
distribution: 'temurin'
- name: Build, Lint, Test with Gradle
run: ./gradlew assemble test
54 changes: 54 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: Deploy to Firebase App Tester
on:
push:
branches:
- main

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: set up JDK 17
uses: actions/setup-java@v4
with:
java-version: 17
distribution: 'temurin'

- name: Service account file
env:
FIREBASE_APP_DISTRIBUTION_KEY: "${{secrets.FIREBASE_APP_DISTRIBUTION_KEY}}"
run: |
echo $FIREBASE_APP_DISTRIBUTION_KEY > service_account.json
- name: Build release
run: ./gradlew assembleRelease

# https://github.com/marketplace/actions/sign-android-release
- uses: r0adkll/sign-android-release@v1
name: Sign app APK
# ID used to access action output
id: sign_app
with:
releaseDirectory: "app/build/outputs/apk/release"
signingKeyBase64: ${{ secrets.ANDROID_INTERNAL_SIGNING_KEYSTORE }}
alias: ${{ secrets.ANDROID_INTERNAL_SIGNING_KEY_ALIAS }}
keyStorePassword: ${{ secrets.ANDROID_INTERNAL_SIGNING_STORE_PASSWORD }}
keyPassword: ${{ secrets.ANDROID_INTERNAL_SIGNING_KEY_PASSWORD }}
env:
BUILD_TOOLS_VERSION: "34.0.0"

- name: Upload artifact to Firebase App Distribution
uses: wzieba/Firebase-Distribution-Github-Action@v1
env:
FIREBASE_APP_ID: ${{ secrets.FIREBASE_APP_ID }}
FIREBASE_TEST_TEAM: "anyone"
APP_PATH: ${{steps.sign_app.outputs.signedReleaseFile}}

with:
appId: ${{env.FIREBASE_APP_ID}}
groups: ${{env.FIREBASE_TEST_TEAM}}
serviceCredentialsFile: "service_account.json"
file: ${{env.APP_PATH}}
releaseNotes: "🚀 New build!"
17 changes: 17 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
*.iml
.gradle
/local.properties
/.idea
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
/.idea/inspectionProfiles
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
Empty file added README.md
Empty file.
1 change: 1 addition & 0 deletions app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
119 changes: 119 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.jetbrains.kotlin.android)
kotlin("kapt")
id("com.google.dagger.hilt.android")
id("dagger.hilt.android.plugin")
alias(libs.plugins.kotlinxSerialization)
}

android {
namespace = "com.tinaciousdesign.interviews.stocks"
compileSdk = 34

defaultConfig {
applicationId = "com.tinaciousdesign.interviews.stocks"
minSdk = 29
targetSdk = 34
versionCode = 1
versionName = "1.0"

testInstrumentationRunner = "com.tinaciousdesign.interviews.stocks.HiltTestRunner"
vectorDrawables {
useSupportLibrary = true
}

kotlinOptions {
freeCompilerArgs += arrayOf(
"-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi"
)
}
}

buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
buildFeatures {
buildConfig = true
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.5.1"
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
}
}

dependencies {

implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.activity.compose)
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.ui)
implementation(libs.androidx.ui.graphics)
implementation(libs.androidx.ui.tooling.preview)
implementation(libs.androidx.material3)

// Logging
implementation(libs.timber)
implementation(libs.square.okhttp.logging.interceptor)

// DI
implementation(libs.hilt.android)
kapt(libs.hilt.android.compiler)
kapt(libs.dagger.compiler)
kapt(libs.hilt.compiler)

// Networking
implementation(libs.retrofit)
implementation(libs.retrofit.converter.kotlinx.serialization)
implementation(libs.coil.compose)

// Navigation
implementation(libs.androidx.navigation.compose)
implementation(libs.androidx.hilt.navigation.compose)
implementation(libs.androidx.hilt.navigation.fragment)
implementation(libs.kotlinx.serialization.json)

// Room database
implementation(libs.androidx.room.runtime)
annotationProcessor(libs.androidx.room.compiler)
kapt(libs.androidx.room.compiler)
implementation(libs.androidx.room.ktx)

// WorkManager
implementation(libs.androidx.hilt.work)
implementation(libs.androidx.work.runtime.ktx)

/// Testing
androidTestImplementation(libs.hilt.android.testing)
kaptAndroidTest(libs.hilt.android.compiler)
testImplementation(libs.junit)
testImplementation(libs.mockk)
testImplementation(libs.kotlinx.coroutines.test)
testImplementation(libs.turbine)
androidTestImplementation(libs.turbine)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
androidTestImplementation(platform(libs.androidx.compose.bom))
androidTestImplementation(libs.androidx.ui.test.junit4)
debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest)
}
21 changes: 21 additions & 0 deletions app/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.tinaciousdesign.interviews.stocks

import android.app.Application
import android.content.Context
import androidx.test.runner.AndroidJUnitRunner
import dagger.hilt.android.testing.HiltTestApplication

class HiltTestRunner : AndroidJUnitRunner() {

override fun newApplication(cl: ClassLoader?, className: String?, context: Context?): Application {
return super.newApplication(cl, HiltTestApplication::class.java.name, context)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package com.tinaciousdesign.interviews.stocks

import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.ui.Modifier
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performTextInput
import androidx.compose.ui.unit.dp
import androidx.navigation.compose.rememberNavController
import com.tinaciousdesign.interviews.stocks.di.AppModule
import com.tinaciousdesign.interviews.stocks.navigation.BottomNavigationBar
import com.tinaciousdesign.interviews.stocks.navigation.NavigationRouter
import com.tinaciousdesign.interviews.stocks.ui.TestTags
import com.tinaciousdesign.interviews.stocks.ui.theme.StocksTheme
import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
import dagger.hilt.android.testing.UninstallModules
import org.junit.Before
import org.junit.Rule
import org.junit.Test


@HiltAndroidTest
@UninstallModules(AppModule::class)
class StockSearchBehaviourTest {
@get:Rule(order = 0)
val hiltRule = HiltAndroidRule(this)

@get:Rule(order = 1)
val composeRule = createAndroidComposeRule<MainActivity>()

@Before
fun setUp() {
hiltRule.inject()

composeRule.activity.setContent {
StocksTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
val navController = rememberNavController()

Scaffold(
modifier = Modifier.fillMaxSize(),
bottomBar = { BottomNavigationBar(navController = navController) }
) { innerPadding ->
Box(
modifier = Modifier.padding(
PaddingValues(
0.dp,
0.dp,
0.dp,
innerPadding.calculateBottomPadding()
)
)
) {
NavigationRouter(navController)
}
}
}
}
}
}

@Test
fun userCanSearchForStocks() {
with(composeRule) {
composeRule.onNodeWithText("Use the search field above to find stocks by ticker or by name").assertIsDisplayed()

composeRule
.onNodeWithTag(TestTags.searchField)
.performTextInput("ow")

waitForText("POWL")

textIsDisplayed("POWL")
textIsDisplayed("Omni Resources")

textIsDisplayed("FVOW")
textIsDisplayed("Harmony Enterprises")
}
}
}
Loading

0 comments on commit d8f9668

Please sign in to comment.