Skip to content

Commit 3c285d3

Browse files
Merge pull request #6 from MoscowSquad/feature/cli
prepare clothes-suggester ui
2 parents 9311980 + ab3b865 commit 3c285d3

27 files changed

+867
-213
lines changed

build.gradle.kts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ dependencies {
1717
implementation("io.arrow-kt:arrow-core:2.0.1")
1818
implementation("io.arrow-kt:arrow-fx-coroutines:2.0.1")
1919
implementation("io.insert-koin:koin-core:4.0.2")
20-
implementation("com.github.doyaaaaaken:kotlin-csv-jvm:1.9.0")
2120
testImplementation("org.jetbrains.kotlin:kotlin-test")
2221
testImplementation("org.junit.jupiter:junit-jupiter-api:5.12.0-M1")
2322
testImplementation("io.mockk:mockk:1.13.16")
@@ -37,8 +36,7 @@ dependencies {
3736
implementation("io.ktor:ktor-client-content-negotiation:$ktor_version")
3837
implementation("io.ktor:ktor-serialization-kotlinx-json:$ktor_version")
3938
implementation(kotlin("stdlib-jdk8"))
40-
41-
39+
implementation("org.json:json:20210307")
4240
}
4341

4442
tasks.test {

src/main/kotlin/Main.kt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import di.presentationModule
2+
import di.repositoryModule
3+
import di.useCaseModule
4+
import kotlinx.coroutines.*
5+
import org.koin.core.context.startKoin
6+
import org.koin.core.context.stopKoin
7+
import org.koin.mp.KoinPlatform.getKoin
8+
import presentation.ClothesSuggesterConsoleUI
9+
10+
fun main() {
11+
var exit = true
12+
GlobalScope.launch {
13+
startKoin {
14+
modules(repositoryModule, useCaseModule, presentationModule)
15+
}
16+
17+
val mainUi: ClothesSuggesterConsoleUI = getKoin().get()
18+
mainUi.start()
19+
mainUi.uiFlow.collect {
20+
exit = true
21+
stopKoin()
22+
}
23+
}
24+
runBlocking {
25+
while (exit) {
26+
delay(1000)
27+
}
28+
}
29+
}

src/main/kotlin/data/repository/LocationRepositoryImpl.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import domain.models.Location
44
import domain.repository.LocationRepository
55
import domain.util.location_getter.LocationFetcher
66

7-
class LocationRepositoryImpl(private val locationFetcher: LocationFetcher) : LocationRepository {
8-
override suspend fun getLocation(): Location {
7+
class LocationRepositoryImpl() : LocationRepository {
8+
override suspend fun getLocation(locationFetcher: LocationFetcher): Location {
99
return locationFetcher.getLocation()
1010
}
1111
}
Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,43 @@
11
package data.repository
22

3-
import WeatherRepository
43
import domain.models.CurrentWeather
5-
import domain.models.exceptions.FailedFetchWeatherDataException
4+
import domain.models.FailedFetchWeatherDataException
5+
import domain.models.NoLocationRetrieved
6+
import domain.repository.WeatherRepository
67
import io.ktor.client.*
7-
import io.ktor.client.call.*
88
import io.ktor.client.request.*
99
import io.ktor.client.statement.*
1010
import io.ktor.http.*
11+
import kotlinx.serialization.json.Json
12+
import org.json.JSONObject
1113

1214
const val OPEN_METO_API = "https://api.open-meteo.com/v1/forecast"
1315

1416
class WeatherRepositoryImpl(private val httpClient: HttpClient) : WeatherRepository {
1517
override suspend fun getCurrentWeather(latitude: Double, longitude: Double): CurrentWeather {
16-
val response: HttpResponse = httpClient.get(OPEN_METO_API) {
18+
val httpResponse: HttpResponse = httpClient.get(OPEN_METO_API) {
1719
parameter("latitude", latitude)
1820
parameter("longitude", longitude)
1921
parameter(
2022
"current",
21-
"temperature_2m,relative_humidity_2m,apparent_temperature,is_day,wind_speed_10m,snowfall,rain,weather_code,cloud_cover"
23+
"temperature_2m,relative_humidity_2m,apparent_temperature,is_day,rain,showers,snowfall,wind_speed_10m,cloud_cover"
2224
)
2325
}
2426

25-
if (!response.status.isSuccess()) {
27+
if (httpResponse.status != HttpStatusCode.OK) {
2628
throw FailedFetchWeatherDataException(
27-
"Weather API returned error status: ${response.status}"
29+
"Weather API returned error status: ${httpResponse.status}"
2830
)
2931
}
3032

31-
return response.body()
33+
try {
34+
val response = JSONObject(httpResponse.bodyAsText()).get("current").toString()
35+
val json = Json {
36+
ignoreUnknownKeys = true
37+
}
38+
return json.decodeFromString<CurrentWeather>(response)
39+
} catch (e: Exception) {
40+
throw NoLocationRetrieved()
41+
}
3242
}
3343
}

src/main/kotlin/data/util/location_getter/CurrentLocationFetcher.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ import io.ktor.client.*
77
import io.ktor.client.request.*
88
import io.ktor.client.statement.*
99
import io.ktor.http.*
10-
import kotlinx.serialization.decodeFromString
1110
import kotlinx.serialization.json.Json
1211

1312
const val IP_API_URL = "http://ip-api.com/json"
13+
1414
class CurrentLocationFetcher(private val httpClient: HttpClient) : LocationFetcher {
1515
override suspend fun getLocation(): Location {
1616
val httpResponse = httpClient.get(IP_API_URL)

src/main/kotlin/data/util/location_getter/NamedLocationFetcher.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import io.ktor.client.*
77
import io.ktor.client.request.*
88
import io.ktor.client.statement.*
99
import io.ktor.http.*
10-
import kotlinx.serialization.decodeFromString
1110
import kotlinx.serialization.json.Json
11+
import org.json.JSONObject
1212

1313
const val POSITION_STACK_URL = "https://positionstack.com/geo_api.php?query=%s"
1414

@@ -19,7 +19,7 @@ class NamedLocationFetcher(private val placeName: String, private val httpClient
1919
throw NoLocationRetrieved()
2020

2121
try {
22-
val response = httpResponse.bodyAsText()
22+
val response = JSONObject(httpResponse.bodyAsText()).getJSONArray("data")[0].toString()
2323
val json = Json {
2424
ignoreUnknownKeys = true
2525
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package di
2+
3+
import org.koin.dsl.module
4+
import presentation.ClothesSuggesterConsoleUI
5+
import presentation.io.ConsoleIO
6+
import presentation.io.ConsoleIOImpl
7+
import java.util.*
8+
9+
val presentationModule = module {
10+
single { Scanner(System.`in`) }
11+
single<ConsoleIO> { ConsoleIOImpl(get()) }
12+
13+
// Authentication UI
14+
single { ClothesSuggesterConsoleUI(get(), get(), get(), get(), get()) }
15+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package di
2+
3+
import data.repository.LocationRepositoryImpl
4+
import data.repository.WeatherRepositoryImpl
5+
import domain.repository.LocationRepository
6+
import domain.repository.WeatherRepository
7+
import io.ktor.client.*
8+
import io.ktor.client.engine.cio.*
9+
import org.koin.dsl.module
10+
11+
val repositoryModule = module {
12+
single { HttpClient(CIO) }
13+
single<LocationRepository> { LocationRepositoryImpl() }
14+
single<WeatherRepository> { WeatherRepositoryImpl(get()) }
15+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package di
2+
3+
import domain.use_cases.GetCurrentWeatherUseCase
4+
import domain.use_cases.GetLocationUseCase
5+
import domain.use_cases.SuggestClothesBasedOnWeatherUseCase
6+
import org.koin.dsl.module
7+
8+
val useCaseModule = module {
9+
single { GetCurrentWeatherUseCase(get()) }
10+
single { GetLocationUseCase() }
11+
single { SuggestClothesBasedOnWeatherUseCase() }
12+
}

src/main/kotlin/domain/models/exceptions.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,7 @@ import io.ktor.utils.io.errors.*
44

55
class NoLocationRetrieved(message: String = "No location retrieved") : IOException(message)
66

7-
class ErrorOnRetrieveLocation(message: String) : IOException(message)
7+
class FailedFetchWeatherDataException(
8+
message: String,
9+
cause: Throwable? = null
10+
) : Exception(message, cause)

0 commit comments

Comments
 (0)