Skip to content
This repository was archived by the owner on Jun 6, 2025. It is now read-only.

Commit ee802f6

Browse files
[v1.0.2] Upgrade version to 1.0.2(#3)
1 parent 73864f1 commit ee802f6

33 files changed

+600
-197
lines changed

.github/pull_request_template.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
## ✏️ TODO
2+
*(List your doing in your pull request here)*
3+
4+
- Feature one.
5+
- Feature two.
6+
7+
## 📘 Libraries
8+
*(List your libraries that you add or modifier in your pull request)*
9+
10+
- Jetpack Compose.
11+
- Jetpack DataStore.
12+
13+
## 🔔 Notes
14+
*(You must provides some information such as how to testing your pull request because this is important for your reviewer to check your pull request)*
15+
16+
- Delete the project because it's suck. :smile:
17+
18+
## 📷 Screenshots
19+
*(Add some screenshots in here)*

.idea/deploymentTargetDropDown.xml

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/gradle.xml

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ I want to say thanks for those people to help me to make this app.
1313

1414
## :hammer: How to build app
1515

16-
- Using android 13 and above to build app.
1716
- Using the newest version of Android Studio Canary.
1817
- You must add `BASE_URL`, `API_KEY` and `MAPS_API_KEY` inside `local.properties` to build and run Weapose app, like the code below:
1918

@@ -51,6 +50,12 @@ Weapose is built according to the Clean Architecture model combined with the MVV
5150
- Guild to app architecture by Google Android.
5251
- Clean architectur by Uncle Bob.
5352

53+
## :mag_right: Unit test
54+
55+
- Using [MockK](https://mockk.io/) to write unit test.
56+
- Using [Kotlin Reflection](https://kotlinlang.org/docs/reflection.html) to access the private method, private property, etc.
57+
- Using [Kotlin Kover](https://github.com/Kotlin/kotlinx-kover) to generate the test coverage. To generate, you just run command ` ./gradlew koverHtmlReport`.
58+
5459
## :tram: Data flow
5560

5661
Weapose is supported by `Flow` and `suspend` for data stream flow in app.

app/build.gradle.kts

Lines changed: 58 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,48 @@ plugins {
66
kotlin("kapt")
77
id("dagger.hilt.android.plugin")
88
id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin")
9+
id("org.jetbrains.kotlinx.kover") version "0.5.0"
910
}
1011

1112
val properties = Properties().apply {
1213
load(project.rootProject.file("local.properties").inputStream())
1314
}
1415

16+
project.afterEvaluate {
17+
tasks.koverHtmlReport {
18+
group = "kover"
19+
description = ""
20+
dependsOn("testDebugUnitTest")
21+
22+
isEnabled = true
23+
htmlReportDir.set(layout.buildDirectory.dir("kover_report/html_result"))
24+
includes = listOf("com.minhdtm.example.weapose.*")
25+
excludes = listOf(
26+
"*Screen*",
27+
"*_Factory*",
28+
"*_HiltModules*",
29+
"*di*",
30+
"*_Impl*",
31+
"*BuildConfig*",
32+
"*Activity*",
33+
"*App*",
34+
"*Drawer*",
35+
"*Graph*",
36+
"*.theme*",
37+
)
38+
}
39+
}
40+
1541
android {
1642
namespace = "com.minhdtm.example.weapose"
17-
compileSdkPreview = "Tiramisu"
43+
compileSdk = 33
1844

1945
defaultConfig {
2046
applicationId = "com.minhdtm.example.weapose"
2147
minSdk = 21
22-
targetSdkPreview = "Tiramisu"
48+
targetSdk = 33
2349
versionCode = 1
24-
versionName = "1.0.1"
50+
versionName = "1.0.2"
2551

2652
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
2753
vectorDrawables {
@@ -39,6 +65,12 @@ android {
3965
}
4066
}
4167

68+
testOptions {
69+
unitTests {
70+
isIncludeAndroidResources = true
71+
}
72+
}
73+
4274
compileOptions {
4375
sourceCompatibility = JavaVersion.VERSION_11
4476
targetCompatibility = JavaVersion.VERSION_11
@@ -48,6 +80,7 @@ android {
4880
jvmTarget = "11"
4981
freeCompilerArgs = freeCompilerArgs.toMutableList().apply {
5082
add("-opt-in=kotlin.RequiresOptIn")
83+
add("-Xuse-experimental=androidx.compose.ui.text.ExperimentalTextApi")
5184
}
5285
}
5386

@@ -67,13 +100,13 @@ android {
67100
}
68101

69102
dependencies {
70-
implementation("androidx.core:core-ktx:1.7.0")
71-
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.4.1")
72-
implementation("androidx.activity:activity-compose:1.4.0")
73-
implementation("androidx.compose.ui:ui:1.1.1")
74-
implementation("androidx.compose.ui:ui-tooling-preview:1.1.1")
75-
implementation("androidx.compose.material3:material3:1.0.0-alpha12")
76-
implementation("androidx.compose.material:material:1.2.0-beta03")
103+
implementation("androidx.core:core-ktx:1.8.0")
104+
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.5.0")
105+
implementation("androidx.activity:activity-compose:1.5.0")
106+
implementation("androidx.compose.ui:ui:1.3.0-alpha01")
107+
implementation("androidx.compose.ui:ui-tooling-preview:1.3.0-alpha01")
108+
implementation("androidx.compose.material3:material3:1.0.0-alpha14")
109+
implementation("androidx.compose.material:material:1.3.0-alpha01")
77110

78111
// Google accompanist
79112
implementation("com.google.accompanist:accompanist-navigation-animation:0.24.9-beta")
@@ -83,7 +116,7 @@ dependencies {
83116
implementation("com.google.accompanist:accompanist-flowlayout:0.24.9-beta")
84117

85118
// Google play services
86-
implementation("com.google.android.gms:play-services-location:19.0.1")
119+
implementation("com.google.android.gms:play-services-location:20.0.0")
87120
implementation("com.google.android.gms:play-services-maps:18.0.2")
88121
implementation("com.google.android.libraries.places:places:2.6.0")
89122
implementation("com.google.maps.android:maps-compose:2.1.1")
@@ -112,12 +145,14 @@ dependencies {
112145
kapt("com.google.dagger:hilt-android-compiler:2.40")
113146

114147
// Navigation
115-
implementation("androidx.navigation:navigation-compose:2.4.2")
148+
implementation("androidx.navigation:navigation-compose:2.5.0")
116149

117150
// ViewModel
118-
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0-rc01")
119-
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.5.0-rc01")
151+
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.0-alpha01")
152+
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.0-alpha01")
120153

154+
// LiveData
155+
implementation("androidx.compose.runtime:runtime-livedata:1.3.0-alpha01")
121156
// Gson
122157
implementation("com.google.code.gson:gson:2.9.0")
123158

@@ -127,13 +162,20 @@ dependencies {
127162
// DataStore
128163
implementation("androidx.datastore:datastore-preferences:1.0.0")
129164

165+
// Kotlin reflect
166+
implementation("org.jetbrains.kotlin:kotlin-reflect:1.7.0")
167+
130168
testImplementation("junit:junit:4.13.2")
131169
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.1")
132170

171+
// MockK
172+
testImplementation("io.mockk:mockk:1.12.4")
173+
testImplementation("io.mockk:mockk-agent-jvm:1.12.4")
174+
133175
androidTestImplementation("androidx.test.ext:junit:1.1.3")
134176
androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0")
135177
androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.1.1")
136178

137-
debugImplementation("androidx.compose.ui:ui-tooling:1.1.1")
138-
debugImplementation("androidx.compose.ui:ui-test-manifest:1.1.1")
179+
debugImplementation("androidx.compose.ui:ui-tooling:1.3.0-alpha01")
180+
debugImplementation("androidx.compose.ui:ui-test-manifest:1.3.0-alpha01")
139181
}

app/src/main/java/com/minhdtm/example/weapose/data/model/CurrentWeather.kt

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ import com.google.gson.annotations.SerializedName
55
data class CurrentWeather(
66
@SerializedName("id") val id: Int? = 0,
77
@SerializedName("name") val name: String? = "",
8-
@SerializedName("cod") val cod: Int,
9-
@SerializedName("coord") val coord: Coord,
10-
@SerializedName("weather") val weatherItems: List<Weather>,
8+
@SerializedName("cod") val cod: Int? = 0,
9+
@SerializedName("coord") val coord: Coord? = null,
10+
@SerializedName("weather") val weatherItems: List<Weather>? = emptyList(),
1111
@SerializedName("base") val base: String? = "",
12-
@SerializedName("main") val main: Main,
13-
@SerializedName("visibility") val visibility: Int,
14-
@SerializedName("wind") val wind: Wind,
15-
@SerializedName("clouds") val clouds: Cloud,
16-
@SerializedName("dt") val dt: Long,
17-
@SerializedName("sys") val sys: Sys,
18-
@SerializedName("timezone") val timezone: Int
12+
@SerializedName("main") val main: Main? = null,
13+
@SerializedName("visibility") val visibility: Int? = 0,
14+
@SerializedName("wind") val wind: Wind? = null,
15+
@SerializedName("clouds") val clouds: Cloud? = null,
16+
@SerializedName("dt") val dt: Long? = 0L,
17+
@SerializedName("sys") val sys: Sys? = null,
18+
@SerializedName("timezone") val timezone: Int? = null
1919
) : Model()

app/src/main/java/com/minhdtm/example/weapose/data/repositories/LocationRepositoryImpl.kt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@ import android.content.Context
55
import android.location.Address
66
import android.location.Geocoder
77
import android.os.Build
8-
import androidx.compose.ui.text.intl.Locale
9-
import com.google.android.gms.location.LocationRequest
108
import com.google.android.gms.location.LocationServices
9+
import com.google.android.gms.location.Priority
1110
import com.google.android.gms.maps.model.LatLng
1211
import com.google.android.gms.tasks.CancellationTokenSource
1312
import com.google.android.libraries.places.api.model.AutocompletePrediction
@@ -25,7 +24,6 @@ import kotlinx.coroutines.flow.flatMapConcat
2524
import kotlinx.coroutines.flow.flow
2625
import kotlinx.coroutines.suspendCancellableCoroutine
2726
import timber.log.Timber
28-
import java.util.*
2927
import javax.inject.Inject
3028
import kotlin.coroutines.resume
3129
import kotlin.coroutines.resumeWithException
@@ -45,7 +43,7 @@ class LocationRepositoryImpl @Inject constructor(
4543
val cancellationTokenSource = CancellationTokenSource()
4644

4745
fusedLocationProviderClient.getCurrentLocation(
48-
LocationRequest.PRIORITY_HIGH_ACCURACY,
46+
Priority.PRIORITY_HIGH_ACCURACY,
4947
cancellationTokenSource.token,
5048
).addOnSuccessListener { location ->
5149
if (location != null) {

app/src/main/java/com/minhdtm/example/weapose/presentation/base/Event.kt

Lines changed: 0 additions & 3 deletions
This file was deleted.

app/src/main/java/com/minhdtm/example/weapose/presentation/model/CurrentWeatherViewData.kt

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package com.minhdtm.example.weapose.presentation.model
22

33
import androidx.compose.ui.text.capitalize
44
import androidx.compose.ui.text.intl.Locale
5-
import androidx.compose.ui.text.toUpperCase
65
import com.minhdtm.example.weapose.data.model.CurrentWeather
76
import com.minhdtm.example.weapose.presentation.utils.Constants
87
import com.minhdtm.example.weapose.presentation.utils.toBackground
@@ -28,14 +27,14 @@ class CurrentWeatherMapper @Inject constructor() : DataModelMapper<CurrentWeathe
2827

2928
override fun mapToViewData(model: CurrentWeather): CurrentWeatherViewData {
3029
val city = model.name?.uppercase() ?: ""
31-
val maxTemp = model.main.tempMax?.toString() ?: ""
32-
val minTemp = model.main.tempMin?.toString() ?: ""
33-
val temp = model.main.temp?.toString() ?: ""
34-
val weather = model.weatherItems.firstOrNull()?.description?.capitalize(Locale.current) ?: ""
35-
val sunRise = model.sys.sunrise?.toDateTime(Constants.DateFormat.HH_mm, model.timezone) ?: ""
36-
val wind = model.wind.speed?.toString() ?: ""
37-
val humidity = model.main.humidity?.toString() ?: ""
38-
val background = (model.weatherItems.firstOrNull()?.icon ?: "").toBackground()
30+
val maxTemp = model.main?.tempMax?.toString() ?: ""
31+
val minTemp = model.main?.tempMin?.toString() ?: ""
32+
val temp = model.main?.temp?.toString() ?: ""
33+
val weather = model.weatherItems?.firstOrNull()?.description?.capitalize(Locale.current) ?: ""
34+
val sunRise = model.sys?.sunrise?.toDateTime(Constants.DateFormat.HH_mm, model.timezone) ?: ""
35+
val wind = model.wind?.speed?.toString() ?: ""
36+
val humidity = model.main?.humidity?.toString() ?: ""
37+
val background = (model.weatherItems?.firstOrNull()?.icon ?: "").toBackground()
3938

4039
return CurrentWeatherViewData(
4140
city = city,
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.minhdtm.example.weapose.presentation.model.factory
2+
3+
import com.minhdtm.example.weapose.R
4+
import com.minhdtm.example.weapose.presentation.model.DayWeatherViewData
5+
6+
fun previewDayWeatherViewData() = DayWeatherViewData(
7+
dateTime = "Saturday, Jan 1",
8+
weatherDetail = "Rain",
9+
icon = R.drawable.ic_rain,
10+
maxTemp = 40.0,
11+
minTemp = 30.0,
12+
humidity = 80,
13+
sunset = "06:00",
14+
sunrise = "17:00",
15+
uvIndex = 8.0,
16+
windSpeed = "10",
17+
)

0 commit comments

Comments
 (0)