mirror of
https://github.com/sudoxnym/habitica-android.git
synced 2026-04-14 19:56:32 +00:00
Improve tests
This commit is contained in:
parent
afb2b234d9
commit
18796e1f8a
40 changed files with 337 additions and 90 deletions
|
|
@ -58,12 +58,12 @@ dependencies {
|
|||
implementation "com.amplitude:analytics-android:$amplitude_version"
|
||||
|
||||
//Tests
|
||||
testImplementation 'io.kotest:kotest-runner-junit5:5.5.5'
|
||||
testImplementation 'androidx.test:core:1.5.0'
|
||||
testImplementation 'io.mockk:mockk:1.13.4'
|
||||
testImplementation 'io.mockk:mockk-android:1.13.4'
|
||||
testImplementation 'io.kotest:kotest-assertions-core:5.5.5'
|
||||
testImplementation 'io.kotest:kotest-framework-datatest:5.5.5'
|
||||
testImplementation "io.mockk:mockk:$mockk_version"
|
||||
testImplementation "io.mockk:mockk-android:$mockk_version"
|
||||
testImplementation "io.kotest:kotest-runner-junit5:$kotest_version"
|
||||
testImplementation "io.kotest:kotest-assertions-core:$kotest_version"
|
||||
testImplementation "io.kotest:kotest-framework-datatest:$kotest_version"
|
||||
androidTestImplementation ('com.kaspersky.android-components:kaspresso:1.5.1') {
|
||||
exclude module: "protobuf-lite"
|
||||
}
|
||||
|
|
@ -74,8 +74,8 @@ dependencies {
|
|||
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
|
||||
androidTestImplementation 'androidx.test:core-ktx:1.5.0'
|
||||
androidTestImplementation 'androidx.test.ext:junit-ktx:1.1.5'
|
||||
androidTestImplementation 'io.mockk:mockk-android:1.13.4'
|
||||
androidTestImplementation 'io.kotest:kotest-assertions-core:5.5.5'
|
||||
androidTestImplementation "io.mockk:mockk-android:$mockk_version"
|
||||
androidTestImplementation "io.kotest:kotest-assertions-core:$kotest_version"
|
||||
androidTestUtil("androidx.test:orchestrator:1.4.2")
|
||||
|
||||
implementation 'com.facebook.shimmer:shimmer:0.5.0'
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ open class SubscriptionPlan : RealmObject(), BaseObject {
|
|||
val monthsUntilNextHourglass: Int
|
||||
get() {
|
||||
return if (subMonthCount > 0) {
|
||||
(consecutive?.offset ?: 0) + 1
|
||||
(consecutive?.offset ?: 0)
|
||||
} else {
|
||||
(3 - (((consecutive?.count ?: 0)) % 3))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import com.habitrpg.android.habitica.R
|
|||
import com.habitrpg.android.habitica.components.UserComponent
|
||||
import com.habitrpg.android.habitica.databinding.ActivityAdventureGuideBinding
|
||||
import com.habitrpg.android.habitica.databinding.AdventureGuideItemBinding
|
||||
import com.habitrpg.android.habitica.extensions.fromHtml
|
||||
import com.habitrpg.common.habitica.extensions.fromHtml
|
||||
import com.habitrpg.android.habitica.helpers.AmplitudeManager
|
||||
import com.habitrpg.android.habitica.models.user.User
|
||||
import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import com.habitrpg.android.habitica.R
|
|||
import com.habitrpg.android.habitica.components.UserComponent
|
||||
import com.habitrpg.android.habitica.data.InventoryRepository
|
||||
import com.habitrpg.android.habitica.databinding.ActivityDeathBinding
|
||||
import com.habitrpg.android.habitica.extensions.fromHtml
|
||||
import com.habitrpg.common.habitica.extensions.fromHtml
|
||||
import com.habitrpg.android.habitica.extensions.observeOnce
|
||||
import com.habitrpg.android.habitica.helpers.AdHandler
|
||||
import com.habitrpg.android.habitica.helpers.AdType
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import androidx.appcompat.app.ActionBarDrawerToggle
|
|||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.view.children
|
||||
import androidx.drawerlayout.widget.DrawerLayout
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
|
|
@ -264,16 +263,10 @@ open class MainActivity : BaseActivity(), SnackbarActivity {
|
|||
showAsBottomSheet { onClose ->
|
||||
val group by viewModel.userViewModel.currentTeamPlanGroup.collectAsState(null)
|
||||
val members by viewModel.userViewModel.currentTeamPlanMembers.observeAsState()
|
||||
GroupPlanMemberList(members, group, {
|
||||
GroupPlanMemberList(members, group) {
|
||||
onClose()
|
||||
FullProfileActivity.open(it)
|
||||
}, { member ->
|
||||
onClose()
|
||||
MainNavigationController.navigate(
|
||||
R.id.inboxMessageListFragment,
|
||||
bundleOf(Pair("username", member.username), Pair("userID", member.id))
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import com.habitrpg.android.habitica.components.UserComponent
|
|||
import com.habitrpg.android.habitica.data.InventoryRepository
|
||||
import com.habitrpg.android.habitica.data.SocialRepository
|
||||
import com.habitrpg.android.habitica.databinding.ActivityNotificationsBinding
|
||||
import com.habitrpg.android.habitica.extensions.fromHtml
|
||||
import com.habitrpg.common.habitica.extensions.fromHtml
|
||||
import com.habitrpg.android.habitica.helpers.ExceptionHandler
|
||||
import com.habitrpg.android.habitica.helpers.launchCatching
|
||||
import com.habitrpg.android.habitica.models.inventory.QuestContent
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import android.widget.Button
|
|||
import android.widget.TextView
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.databinding.ShopHeaderBinding
|
||||
import com.habitrpg.android.habitica.extensions.fromHtml
|
||||
import com.habitrpg.common.habitica.extensions.fromHtml
|
||||
import com.habitrpg.android.habitica.extensions.inflate
|
||||
import com.habitrpg.android.habitica.helpers.MainNavigationController
|
||||
import com.habitrpg.android.habitica.models.shops.Shop
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import com.habitrpg.android.habitica.components.UserComponent
|
|||
import com.habitrpg.android.habitica.data.InventoryRepository
|
||||
import com.habitrpg.android.habitica.data.SocialRepository
|
||||
import com.habitrpg.android.habitica.databinding.FragmentQuestDetailBinding
|
||||
import com.habitrpg.android.habitica.extensions.fromHtml
|
||||
import com.habitrpg.common.habitica.extensions.fromHtml
|
||||
import com.habitrpg.android.habitica.helpers.ExceptionHandler
|
||||
import com.habitrpg.android.habitica.helpers.HapticFeedbackManager
|
||||
import com.habitrpg.android.habitica.helpers.launchCatching
|
||||
|
|
|
|||
|
|
@ -163,6 +163,7 @@ open class GroupViewModel(initializeComponent: Boolean) : BaseViewModel(initiali
|
|||
fun leaveGroup(
|
||||
groupChallenges: List<Challenge>,
|
||||
keepChallenges: Boolean = true,
|
||||
function: (() -> Unit)? = null
|
||||
) {
|
||||
if (!keepChallenges) {
|
||||
viewModelScope.launchCatching {
|
||||
|
|
@ -174,6 +175,7 @@ open class GroupViewModel(initializeComponent: Boolean) : BaseViewModel(initiali
|
|||
viewModelScope.launch(ExceptionHandler.coroutine()) {
|
||||
socialRepository.leaveGroup(groupID ?: "", keepChallenges)
|
||||
userRepository.retrieveUser(withTasks = false, forced = true)
|
||||
function?.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ import kotlin.random.Random
|
|||
fun GroupPlanMemberList(
|
||||
members: List<Member>?,
|
||||
group: Group?,
|
||||
onMemberClicked: (String) -> Unit) {
|
||||
onMemberClicked: (String) -> Unit
|
||||
) {
|
||||
LazyColumn {
|
||||
item {
|
||||
Text(
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import android.view.View
|
|||
import android.widget.TextView
|
||||
import com.habitrpg.android.habitica.databinding.DialogAchievementDetailBinding
|
||||
import com.habitrpg.android.habitica.extensions.addCloseButton
|
||||
import com.habitrpg.android.habitica.extensions.fromHtml
|
||||
import com.habitrpg.common.habitica.extensions.fromHtml
|
||||
import com.habitrpg.android.habitica.models.Achievement
|
||||
import com.habitrpg.common.habitica.extensions.loadImage
|
||||
import com.habitrpg.common.habitica.views.PixelArtView
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import android.view.View
|
|||
import android.widget.TextView
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.databinding.DialogAchievementDetailBinding
|
||||
import com.habitrpg.android.habitica.extensions.fromHtml
|
||||
import com.habitrpg.common.habitica.extensions.fromHtml
|
||||
import com.habitrpg.android.habitica.helpers.MainNavigationController
|
||||
import com.habitrpg.android.habitica.models.user.User
|
||||
import com.habitrpg.common.habitica.extensions.layoutInflater
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import android.widget.LinearLayout
|
|||
import android.widget.TextView
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.databinding.DialogCompletedQuestContentBinding
|
||||
import com.habitrpg.android.habitica.extensions.fromHtml
|
||||
import com.habitrpg.common.habitica.extensions.fromHtml
|
||||
import com.habitrpg.android.habitica.models.inventory.QuestContent
|
||||
import com.habitrpg.android.habitica.models.inventory.QuestDropItem
|
||||
import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import android.view.View
|
|||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.extensions.fromHtml
|
||||
import com.habitrpg.common.habitica.extensions.fromHtml
|
||||
import com.habitrpg.common.habitica.extensions.loadImage
|
||||
import com.habitrpg.common.habitica.models.notifications.ChallengeWonData
|
||||
import com.habitrpg.common.habitica.views.PixelArtView
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import android.util.AttributeSet
|
|||
import android.view.Gravity
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import com.habitrpg.android.habitica.extensions.fromHtml
|
||||
import com.habitrpg.common.habitica.extensions.fromHtml
|
||||
import com.habitrpg.android.habitica.models.inventory.QuestContent
|
||||
import com.habitrpg.android.habitica.models.shops.ShopItem
|
||||
import com.habitrpg.common.habitica.extensions.dpToPx
|
||||
|
|
|
|||
|
|
@ -81,13 +81,6 @@ class TaskRepositoryImplTest : WordSpec({
|
|||
localRepository.getUser("")
|
||||
}
|
||||
}
|
||||
"does not update user for team tasks" {
|
||||
val data = TaskDirectionData()
|
||||
data.lvl = 0
|
||||
coEvery { apiClient.postTaskDirection(any(), "up") } returns data
|
||||
repository.taskChecked(user, task, true, false, null)
|
||||
verify(exactly = 0) { user.stats }
|
||||
}
|
||||
"builds task result correctly" {
|
||||
val data = TaskDirectionData()
|
||||
data.lvl = 10
|
||||
|
|
|
|||
|
|
@ -31,9 +31,17 @@ class MemberTest : WordSpec({
|
|||
member.hasClass shouldBe false
|
||||
}
|
||||
|
||||
"false if user is below level 10" {
|
||||
member.flags?.classSelected = true
|
||||
member.stats?.habitClass = Stats.ROGUE
|
||||
member.stats?.lvl = 9
|
||||
member.hasClass shouldBe false
|
||||
}
|
||||
|
||||
"true if class was selected and not disabled" {
|
||||
member.flags?.classSelected = true
|
||||
member.stats?.habitClass = Stats.ROGUE
|
||||
member.stats?.lvl = 10
|
||||
member.hasClass shouldBe true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,10 +37,17 @@ class UserTest : WordSpec({
|
|||
user.hasClass shouldBe false
|
||||
}
|
||||
|
||||
"false if user is below level 10" {
|
||||
user.flags?.classSelected = true
|
||||
user.stats?.habitClass = Stats.ROGUE
|
||||
user.stats?.lvl = 9
|
||||
user.hasClass shouldBe false
|
||||
}
|
||||
|
||||
"true if class was selected and not disabled" {
|
||||
user.flags?.classSelected = true
|
||||
user.preferences?.disableClasses = false
|
||||
user.stats?.habitClass = Stats.ROGUE
|
||||
user.stats?.lvl = 10
|
||||
user.hasClass shouldBe true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,10 +16,12 @@ buildscript {
|
|||
coroutines_version = '1.6.4'
|
||||
daggerhilt_version = '2.44.2'
|
||||
firebase_bom = '31.2.0'
|
||||
kotest_version = '5.5.5'
|
||||
kotlin_version = '1.8.10'
|
||||
ktlint_version = '0.48.2'
|
||||
lifecycle_version = '2.5.1'
|
||||
markwon_version = '4.6.2'
|
||||
mockk_version = '1.13.4'
|
||||
moshi_version = '1.14.0'
|
||||
navigation_version = '2.5.3'
|
||||
okhttp_version = '4.10.0'
|
||||
|
|
|
|||
|
|
@ -38,6 +38,37 @@ android {
|
|||
jvmTarget = JavaVersion.VERSION_1_8.toString()
|
||||
}
|
||||
namespace 'com.habitrpg.common.habitica'
|
||||
|
||||
flavorDimensions "buildType"
|
||||
|
||||
productFlavors {
|
||||
dev {
|
||||
dimension "buildType"
|
||||
}
|
||||
|
||||
staff {
|
||||
dimension "buildType"
|
||||
buildConfigField "String", "TESTING_LEVEL", "\"staff\""
|
||||
}
|
||||
|
||||
partners {
|
||||
dimension "buildType"
|
||||
buildConfigField "String", "TESTING_LEVEL", "\"partners\""
|
||||
}
|
||||
|
||||
alpha {
|
||||
dimension "buildType"
|
||||
buildConfigField "String", "TESTING_LEVEL", "\"alpha\""
|
||||
}
|
||||
|
||||
beta {
|
||||
buildConfigField "String", "TESTING_LEVEL", "\"beta\""
|
||||
}
|
||||
|
||||
prod {
|
||||
buildConfigField "String", "TESTING_LEVEL", "\"production\""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
|
@ -57,13 +88,23 @@ dependencies {
|
|||
implementation("io.coil-kt:coil:$coil_version")
|
||||
implementation("io.coil-kt:coil-gif:$coil_version")
|
||||
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
||||
testImplementation "io.mockk:mockk:$mockk_version"
|
||||
testImplementation "io.mockk:mockk-android:$mockk_version"
|
||||
testImplementation "io.kotest:kotest-runner-junit5:$kotest_version"
|
||||
testImplementation "io.kotest:kotest-assertions-core:$kotest_version"
|
||||
testImplementation "io.kotest:kotest-framework-datatest:$kotest_version"
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
|
||||
|
||||
implementation project(':shared')
|
||||
}
|
||||
|
||||
android.testOptions {
|
||||
unitTests.all {
|
||||
it.useJUnitPlatform()
|
||||
}
|
||||
}
|
||||
|
||||
// Add Habitica Properties to buildConfigField
|
||||
final File HRPG_PROPS_FILE = new File(projectDir.absolutePath + '/../habitica.properties')
|
||||
if (HRPG_PROPS_FILE.canRead()) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package com.habitrpg.android.habitica.extensions
|
||||
package com.habitrpg.common.habitica.extensions
|
||||
|
||||
import android.text.Html
|
||||
import android.text.Spannable
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
package com.habitrpg.common.habitica.api
|
||||
|
||||
import io.kotest.core.spec.style.WordSpec
|
||||
import io.kotest.matchers.string.shouldEndWith
|
||||
|
||||
class ServerTest : WordSpec({
|
||||
"constructor" should {
|
||||
"add api version if missing" {
|
||||
val server = Server("https://habitica.com")
|
||||
server.toString() shouldEndWith "/api/v4/"
|
||||
}
|
||||
"add api version if missing but has trailing slash" {
|
||||
val server = Server("https://habitica.com")
|
||||
server.toString() shouldEndWith ".com/api/v4/"
|
||||
}
|
||||
"not add api version multiple times" {
|
||||
val server = Server("https://habitica.com")
|
||||
server.toString() shouldEndWith ".com/api/v4/"
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -3,20 +3,19 @@ plugins {
|
|||
id("com.android.library")
|
||||
id("kotlin-parcelize")
|
||||
id("kotlin-kapt")
|
||||
id("io.kotest.multiplatform") version "5.5.5"
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
}
|
||||
}
|
||||
|
||||
kotlin {
|
||||
android()
|
||||
|
||||
listOf(
|
||||
iosX64(),
|
||||
iosArm64(),
|
||||
iosSimulatorArm64()
|
||||
).forEach {
|
||||
it.binaries.framework {
|
||||
baseName = "shared"
|
||||
}
|
||||
}
|
||||
ios()
|
||||
|
||||
sourceSets {
|
||||
val commonMain by getting {
|
||||
|
|
@ -26,29 +25,13 @@ kotlin {
|
|||
}
|
||||
val commonTest by getting {
|
||||
dependencies {
|
||||
implementation(kotlin("test"))
|
||||
implementation(kotlin("test")) // This brings all the platform dependencies automatically
|
||||
}
|
||||
}
|
||||
val androidMain by getting
|
||||
val androidTest by getting
|
||||
val iosX64Main by getting
|
||||
val iosArm64Main by getting
|
||||
val iosSimulatorArm64Main by getting
|
||||
val iosMain by creating {
|
||||
dependsOn(commonMain)
|
||||
iosX64Main.dependsOn(this)
|
||||
iosArm64Main.dependsOn(this)
|
||||
iosSimulatorArm64Main.dependsOn(this)
|
||||
}
|
||||
val iosX64Test by getting
|
||||
val iosArm64Test by getting
|
||||
val iosSimulatorArm64Test by getting
|
||||
val iosTest by creating {
|
||||
dependsOn(commonTest)
|
||||
iosX64Test.dependsOn(this)
|
||||
iosArm64Test.dependsOn(this)
|
||||
iosSimulatorArm64Test.dependsOn(this)
|
||||
}
|
||||
val iosMain by getting
|
||||
val iosTest by getting
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -66,4 +49,4 @@ android {
|
|||
}
|
||||
|
||||
namespace = "com.habitrpg.shared.habitica"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package com.habitrpg.shared.habitica.models.tasks
|
||||
|
||||
interface BaseTask {
|
||||
|
||||
val completed: Boolean
|
||||
var type: TaskType?
|
||||
var isDue: Boolean?
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
package com.habitrpg.shared.habitica.models.tasks
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class AttributeTest {
|
||||
@Test
|
||||
fun testFrom() {
|
||||
assertEquals(Attribute.STRENGTH, Attribute.from("str"))
|
||||
assertEquals(Attribute.CONSTITUTION, Attribute.from("con"))
|
||||
assertEquals(Attribute.PERCEPTION, Attribute.from("per"))
|
||||
assertEquals(Attribute.INTELLIGENCE, Attribute.from("int"))
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,13 @@ apply plugin: 'kotlin-android'
|
|||
android {
|
||||
compileSdk target_sdk
|
||||
|
||||
testOptions {
|
||||
unitTests {
|
||||
includeAndroidResources = true
|
||||
}
|
||||
animationsDisabled = true
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.habitrpg.android.habitica"
|
||||
minSdk 26
|
||||
|
|
@ -137,11 +144,25 @@ dependencies {
|
|||
kapt "com.google.dagger:hilt-compiler:$daggerhilt_version"
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
|
||||
testImplementation "io.mockk:mockk:$mockk_version"
|
||||
testImplementation "io.mockk:mockk-android:$mockk_version"
|
||||
testImplementation "io.kotest:kotest-runner-junit5:$kotest_version"
|
||||
testImplementation "io.kotest:kotest-assertions-core:$kotest_version"
|
||||
testImplementation "io.kotest:kotest-framework-datatest:$kotest_version"
|
||||
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version"
|
||||
testImplementation 'app.cash.turbine:turbine:0.12.1'
|
||||
}
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
android.testOptions {
|
||||
unitTests.all {
|
||||
it.useJUnitPlatform()
|
||||
}
|
||||
}
|
||||
|
||||
final File HRPG_PROPS_FILE = new File(projectDir.absolutePath + '/../habitica.properties')
|
||||
if (HRPG_PROPS_FILE.canRead()) {
|
||||
Properties HRPG_PROPS = new Properties()
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import dagger.hilt.android.HiltAndroidApp
|
|||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
|
@ -40,6 +41,7 @@ class MainApplication : Application() {
|
|||
|
||||
MainScope().launch {
|
||||
userRepository.getUser()
|
||||
.filterNotNull()
|
||||
.onEach {
|
||||
if (it.isDead && BaseActivity.currentActivityClassName == MainActivity::class.java.name) {
|
||||
val intent = Intent(this@MainApplication, FaintActivity::class.java)
|
||||
|
|
|
|||
|
|
@ -1,16 +1,14 @@
|
|||
package com.habitrpg.wearos.habitica.data.repositories
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.asFlow
|
||||
import com.habitrpg.wearos.habitica.models.user.User
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class UserLocalRepository @Inject constructor() {
|
||||
private val user = MutableLiveData<User?>()
|
||||
fun getUser() = user.asFlow().filterNotNull()
|
||||
private val user = MutableStateFlow<User?>(null)
|
||||
fun getUser() = user
|
||||
|
||||
fun saveUser(user: User) {
|
||||
this.user.value = user
|
||||
|
|
|
|||
|
|
@ -23,6 +23,6 @@ sealed class NetworkResult<out T : Any> {
|
|||
val isError: Boolean
|
||||
get() = this is Error
|
||||
|
||||
data class Success<out T : Any>(val data: T, val isFresh: Boolean) : NetworkResult<T>()
|
||||
data class Error(val exception: Exception, val isFresh: Boolean) : NetworkResult<Nothing>()
|
||||
data class Success<out T : Any>(val data: T, internal val isFresh: Boolean) : NetworkResult<T>()
|
||||
data class Error(val exception: Exception, internal val isFresh: Boolean) : NetworkResult<Nothing>()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,10 +6,13 @@ import android.view.Gravity
|
|||
import android.view.ViewOutlineProvider
|
||||
import android.widget.FrameLayout
|
||||
import androidx.activity.viewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.habitrpg.android.habitica.databinding.ActivityAvatarBinding
|
||||
import com.habitrpg.common.habitica.extensions.dpToPx
|
||||
import com.habitrpg.wearos.habitica.ui.viewmodels.AvatarViewModel
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.launch
|
||||
import java.lang.Integer.max
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
|
|
@ -21,8 +24,10 @@ class AvatarActivity : BaseActivity<ActivityAvatarBinding, AvatarViewModel>() {
|
|||
binding = ActivityAvatarBinding.inflate(layoutInflater)
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
viewModel.user.observe(this) {
|
||||
binding.avatarView.setAvatar(it)
|
||||
lifecycleScope.launch {
|
||||
viewModel.user.filterNotNull().collect {
|
||||
binding.avatarView.setAvatar(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import com.habitrpg.wearos.habitica.ui.adapters.HubAdapter
|
|||
import com.habitrpg.wearos.habitica.ui.viewmodels.MainViewModel
|
||||
import com.habitrpg.wearos.habitica.util.HabiticaScrollingLayoutCallback
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@AndroidEntryPoint
|
||||
|
|
@ -111,12 +112,17 @@ class MainActivity : BaseActivity<ActivityMainBinding, MainViewModel>() {
|
|||
openSettingsActivity()
|
||||
}
|
||||
)
|
||||
viewModel.user.observe(this) { user ->
|
||||
adapter.title = user.profile?.name ?: ""
|
||||
val index = adapter.data.indexOfFirst { it.identifier == "stats" }
|
||||
adapter.data[index].detailText = getString(R.string.user_level, user.stats?.lvl ?: 0)
|
||||
adapter.notifyItemChanged(index + 1)
|
||||
lifecycleScope.launch {
|
||||
viewModel.user
|
||||
.filterNotNull()
|
||||
.collect { user ->
|
||||
adapter.title = user.profile?.name ?: ""
|
||||
val index = adapter.data.indexOfFirst { it.identifier == "stats" }
|
||||
adapter.data[index].detailText = getString(R.string.user_level, user.stats?.lvl ?: 0)
|
||||
adapter.notifyItemChanged(index + 1)
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.taskCounts.observe(this) {
|
||||
adapter.data.forEach { menuItem ->
|
||||
if (it.containsKey(menuItem.identifier)) {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import androidx.preference.PreferenceManager
|
|||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.databinding.ActivityTaskResultBinding
|
||||
import com.habitrpg.android.habitica.databinding.TaskRewardDropBinding
|
||||
import com.habitrpg.android.habitica.extensions.localizedCapitalize
|
||||
import com.habitrpg.common.habitica.extensions.localizedCapitalize
|
||||
import com.habitrpg.common.habitica.extensions.dpToPx
|
||||
import com.habitrpg.common.habitica.extensions.loadImage
|
||||
import com.habitrpg.shared.habitica.models.responses.TaskScoringResult
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.habitrpg.wearos.habitica.ui.viewmodels
|
||||
|
||||
import androidx.lifecycle.asLiveData
|
||||
import com.habitrpg.wearos.habitica.data.repositories.TaskRepository
|
||||
import com.habitrpg.wearos.habitica.data.repositories.UserRepository
|
||||
import com.habitrpg.wearos.habitica.managers.AppStateManager
|
||||
|
|
@ -19,5 +18,5 @@ class AvatarViewModel @Inject constructor(
|
|||
taskRepository,
|
||||
exceptionBuilder, appStateManager
|
||||
) {
|
||||
var user = userRepository.getUser().asLiveData()
|
||||
var user = userRepository.getUser()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,6 @@ class LevelupViewModel @Inject constructor(
|
|||
appStateManager: AppStateManager
|
||||
) : BaseViewModel(userRepository, taskRepository, exceptionBuilder, appStateManager) {
|
||||
val level = userRepository.getUser()
|
||||
.map { it.stats?.lvl }
|
||||
.map { it?.stats?.lvl }
|
||||
.asLiveData()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,5 +28,5 @@ class MainViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
val taskCounts = taskRepository.getActiveTaskCounts().asLiveData()
|
||||
val user = userRepository.getUser().asLiveData()
|
||||
val user = userRepository.getUser()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import com.habitrpg.wearos.habitica.models.user.User
|
|||
import com.habitrpg.wearos.habitica.util.ExceptionHandlerBuilder
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -27,6 +28,7 @@ class StatsViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
var user: LiveData<User> = userRepository.getUser()
|
||||
.filterNotNull()
|
||||
.distinctUntilChanged { old, new ->
|
||||
val oldStats = old.stats ?: return@distinctUntilChanged false
|
||||
val newStats = new.stats ?: return@distinctUntilChanged false
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
package com.habitrpg.wearos.habitica
|
||||
|
||||
import androidx.arch.core.executor.ArchTaskExecutor
|
||||
import androidx.arch.core.executor.TaskExecutor
|
||||
import io.kotest.core.config.AbstractProjectConfig
|
||||
import kotlinx.coroutines.test.TestCoroutineDispatcher
|
||||
|
||||
object ProjectConfig : AbstractProjectConfig() {
|
||||
private val testDispatcher = TestCoroutineDispatcher()
|
||||
|
||||
override suspend fun beforeProject() {
|
||||
super.beforeProject()
|
||||
setupLiveData()
|
||||
}
|
||||
|
||||
override suspend fun afterProject() {
|
||||
super.afterProject()
|
||||
resetLiveData()
|
||||
}
|
||||
|
||||
private fun setupLiveData() {
|
||||
ArchTaskExecutor.getInstance().setDelegate(object : TaskExecutor() {
|
||||
override fun executeOnDiskIO(runnable: Runnable) {
|
||||
runnable.run()
|
||||
}
|
||||
|
||||
override fun postToMainThread(runnable: Runnable) {
|
||||
runnable.run()
|
||||
}
|
||||
|
||||
override fun isMainThread(): Boolean {
|
||||
return true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun resetLiveData() {
|
||||
ArchTaskExecutor.getInstance().setDelegate(null)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package com.habitrpg.wearos.habitica.data.repositories
|
||||
|
||||
import app.cash.turbine.test
|
||||
import com.habitrpg.shared.habitica.models.tasks.TaskType
|
||||
import com.habitrpg.wearos.habitica.models.tasks.Task
|
||||
import com.habitrpg.wearos.habitica.models.tasks.TaskList
|
||||
import io.kotest.core.spec.style.WordSpec
|
||||
import io.kotest.matchers.shouldBe
|
||||
|
||||
class TaskLocalRepositoryTest : WordSpec({
|
||||
val repository = TaskLocalRepository()
|
||||
val list = TaskList()
|
||||
list.tasks["1"] = Task().apply {
|
||||
id = "1"
|
||||
type = TaskType.HABIT
|
||||
}
|
||||
list.tasks["2"] = Task().apply {
|
||||
id = "2"
|
||||
type = TaskType.DAILY
|
||||
}
|
||||
list.tasks["3"] = Task().apply {
|
||||
id = "3"
|
||||
type = TaskType.DAILY
|
||||
}
|
||||
list.tasks["4"] = Task().apply {
|
||||
id = "4"
|
||||
type = TaskType.REWARD
|
||||
}
|
||||
"getTask" should {
|
||||
"return right task" {
|
||||
repository.getTask("3").test {
|
||||
awaitItem()?.id shouldBe "3"
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package com.habitrpg.wearos.habitica.data.repositories
|
||||
|
||||
import app.cash.turbine.test
|
||||
import com.habitrpg.wearos.habitica.models.user.User
|
||||
import io.kotest.core.spec.style.WordSpec
|
||||
import io.kotest.matchers.shouldBe
|
||||
|
||||
class UserLocalRepositoryTest : WordSpec({
|
||||
coroutineTestScope = true
|
||||
val repository = UserLocalRepository()
|
||||
|
||||
"saveUser" should {
|
||||
"update user in flow" {
|
||||
val existing = User()
|
||||
repository.saveUser(existing)
|
||||
repository.getUser().test {
|
||||
awaitItem() shouldBe existing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"clearData" should {
|
||||
"clear user from flow" {
|
||||
val existing = User()
|
||||
repository.saveUser(existing)
|
||||
repository.clearData()
|
||||
repository.getUser().test {
|
||||
awaitItem() shouldBe null
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package com.habitrpg.wearos.habitica.models
|
||||
|
||||
import io.kotest.core.spec.style.WordSpec
|
||||
import io.kotest.matchers.shouldBe
|
||||
|
||||
class NetworkResultTest : WordSpec({
|
||||
"isSuccess" should {
|
||||
"be true if it's successful" {
|
||||
val response = NetworkResult.Success<String>("", true)
|
||||
response.isSuccess shouldBe true
|
||||
}
|
||||
|
||||
"be false if it errored" {
|
||||
val response = NetworkResult.Error(Exception(), true)
|
||||
response.isSuccess shouldBe false
|
||||
}
|
||||
}
|
||||
|
||||
"isError" should {
|
||||
"be true if it's errored" {
|
||||
val response = NetworkResult.Error(Exception(), true)
|
||||
response.isError shouldBe true
|
||||
}
|
||||
|
||||
"be false if it's successful" {
|
||||
val response = NetworkResult.Success<String>("", true)
|
||||
response.isError shouldBe false
|
||||
}
|
||||
}
|
||||
|
||||
"isResponseFresh" should {
|
||||
"be true if it's a fresh response" {
|
||||
val response = NetworkResult.Success<String>("", true)
|
||||
response.isResponseFresh shouldBe true
|
||||
}
|
||||
|
||||
"be false if it errored" {
|
||||
val response = NetworkResult.Success<String>("", false)
|
||||
response.isResponseFresh shouldBe false
|
||||
}
|
||||
}
|
||||
})
|
||||
Loading…
Reference in a new issue