Skip to content

Commit

Permalink
-2nd Screen Finished (i think, API acces died for today, gotta wait t…
Browse files Browse the repository at this point in the history
…ill tomorrow)

-a test is failing on purpose for checking out the Unit Testing CI
  • Loading branch information
LeonelZalegas committed Jul 24, 2024
1 parent 094e75a commit 0d797fc
Show file tree
Hide file tree
Showing 24 changed files with 559 additions and 69 deletions.
18 changes: 17 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ android {

defaultConfig {
applicationId = "com.example.stockmarketcheck"
minSdk = 24
minSdk = 26
targetSdk = 34
versionCode = 1
versionName = "1.0"
Expand Down Expand Up @@ -114,13 +114,26 @@ dependencies {
implementation(libs.androidx.ui.tooling.preview)
implementation(libs.androidx.material3)
testImplementation(libs.junit)
testImplementation(libs.junit.jupiter)
testImplementation(libs.junit.jupiter)
testImplementation(libs.junit.jupiter)
testImplementation(libs.junit.jupiter)
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)

// MockK
testImplementation(libs.mockk.mockk)

// Turbine (testing flows)
testImplementation(libs.turbine)

// Coroutines Test
testImplementation(libs.jetbrains.kotlinx.coroutines.test)

// Type-Safe Navigation with the OFFICIAL Compose Navigation Library
implementation(libs.navigation.compose)
implementation(libs.kotlinx.serialization.json)
Expand Down Expand Up @@ -159,4 +172,7 @@ dependencies {

// System Bar control
implementation(libs.accompanist.systemuicontroller)

// Graph creation
implementation(libs.ycharts)
}
4 changes: 2 additions & 2 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<uses-permission android:name="android.permission.INTERNET"/>

<application
android:name=".StockApplication"
android:name=".core.StockApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
Expand All @@ -16,7 +16,7 @@
android:theme="@style/Theme.StockMarketCheck"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:name=".core.MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.StockMarketCheck">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.example.stockmarketcheck
package com.example.stockmarketcheck.core

import android.os.Bundle
import androidx.activity.ComponentActivity
Expand All @@ -9,7 +9,7 @@ import androidx.compose.material3.Surface
import androidx.compose.runtime.SideEffect
import androidx.compose.ui.graphics.Color
import androidx.navigation.compose.rememberNavController
import com.example.stockmarketcheck.mainFeature.presentation.navigation.AppNavHost
import com.example.stockmarketcheck.core.navigation.AppNavHost
import com.example.stockmarketcheck.ui.theme.StockMarketCheckTheme
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import dagger.hilt.android.AndroidEntryPoint
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.example.stockmarketcheck
package com.example.stockmarketcheck.core

import android.app.Application
import dagger.hilt.android.HiltAndroidApp
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.example.stockmarketcheck.di
package com.example.stockmarketcheck.core.di

import android.app.Application
import androidx.room.Room
Expand All @@ -13,6 +13,7 @@ import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.create
import javax.inject.Singleton

// Damos por sentado que utilizaremos Room y Retrofit (con el mismo Base URL) en otras features
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.example.stockmarketcheck.core.navigation

import androidx.compose.runtime.Composable
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.toRoute
import com.example.stockmarketcheck.mainFeature.presentation.company_info.CompanyInfoScreen
import com.example.stockmarketcheck.mainFeature.presentation.company_listings.CompanyListingsScreen

// https://www.notion.so/StockMarket-app-fd555472e30c45ef8586565dc35d7d42?pvs=4#374709ebbc634c2abbaa464580d829c3
@Composable
fun AppNavHost(navController: NavHostController) {
NavHost(navController, startDestination = CompanyListings::class) {
composable<CompanyListings> {
CompanyListingsScreen(navController = navController)
}
composable<CompanyInfo> { backStackEntry ->
val screenBArgs: CompanyInfo = backStackEntry.toRoute()
CompanyInfoScreen(screenBArgs.symbol)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.example.stockmarketcheck.core.navigation

import kotlinx.serialization.Serializable

@Serializable
object CompanyListings

@Serializable
data class CompanyInfo(val symbol: String)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.example.stockmarketcheck.util
package com.example.stockmarketcheck.core.util

sealed class Resource<T>(val data: T? = null, val message: String? = null) {
class Success<T>(data: T?) : Resource<T>(data)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package com.example.stockmarketcheck.mainFeature.data.csv

import android.os.Build
import androidx.annotation.RequiresApi
import com.example.stockmarketcheck.mainFeature.domain.model.IntradayInfo
import com.opencsv.CSVReader
import kotlinx.coroutines.Dispatchers
Expand All @@ -19,7 +17,6 @@ import javax.inject.Singleton
class IntradayInfoParser
@Inject
constructor() : CSVParser<IntradayInfo> {
@RequiresApi(Build.VERSION_CODES.O)
override suspend fun parse(stream: InputStream): List<IntradayInfo> {
val csvReader = CSVReader(InputStreamReader(stream))
return withContext(Dispatchers.IO) {
Expand All @@ -35,7 +32,7 @@ class IntradayInfoParser
)
} // Aca ya tenemos la lista de IntradayInfo pero a esto filtramos y Guardamos solo
.filter { // los IntradayInfo con campo date = a la fecha de ayer de nuetra maquina
it.date.dayOfMonth == LocalDate.now().minusDays(4).dayOfMonth
it.date.dayOfMonth == LocalDate.now().minusDays(1).dayOfMonth
}
.sortedBy {
it.date.hour
Expand All @@ -46,7 +43,6 @@ class IntradayInfoParser
}
}

@RequiresApi(Build.VERSION_CODES.O)
private fun convertToLocalDateTime(timestamp: String): LocalDateTime {
val pattern = "yyyy-MM-dd HH:mm:ss"
val formatter = DateTimeFormatter.ofPattern(pattern, Locale.getDefault())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.example.stockmarketcheck.mainFeature.data.repository

import com.example.stockmarketcheck.core.util.Resource
import com.example.stockmarketcheck.mainFeature.data.csv.CSVParser
import com.example.stockmarketcheck.mainFeature.data.local.StockDatabase
import com.example.stockmarketcheck.mainFeature.data.mapper.toCompanyInfo
Expand All @@ -10,7 +11,6 @@ import com.example.stockmarketcheck.mainFeature.domain.model.CompanyInfo
import com.example.stockmarketcheck.mainFeature.domain.model.CompanyListing
import com.example.stockmarketcheck.mainFeature.domain.model.IntradayInfo
import com.example.stockmarketcheck.mainFeature.domain.repository.StockRepository
import com.example.stockmarketcheck.util.Resource
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import retrofit2.HttpException
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.example.stockmarketcheck.di
package com.example.stockmarketcheck.mainFeature.di

import com.example.stockmarketcheck.mainFeature.data.csv.CSVParser
import com.example.stockmarketcheck.mainFeature.data.csv.CompanyListingsParser
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package com.example.stockmarketcheck.mainFeature.domain.model

data class CompanyInfo(
val symbol: String?,
val description: String?,
val name: String?,
val country: String?,
val industry: String?,
val symbol: String,
val description: String,
val name: String,
val country: String,
val industry: String,
)
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package com.example.stockmarketcheck.mainFeature.domain.repository

import com.example.stockmarketcheck.core.util.Resource
import com.example.stockmarketcheck.mainFeature.domain.model.CompanyInfo
import com.example.stockmarketcheck.mainFeature.domain.model.CompanyListing
import com.example.stockmarketcheck.mainFeature.domain.model.IntradayInfo
import com.example.stockmarketcheck.util.Resource
import kotlinx.coroutines.flow.Flow

interface StockRepository {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
package com.example.stockmarketcheck.mainFeature.presentation.company_info

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.asPaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.layout.width
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Alignment.Companion.Center
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.zIndex
import androidx.hilt.navigation.compose.hiltViewModel
import com.example.stockmarketcheck.ui.theme.DarkBlue

@Composable
fun CompanyInfoScreen(
symbol: String,
viewModel: CompanyInfoViewModel = hiltViewModel(),
) {
val state = viewModel.state
val systemBarsPadding = WindowInsets.systemBars.asPaddingValues()

if (state.error == null) {
Column(
modifier =
Modifier
.fillMaxSize()
.background(DarkBlue)
.padding(top = systemBarsPadding.calculateTopPadding()),
) {
state.company?.let { company ->
Text(
text = company.name,
fontWeight = FontWeight.Bold,
fontSize = 18.sp,
overflow = TextOverflow.Ellipsis,
modifier =
Modifier
.fillMaxWidth()
.padding(start = 5.dp),
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = company.symbol,
fontStyle = FontStyle.Italic,
fontSize = 14.sp,
modifier =
Modifier
.fillMaxWidth()
.padding(start = 5.dp),
)
Spacer(modifier = Modifier.height(8.dp))
HorizontalDivider(
modifier =
Modifier
.fillMaxWidth(),
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = "Industry: ${company.industry}",
fontSize = 14.sp,
modifier =
Modifier
.fillMaxWidth()
.padding(start = 5.dp),
overflow = TextOverflow.Ellipsis,
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = "Country: ${company.country}",
fontSize = 14.sp,
modifier =
Modifier
.fillMaxWidth()
.padding(start = 5.dp),
overflow = TextOverflow.Ellipsis,
)
Spacer(modifier = Modifier.height(8.dp))
HorizontalDivider(
modifier =
Modifier
.fillMaxWidth(),
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = company.description,
fontSize = 12.sp,
modifier =
Modifier
.fillMaxWidth()
.padding(start = 5.dp),
)
if (state.stockIntradayInfos.isNotEmpty()) {
Spacer(modifier = Modifier.height(16.dp))
Text(text = "Market Summary")
Spacer(modifier = Modifier.height(32.dp))

Box(
modifier =
Modifier
.fillMaxWidth()
.height(300.dp),
) {
IntradayInfoChart(
infos = state.stockIntradayInfos,
modifier =
Modifier
.fillMaxWidth()
.height(300.dp),
)
Box(
modifier =
Modifier
.height(300.dp)
.width(20.dp)
.background(DarkBlue)
.align(Alignment.CenterEnd)
.offset(x = (-20).dp)
.zIndex(1f),
)
}
}
}
}
}
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Center,
) {
if (state.isLoading) {
CircularProgressIndicator()
} else if (state.error != null) {
Text(
text = state.error,
color = MaterialTheme.colorScheme.error,
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import androidx.compose.runtime.setValue
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.stockmarketcheck.core.util.Resource
import com.example.stockmarketcheck.mainFeature.domain.repository.StockRepository
import com.example.stockmarketcheck.util.Resource
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
Expand All @@ -21,7 +21,7 @@ class CompanyInfoViewModel
private val savedStateHandle: SavedStateHandle,
private val repository: StockRepository,
) : ViewModel() {
private var state by mutableStateOf(CompanyInfoState())
var state by mutableStateOf(CompanyInfoState())

init {
viewModelScope.launch {
Expand Down
Loading

0 comments on commit 0d797fc

Please sign in to comment.