mirror of
https://github.com/sudoxnym/habitica-android.git
synced 2026-05-18 11:49:01 +00:00
Fix some tests
This commit is contained in:
parent
553cd19176
commit
6222b24df6
11 changed files with 330 additions and 312 deletions
|
|
@ -96,6 +96,7 @@
|
|||
app:layout_collapseMode="pin"
|
||||
app:tabGravity="fill"
|
||||
app:tabIndicatorColor="?textColorPrimary"
|
||||
app:tabSelectedTextColor="?textColorPrimary"
|
||||
app:tabMode="fixed" />
|
||||
<FrameLayout
|
||||
android:id="@+id/connection_issue_view"
|
||||
|
|
|
|||
|
|
@ -1338,6 +1338,7 @@
|
|||
<string name="twenty_gems">20 Gems</string>
|
||||
<string name="background">Background</string>
|
||||
<string name="birthday_set">Birthday Set</string>
|
||||
<string name="you_equipped_x">You equipped %s</string>
|
||||
|
||||
<plurals name="you_x_others">
|
||||
<item quantity="zero">You</item>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import io.github.kakaocup.kakao.text.KTextView
|
|||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.spyk
|
||||
import io.reactivex.rxjava3.core.Flowable
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
|
|
@ -38,7 +38,7 @@ class PartyDetailFragmentTest : FragmentTestCase<PartyDetailFragment, FragmentPa
|
|||
override fun makeFragment() {
|
||||
val group = Group()
|
||||
group.name = "Group Name"
|
||||
every { socialRepository.getGroup(any()) } returns Flowable.just(group)
|
||||
every { socialRepository.getGroup(any()) } returns flowOf(group)
|
||||
viewModel = PartyViewModel(false)
|
||||
viewModel.socialRepository = socialRepository
|
||||
viewModel.userRepository = userRepository
|
||||
|
|
|
|||
|
|
@ -10,10 +10,11 @@ import com.habitrpg.shared.habitica.models.tasks.Attribute
|
|||
import io.github.kakaocup.kakao.common.views.KView
|
||||
import io.github.kakaocup.kakao.screen.Screen
|
||||
import io.github.kakaocup.kakao.text.KButton
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.every
|
||||
import io.mockk.spyk
|
||||
import io.mockk.verify
|
||||
import io.reactivex.rxjava3.core.Flowable
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
|
@ -63,9 +64,9 @@ class StatsFragmentTest : FragmentTestCase<StatsFragment, FragmentStatsBinding,
|
|||
fun setUpUser() {
|
||||
user.stats?.lvl = 20
|
||||
user.stats?.points = 30
|
||||
userState.onNext(user)
|
||||
userState.value = user
|
||||
|
||||
every { inventoryRepository.getEquipment(listOf()) } returns Flowable.just(listOf())
|
||||
every { inventoryRepository.getEquipment(listOf()) } returns flowOf(listOf())
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -96,13 +97,13 @@ class StatsFragmentTest : FragmentTestCase<StatsFragment, FragmentStatsBinding,
|
|||
fun allocatesOnClick() {
|
||||
screen {
|
||||
strengthAllocateButton.click()
|
||||
verify { userRepository.allocatePoint(Attribute.STRENGTH) }
|
||||
coVerify { userRepository.allocatePoint(Attribute.STRENGTH) }
|
||||
intelligenceAllocateButton.click()
|
||||
verify { userRepository.allocatePoint(Attribute.INTELLIGENCE) }
|
||||
coVerify { userRepository.allocatePoint(Attribute.INTELLIGENCE) }
|
||||
constitutionAllocateButton.click()
|
||||
verify { userRepository.allocatePoint(Attribute.CONSTITUTION) }
|
||||
coVerify { userRepository.allocatePoint(Attribute.CONSTITUTION) }
|
||||
perceptionAllocateButton.click()
|
||||
verify { userRepository.allocatePoint(Attribute.PERCEPTION) }
|
||||
coVerify { userRepository.allocatePoint(Attribute.PERCEPTION) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,12 +15,14 @@ import io.github.kakaocup.kakao.recycler.KRecyclerView
|
|||
import io.github.kakaocup.kakao.screen.Screen
|
||||
import io.kotest.matchers.shouldBe
|
||||
import io.mockk.CapturingSlot
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkObject
|
||||
import io.mockk.spyk
|
||||
import io.mockk.verify
|
||||
import io.reactivex.rxjava3.core.Flowable
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import org.junit.Test
|
||||
|
||||
class PetDetailScreen : Screen<PetDetailScreen>() {
|
||||
|
|
@ -35,12 +37,12 @@ class PetDetailScreen : Screen<PetDetailScreen>() {
|
|||
internal class PetDetailRecyclerFragmentTest :
|
||||
FragmentTestCase<PetDetailRecyclerFragment, FragmentRecyclerviewBinding, PetDetailScreen>(false) {
|
||||
override fun makeFragment() {
|
||||
every { inventoryRepository.getOwnedPets() } returns Flowable.just(user.items?.pets!!)
|
||||
every { inventoryRepository.getOwnedMounts() } returns Flowable.just(user.items?.mounts!!)
|
||||
every { inventoryRepository.getOwnedItems("food") } returns Flowable.just(user.items?.food!!.filter { it.numberOwned > 0 })
|
||||
every { inventoryRepository.getOwnedPets() } returns flowOf(user.items?.pets!!)
|
||||
every { inventoryRepository.getOwnedMounts() } returns flowOf(user.items?.mounts!!)
|
||||
every { inventoryRepository.getOwnedItems("food") } returns flowOf(user.items?.food!!.filter { it.numberOwned > 0 })
|
||||
val saddle = OwnedItem()
|
||||
saddle.numberOwned = 1
|
||||
every { inventoryRepository.getOwnedItems(true) } returns Flowable.just(
|
||||
every { inventoryRepository.getOwnedItems(true) } returns flowOf(
|
||||
mapOf(
|
||||
Pair(
|
||||
"Saddle-food",
|
||||
|
|
@ -69,21 +71,21 @@ internal class PetDetailRecyclerFragmentTest :
|
|||
@Test
|
||||
fun canFeedPet() {
|
||||
val slot = CapturingSlot<FeedPetUseCase.RequestValues>()
|
||||
every { feedPetUseCase.callInteractor(capture(slot)) } returns mockk(relaxed = true)
|
||||
coEvery { feedPetUseCase.callInteractor(capture(slot)) } returns mockk(relaxed = true)
|
||||
every {
|
||||
inventoryRepository.getPets(
|
||||
any(),
|
||||
any(),
|
||||
any()
|
||||
)
|
||||
} returns Flowable.just(content.pets.filter { it.animal == "Cactus" })
|
||||
} returns flowOf(content.pets.filter { it.animal == "Cactus" })
|
||||
every {
|
||||
inventoryRepository.getMounts(
|
||||
any(),
|
||||
any(),
|
||||
any()
|
||||
)
|
||||
} returns Flowable.just(content.mounts.filter { it.animal == "Cactus" })
|
||||
} returns flowOf(content.mounts.filter { it.animal == "Cactus" })
|
||||
launchFragment(
|
||||
PetDetailRecyclerFragmentArgs.Builder("cactus", "drop", "").build().toBundle()
|
||||
)
|
||||
|
|
@ -92,7 +94,7 @@ internal class PetDetailRecyclerFragmentTest :
|
|||
childWith<PetItem> { withContentDescription("Skeleton Cactus") }.click()
|
||||
KView { withText(R.string.feed) }.click()
|
||||
KView { withText("Meat") }.click()
|
||||
verify { feedPetUseCase.callInteractor(any()) }
|
||||
coVerify { feedPetUseCase.callInteractor(any()) }
|
||||
slot.captured.pet.key shouldBe "Cactus-Skeleton"
|
||||
slot.captured.food.key shouldBe "Meat"
|
||||
}
|
||||
|
|
@ -102,27 +104,27 @@ internal class PetDetailRecyclerFragmentTest :
|
|||
@Test
|
||||
fun canUseSaddle() {
|
||||
val slot = CapturingSlot<FeedPetUseCase.RequestValues>()
|
||||
every { feedPetUseCase.callInteractor(capture(slot)) } returns mockk(relaxed = true)
|
||||
coEvery { feedPetUseCase.callInteractor(capture(slot)) } returns mockk(relaxed = true)
|
||||
every {
|
||||
inventoryRepository.getPets(
|
||||
any(),
|
||||
any(),
|
||||
any()
|
||||
)
|
||||
} returns Flowable.just(content.pets.filter { it.animal == "Fox" })
|
||||
} returns flowOf(content.pets.filter { it.animal == "Fox" })
|
||||
every {
|
||||
inventoryRepository.getMounts(
|
||||
any(),
|
||||
any(),
|
||||
any()
|
||||
)
|
||||
} returns Flowable.just(content.mounts.filter { it.animal == "Fox" })
|
||||
} returns flowOf(content.mounts.filter { it.animal == "Fox" })
|
||||
launchFragment(PetDetailRecyclerFragmentArgs.Builder("fox", "drop", "").build().toBundle())
|
||||
screen {
|
||||
recycler {
|
||||
childWith<PetItem> { withContentDescription("Shade Fox") }.click()
|
||||
KView { withText(R.string.use_saddle) }.click()
|
||||
verify { feedPetUseCase.callInteractor(any()) }
|
||||
coVerify { feedPetUseCase.callInteractor(any()) }
|
||||
slot.captured.pet.key shouldBe "Fox-Shade"
|
||||
slot.captured.food.key shouldBe "Saddle"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import io.github.kakaocup.kakao.text.KTextView
|
|||
import io.mockk.every
|
||||
import io.mockk.spyk
|
||||
import io.mockk.verify
|
||||
import io.reactivex.rxjava3.core.Flowable
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import org.hamcrest.Matcher
|
||||
import org.junit.Test
|
||||
|
||||
|
|
@ -40,8 +40,8 @@ class StableScreen : Screen<StableScreen>() {
|
|||
|
||||
internal class StableRecyclerFragmentTest : FragmentTestCase<StableRecyclerFragment, FragmentRecyclerviewBinding, StableScreen>(false) {
|
||||
override fun makeFragment() {
|
||||
every { inventoryRepository.getOwnedPets() } returns Flowable.just(user.items?.pets!!)
|
||||
every { inventoryRepository.getOwnedMounts() } returns Flowable.just(user.items?.mounts!!)
|
||||
every { inventoryRepository.getOwnedPets() } returns flowOf(user.items?.pets!!)
|
||||
every { inventoryRepository.getOwnedMounts() } returns flowOf(user.items?.mounts!!)
|
||||
fragment = spyk()
|
||||
fragment.shouldInitializeComponent = false
|
||||
fragment.itemType = "pets"
|
||||
|
|
|
|||
|
|
@ -68,4 +68,5 @@ interface TaskRepository : BaseRepository {
|
|||
fun getTasksForChallenge(challengeID: String?): Flow<List<Task>>
|
||||
suspend fun bulkScoreTasks(data: List<Map<String, String>>): BulkTaskScoringData?
|
||||
suspend fun markTaskNeedsWork(task: Task, userID: String)
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -196,7 +196,9 @@ class TaskRepositoryImpl(
|
|||
override suspend fun markTaskNeedsWork(task: Task, userID: String) {
|
||||
val savedTask = apiClient.markTaskNeedsWork(task.id ?: "", userID)
|
||||
if (savedTask != null) {
|
||||
savedTask.id = task.id
|
||||
savedTask.position = task.position
|
||||
savedTask.group?.assignedUsersDetail?.firstOrNull { it.assignedUserID == userID }?.completed = false
|
||||
localRepository.save(savedTask)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.habitrpg.android.habitica.ui.activities
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
||||
import android.os.Bundle
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.foundation.Image
|
||||
|
|
@ -20,9 +21,16 @@ import androidx.compose.foundation.verticalScroll
|
|||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.material.CircularProgressIndicator
|
||||
import androidx.compose.material.DrawerState
|
||||
import androidx.compose.material.DrawerValue
|
||||
import androidx.compose.material.ProvideTextStyle
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.material.ScaffoldState
|
||||
import androidx.compose.material.SnackbarHostState
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.rememberScaffoldState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -49,6 +57,7 @@ import androidx.compose.ui.unit.sp
|
|||
import androidx.lifecycle.lifecycleScope
|
||||
import coil.compose.AsyncImage
|
||||
import com.android.billingclient.api.ProductDetails
|
||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.components.UserComponent
|
||||
import com.habitrpg.android.habitica.data.InventoryRepository
|
||||
|
|
@ -81,6 +90,7 @@ class BirthdayActivity : BaseActivity() {
|
|||
@Inject
|
||||
lateinit var configManager: AppConfigManager
|
||||
|
||||
val scaffoldState: ScaffoldState = ScaffoldState(DrawerState(DrawerValue.Closed), SnackbarHostState())
|
||||
private val isPurchasing = mutableStateOf(false)
|
||||
private val price = mutableStateOf("")
|
||||
private val hasGryphatrice = mutableStateOf(false)
|
||||
|
|
@ -94,6 +104,7 @@ class BirthdayActivity : BaseActivity() {
|
|||
setContent {
|
||||
HabiticaTheme {
|
||||
BirthdayActivityView(
|
||||
scaffoldState,
|
||||
isPurchasing.value,
|
||||
hasGryphatrice.value,
|
||||
price.value,
|
||||
|
|
@ -114,12 +125,13 @@ class BirthdayActivity : BaseActivity() {
|
|||
userRepository.retrieveUser(false, true)
|
||||
isPurchasing.value = false
|
||||
}
|
||||
},
|
||||
{
|
||||
lifecycleScope.launchCatching {
|
||||
inventoryRepository.equip("pet", "Gryphatrice-Jubilant")
|
||||
}
|
||||
})
|
||||
}
|
||||
) {
|
||||
lifecycleScope.launchCatching {
|
||||
inventoryRepository.equip("pet", "Gryphatrice-Jubilant")
|
||||
scaffoldState.snackbarHostState.showSnackbar(getString(R.string.you_equipped_x, getString(R.string.animated_gryphatrice_pet)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -177,6 +189,7 @@ fun BirthdayTitle(text: String) {
|
|||
|
||||
@Composable
|
||||
fun BirthdayActivityView(
|
||||
scaffoldState: ScaffoldState,
|
||||
isPurchasing: Boolean,
|
||||
hasGryphatrice: Boolean,
|
||||
price: String,
|
||||
|
|
@ -191,250 +204,269 @@ fun BirthdayActivityView(
|
|||
val textColor = Color.White
|
||||
val specialTextColor = colorResource(R.color.yellow_50)
|
||||
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier
|
||||
.background(
|
||||
Brush.verticalGradient(
|
||||
Pair(0.0f, colorResource(id = R.color.brand_300)),
|
||||
Pair(1.0f, colorResource(id = R.color.brand_200))
|
||||
)
|
||||
)
|
||||
.fillMaxWidth()
|
||||
.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
Button(
|
||||
onClick = {
|
||||
if (activity != null) {
|
||||
activity.finish()
|
||||
return@Button
|
||||
}
|
||||
MainNavigationController.navigateBack()
|
||||
},
|
||||
colors = ButtonDefaults.textButtonColors(contentColor = textColor),
|
||||
elevation = ButtonDefaults.elevation(0.dp, 0.dp),
|
||||
modifier = Modifier.align(Alignment.Start)
|
||||
) {
|
||||
Image(
|
||||
painterResource(R.drawable.arrow_back),
|
||||
stringResource(R.string.action_back),
|
||||
colorFilter = ColorFilter.tint(
|
||||
textColor
|
||||
)
|
||||
)
|
||||
}
|
||||
val systemUiController = rememberSystemUiController()
|
||||
val statusbarColor = colorResource(R.color.brand_300)
|
||||
val navigationbarColor = colorResource(R.color.brand_50)
|
||||
DisposableEffect(systemUiController) {
|
||||
systemUiController.setStatusBarColor(statusbarColor, darkIcons = false)
|
||||
systemUiController.setNavigationBarColor(navigationbarColor)
|
||||
onDispose {}
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
scaffoldState = scaffoldState
|
||||
) { padding ->
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier
|
||||
.padding(horizontal = 20.dp)
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
Image(
|
||||
painterResource(R.drawable.birthday_header),
|
||||
null,
|
||||
Modifier.padding(bottom = 8.dp)
|
||||
)
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Image(painterResource(R.drawable.birthday_gifts), null)
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier.padding(horizontal = 22.dp)
|
||||
) {
|
||||
Text(
|
||||
stringResource(id = R.string.limited_event).toUpperCase(Locale.current),
|
||||
fontSize = 12.sp,
|
||||
color = specialTextColor,
|
||||
fontWeight = FontWeight.Bold
|
||||
.background(
|
||||
Brush.verticalGradient(
|
||||
Pair(0.0f, colorResource(id = R.color.brand_300)),
|
||||
Pair(1.0f, colorResource(id = R.color.brand_200))
|
||||
)
|
||||
)
|
||||
.fillMaxWidth()
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(padding)
|
||||
) {
|
||||
Button(
|
||||
onClick = {
|
||||
if (activity != null) {
|
||||
activity.finish()
|
||||
return@Button
|
||||
}
|
||||
MainNavigationController.navigateBack()
|
||||
},
|
||||
colors = ButtonDefaults.textButtonColors(contentColor = textColor),
|
||||
elevation = ButtonDefaults.elevation(0.dp, 0.dp),
|
||||
modifier = Modifier.align(Alignment.Start)
|
||||
) {
|
||||
Image(
|
||||
painterResource(R.drawable.arrow_back),
|
||||
stringResource(R.string.action_back),
|
||||
colorFilter = ColorFilter.tint(
|
||||
textColor
|
||||
)
|
||||
)
|
||||
}
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier
|
||||
.padding(horizontal = 20.dp)
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
Image(
|
||||
painterResource(R.drawable.birthday_header),
|
||||
null,
|
||||
Modifier.padding(bottom = 8.dp)
|
||||
)
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Image(painterResource(R.drawable.birthday_gifts), null)
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier.padding(horizontal = 22.dp)
|
||||
) {
|
||||
Text(
|
||||
stringResource(id = R.string.limited_event).toUpperCase(Locale.current),
|
||||
fontSize = 12.sp,
|
||||
color = specialTextColor,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
Text(
|
||||
stringResource(
|
||||
R.string.x_to_y,
|
||||
dateFormat.format(startDate),
|
||||
dateFormat.format(endDate)
|
||||
),
|
||||
fontSize = 12.sp,
|
||||
color = textColor,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
}
|
||||
// right image should be flipped
|
||||
Image(
|
||||
painterResource(id = R.drawable.birthday_gifts),
|
||||
null,
|
||||
modifier = Modifier.scale(-1f, 1f)
|
||||
)
|
||||
}
|
||||
Text(
|
||||
stringResource(R.string.birthday_title_description),
|
||||
fontSize = 16.sp,
|
||||
color = specialTextColor,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.padding(top = 22.dp)
|
||||
)
|
||||
BirthdayTitle(stringResource(id = R.string.animated_gryphatrice_pet))
|
||||
Box(
|
||||
Modifier
|
||||
.size(161.dp, 129.dp)
|
||||
.padding(vertical = 20.dp)
|
||||
.background(colorResource(R.color.brand_50), RoundedCornerShape(8.dp))
|
||||
) {
|
||||
|
||||
}
|
||||
Text(
|
||||
stringResource(R.string.limited_edition).toUpperCase(Locale.current),
|
||||
fontSize = 12.sp,
|
||||
color = specialTextColor,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
Text(
|
||||
stringResource(R.string.gryphatrice_description),
|
||||
fontSize = 16.sp,
|
||||
color = textColor,
|
||||
textAlign = TextAlign.Center,
|
||||
lineHeight = 20.sp,
|
||||
modifier = Modifier.padding(bottom = 16.dp)
|
||||
)
|
||||
if (hasGryphatrice) {
|
||||
Text(
|
||||
stringResource(
|
||||
R.string.x_to_y,
|
||||
dateFormat.format(startDate),
|
||||
dateFormat.format(endDate)
|
||||
),
|
||||
stringResource(R.string.thanks_for_support),
|
||||
fontSize = 12.sp,
|
||||
color = textColor,
|
||||
fontWeight = FontWeight.Bold
|
||||
fontWeight = FontWeight.SemiBold
|
||||
)
|
||||
HabiticaButton(
|
||||
Color.White,
|
||||
colorResource(R.color.brand_200),
|
||||
{
|
||||
onEquipClick()
|
||||
},
|
||||
modifier = Modifier.padding(top = 20.dp)
|
||||
) {
|
||||
Text(stringResource(R.string.equip))
|
||||
}
|
||||
} else if (isPurchasing) {
|
||||
CircularProgressIndicator()
|
||||
} else {
|
||||
Text(buildAnnotatedString {
|
||||
append("Buy for ")
|
||||
withStyle(SpanStyle(fontWeight = FontWeight.Bold)) {
|
||||
append(price)
|
||||
}
|
||||
append(" or ")
|
||||
withStyle(SpanStyle(fontWeight = FontWeight.Bold)) {
|
||||
append("60 Gems")
|
||||
}
|
||||
}, color = Color.White)
|
||||
HabiticaButton(
|
||||
Color.White,
|
||||
colorResource(R.color.brand_200),
|
||||
{
|
||||
onPurchaseClick()
|
||||
},
|
||||
modifier = Modifier.padding(top = 20.dp)
|
||||
) {
|
||||
Text(stringResource(R.string.buy_for_x, price))
|
||||
}
|
||||
HabiticaButton(
|
||||
Color.White,
|
||||
colorResource(R.color.brand_200),
|
||||
{
|
||||
onGemPurchaseClick()
|
||||
},
|
||||
modifier = Modifier.padding(top = 20.dp)
|
||||
) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(stringResource(R.string.buy_for))
|
||||
CurrencyText(currency = "gems", value = 60)
|
||||
}
|
||||
}
|
||||
}
|
||||
// right image should be flipped
|
||||
Image(
|
||||
painterResource(id = R.drawable.birthday_gifts),
|
||||
null,
|
||||
modifier = Modifier.scale(-1f, 1f)
|
||||
)
|
||||
}
|
||||
Text(
|
||||
stringResource(R.string.birthday_title_description),
|
||||
fontSize = 16.sp,
|
||||
color = specialTextColor,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.padding(top = 22.dp)
|
||||
)
|
||||
BirthdayTitle(stringResource(id = R.string.animated_gryphatrice_pet))
|
||||
Box(
|
||||
Modifier
|
||||
.size(161.dp, 129.dp)
|
||||
.padding(vertical = 20.dp)
|
||||
.background(colorResource(R.color.brand_50), RoundedCornerShape(8.dp))
|
||||
) {
|
||||
|
||||
}
|
||||
Text(
|
||||
stringResource(R.string.limited_edition).toUpperCase(Locale.current),
|
||||
fontSize = 12.sp,
|
||||
color = specialTextColor,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
Text(
|
||||
stringResource(R.string.gryphatrice_description),
|
||||
fontSize = 16.sp,
|
||||
color = textColor,
|
||||
textAlign = TextAlign.Center,
|
||||
lineHeight = 20.sp,
|
||||
modifier = Modifier.padding(bottom = 16.dp)
|
||||
)
|
||||
if (hasGryphatrice) {
|
||||
BirthdayTitle(stringResource(id = R.string.plenty_of_potions))
|
||||
Text(
|
||||
stringResource(R.string.thanks_for_support),
|
||||
fontSize = 12.sp,
|
||||
stringResource(R.string.plenty_of_potions_description),
|
||||
fontSize = 16.sp,
|
||||
color = textColor,
|
||||
fontWeight = FontWeight.SemiBold
|
||||
textAlign = TextAlign.Center,
|
||||
lineHeight = 20.sp
|
||||
)
|
||||
HabiticaButton(
|
||||
Color.White,
|
||||
colorResource(R.color.brand_200),
|
||||
{},
|
||||
modifier = Modifier.padding(top = 20.dp)
|
||||
) {
|
||||
Text(stringResource(R.string.equip))
|
||||
}
|
||||
} else if (isPurchasing) {
|
||||
CircularProgressIndicator()
|
||||
} else {
|
||||
Text(buildAnnotatedString {
|
||||
append("Buy for ")
|
||||
withStyle(SpanStyle(fontWeight = FontWeight.Bold)) {
|
||||
append(price)
|
||||
}
|
||||
append(" or ")
|
||||
withStyle(SpanStyle(fontWeight = FontWeight.Bold)) {
|
||||
append("60 Gems")
|
||||
}
|
||||
}, color = Color.White)
|
||||
PotionGrid()
|
||||
HabiticaButton(
|
||||
Color.White,
|
||||
colorResource(R.color.brand_200),
|
||||
{
|
||||
onPurchaseClick()
|
||||
MainScope().launchCatching {
|
||||
activity?.finish()
|
||||
delay(500)
|
||||
MainNavigationController.navigate(R.id.marketFragment)
|
||||
}
|
||||
},
|
||||
modifier = Modifier.padding(top = 20.dp)
|
||||
) {
|
||||
Text(stringResource(R.string.buy_for_x, ""))
|
||||
Text(stringResource(R.string.visit_the_market))
|
||||
}
|
||||
HabiticaButton(
|
||||
Color.White,
|
||||
colorResource(R.color.brand_200),
|
||||
{
|
||||
onGemPurchaseClick()
|
||||
},
|
||||
modifier = Modifier.padding(top = 20.dp)
|
||||
BirthdayTitle(stringResource(id = R.string.for_for_free))
|
||||
Text(
|
||||
stringResource(R.string.for_for_free_description),
|
||||
fontSize = 16.sp,
|
||||
color = textColor,
|
||||
textAlign = TextAlign.Center,
|
||||
lineHeight = 20.sp
|
||||
)
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(14.dp),
|
||||
modifier = Modifier.padding(vertical = 20.dp)
|
||||
) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(stringResource(R.string.buy_for))
|
||||
CurrencyText(currency = "gems", value = 60)
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(14.dp),
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
FourFreeItem(
|
||||
day = 1,
|
||||
title = stringResource(R.string.a_party_robe),
|
||||
imageName = "",
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
FourFreeItem(
|
||||
day = 1,
|
||||
title = stringResource(R.string.twenty_gems),
|
||||
imageName = "",
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
}
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(14.dp),
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
FourFreeItem(
|
||||
day = 5,
|
||||
title = stringResource(R.string.birthday_set),
|
||||
imageName = "",
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
FourFreeItem(
|
||||
day = 10,
|
||||
title = stringResource(R.string.background),
|
||||
imageName = "",
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
BirthdayTitle(stringResource(id = R.string.plenty_of_potions))
|
||||
Text(
|
||||
stringResource(R.string.plenty_of_potions_description),
|
||||
fontSize = 16.sp,
|
||||
color = textColor,
|
||||
textAlign = TextAlign.Center,
|
||||
lineHeight = 20.sp
|
||||
)
|
||||
PotionGrid()
|
||||
HabiticaButton(
|
||||
Color.White,
|
||||
colorResource(R.color.brand_200),
|
||||
{
|
||||
MainScope().launchCatching {
|
||||
activity?.finish()
|
||||
delay(500)
|
||||
MainNavigationController.navigate(R.id.marketFragment)
|
||||
}
|
||||
},
|
||||
modifier = Modifier.padding(top = 20.dp)
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier
|
||||
.padding(top = 20.dp)
|
||||
.background(colorResource(R.color.brand_50))
|
||||
.padding(horizontal = 20.dp)
|
||||
.padding(top = 20.dp, bottom = 60.dp)
|
||||
) {
|
||||
Text(stringResource(R.string.visit_the_market))
|
||||
Text(
|
||||
stringResource(R.string.limitations),
|
||||
fontSize = 16.sp,
|
||||
color = colorResource(R.color.brand_600),
|
||||
fontWeight = FontWeight.Bold,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
Text(
|
||||
stringResource(R.string.birthday_limitations),
|
||||
fontSize = 14.sp,
|
||||
color = colorResource(R.color.brand_600),
|
||||
lineHeight = 20.sp,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
BirthdayTitle(stringResource(id = R.string.for_for_free))
|
||||
Text(
|
||||
stringResource(R.string.for_for_free_description),
|
||||
fontSize = 16.sp,
|
||||
color = textColor,
|
||||
textAlign = TextAlign.Center,
|
||||
lineHeight = 20.sp
|
||||
)
|
||||
Column(verticalArrangement = Arrangement.spacedBy(14.dp), modifier = Modifier.padding(vertical = 20.dp)) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(14.dp),
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
FourFreeItem(
|
||||
day = 1,
|
||||
title = stringResource(R.string.a_party_robe),
|
||||
imageName = "",
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
FourFreeItem(
|
||||
day = 1,
|
||||
title = stringResource(R.string.twenty_gems),
|
||||
imageName = "",
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
}
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(14.dp),
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
FourFreeItem(
|
||||
day = 5,
|
||||
title = stringResource(R.string.birthday_set),
|
||||
imageName = "",
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
FourFreeItem(
|
||||
day = 10,
|
||||
title = stringResource(R.string.background),
|
||||
imageName = "",
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier
|
||||
.padding(top = 20.dp)
|
||||
.background(colorResource(R.color.brand_50))
|
||||
.padding(horizontal = 20.dp)
|
||||
.padding(top = 20.dp, bottom = 60.dp)
|
||||
) {
|
||||
Text(
|
||||
stringResource(R.string.limitations),
|
||||
fontSize = 16.sp,
|
||||
color = colorResource(R.color.brand_600),
|
||||
fontWeight = FontWeight.Bold,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
Text(
|
||||
stringResource(R.string.birthday_limitations),
|
||||
fontSize = 14.sp,
|
||||
color = colorResource(R.color.brand_600),
|
||||
lineHeight = 20.sp,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -532,9 +564,10 @@ fun HabiticaButton(
|
|||
}
|
||||
|
||||
@Preview(device = Devices.PIXEL_4)
|
||||
@Preview(device = Devices.PIXEL_4, uiMode = UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun Preview() {
|
||||
BirthdayActivityView(true, false, "", Date(), Date(), {
|
||||
|
||||
}, {}, {})
|
||||
val scaffoldState = rememberScaffoldState()
|
||||
BirthdayActivityView(scaffoldState, true, false, "", Date(), Date(), {
|
||||
}, {}) {}
|
||||
}
|
||||
|
|
@ -199,7 +199,7 @@ class GuildDetailFragment : BaseFragment<FragmentGuildDetailBinding>() {
|
|||
binding?.guildSummary?.setMarkdown(guild?.summary)
|
||||
binding?.guildDescription?.setMarkdown(guild?.description)
|
||||
|
||||
binding?.inviteButton?.isVisible = guild?.isGroupPlan == true
|
||||
binding?.inviteButton?.isVisible = guild?.isGroupPlan != true
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
|||
|
|
@ -4,27 +4,27 @@ import com.habitrpg.android.habitica.data.ApiClient
|
|||
import com.habitrpg.android.habitica.data.TaskRepository
|
||||
import com.habitrpg.android.habitica.data.local.TaskLocalRepository
|
||||
import com.habitrpg.android.habitica.models.BaseObject
|
||||
import com.habitrpg.shared.habitica.models.responses.TaskDirectionData
|
||||
import com.habitrpg.shared.habitica.models.responses.TaskScoringResult
|
||||
import com.habitrpg.android.habitica.models.tasks.Task
|
||||
import com.habitrpg.android.habitica.models.tasks.TaskList
|
||||
import com.habitrpg.shared.habitica.models.tasks.TaskType
|
||||
import com.habitrpg.shared.habitica.models.tasks.TasksOrder
|
||||
import com.habitrpg.android.habitica.models.user.Stats
|
||||
import com.habitrpg.android.habitica.models.user.User
|
||||
import com.habitrpg.shared.habitica.models.responses.TaskDirectionData
|
||||
import com.habitrpg.shared.habitica.models.tasks.TaskType
|
||||
import com.habitrpg.shared.habitica.models.tasks.TasksOrder
|
||||
import io.kotest.common.ExperimentalKotest
|
||||
import io.kotest.core.spec.style.WordSpec
|
||||
import io.kotest.framework.concurrency.eventually
|
||||
import io.kotest.matchers.shouldBe
|
||||
import io.mockk.clearAllMocks
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.slot
|
||||
import io.mockk.spyk
|
||||
import io.mockk.verify
|
||||
import io.reactivex.rxjava3.core.Flowable
|
||||
import io.reactivex.subscribers.TestSubscriber
|
||||
import io.realm.Realm
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import java.util.UUID
|
||||
|
||||
@OptIn(ExperimentalKotest::class)
|
||||
|
|
@ -52,12 +52,10 @@ class TaskRepositoryImplTest : WordSpec({
|
|||
"retrieveTasks" should {
|
||||
"save tasks locally" {
|
||||
val list = TaskList()
|
||||
every { apiClient.tasks } returns Flowable.just(list)
|
||||
coEvery { apiClient.getTasks() } returns list
|
||||
every { localRepository.saveTasks("", any(), any()) } returns Unit
|
||||
val order = TasksOrder()
|
||||
val subscriber = TestSubscriber<TaskList>()
|
||||
repository.retrieveTasks("", order).subscribe(subscriber)
|
||||
subscriber.assertComplete()
|
||||
repository.retrieveTasks("", order)
|
||||
verify { localRepository.saveTasks("", order, list) }
|
||||
}
|
||||
}
|
||||
|
|
@ -70,32 +68,25 @@ class TaskRepositoryImplTest : WordSpec({
|
|||
user.stats = Stats()
|
||||
}
|
||||
"debounce" {
|
||||
every { apiClient.postTaskDirection(any(), "up") } returns Flowable.just(
|
||||
TaskDirectionData()
|
||||
)
|
||||
repository.taskChecked(user, task, true, false, null).subscribe()
|
||||
repository.taskChecked(user, task, true, false, null).subscribe()
|
||||
verify(exactly = 1) { apiClient.postTaskDirection(any(), any()) }
|
||||
coEvery { apiClient.postTaskDirection(any(), "up") } returns TaskDirectionData()
|
||||
repository.taskChecked(user, task, true, false, null)
|
||||
repository.taskChecked(user, task, true, false, null)
|
||||
coVerify(exactly = 1) { apiClient.postTaskDirection(any(), any()) }
|
||||
}
|
||||
"get user if not passed" {
|
||||
every { apiClient.postTaskDirection(any(), "up") } returns Flowable.just(
|
||||
TaskDirectionData()
|
||||
)
|
||||
every { localRepository.getUserFlowable("") } returns Flowable.just(user)
|
||||
coEvery { apiClient.postTaskDirection(any(), "up") } returns TaskDirectionData()
|
||||
coEvery { localRepository.getUser("") } returns flowOf(user)
|
||||
repository.taskChecked(null, task, true, false, null)
|
||||
eventually(5000) {
|
||||
localRepository.getUserFlowable("")
|
||||
localRepository.getUser("")
|
||||
}
|
||||
}
|
||||
"does not update user for team tasks" {
|
||||
val data = TaskDirectionData()
|
||||
data.lvl = 0
|
||||
every { apiClient.postTaskDirection(any(), "up") } returns Flowable.just(data)
|
||||
val subscriber = TestSubscriber<TaskScoringResult>()
|
||||
repository.taskChecked(user, task, true, false, null).subscribe(subscriber)
|
||||
subscriber.assertComplete()
|
||||
coEvery { apiClient.postTaskDirection(any(), "up") } returns data
|
||||
repository.taskChecked(user, task, true, false, null)
|
||||
verify(exactly = 0) { user.stats }
|
||||
subscriber.values().first().level shouldBe null
|
||||
}
|
||||
"builds task result correctly" {
|
||||
val data = TaskDirectionData()
|
||||
|
|
@ -106,67 +97,53 @@ class TaskRepositoryImplTest : WordSpec({
|
|||
user.stats?.lvl = 10
|
||||
user.stats?.hp = 8.0
|
||||
user.stats?.mp = 4.0
|
||||
every { apiClient.postTaskDirection(any(), "up") } returns Flowable.just(data)
|
||||
val subscriber = TestSubscriber<TaskScoringResult>()
|
||||
repository.taskChecked(user, task, true, false, null).subscribe(subscriber)
|
||||
subscriber.assertComplete()
|
||||
subscriber.values().first().level shouldBe 10
|
||||
subscriber.values().first().healthDelta shouldBe 12.0
|
||||
subscriber.values().first().manaDelta shouldBe 26.0
|
||||
subscriber.values().first().hasLeveledUp shouldBe false
|
||||
coEvery { apiClient.postTaskDirection(any(), "up") } returns data
|
||||
val result = repository.taskChecked(user, task, true, false, null)
|
||||
result?.level shouldBe 10
|
||||
result?.healthDelta shouldBe 12.0
|
||||
result?.manaDelta shouldBe 26.0
|
||||
result?.hasLeveledUp shouldBe false
|
||||
}
|
||||
"set hasLeveledUp correctly" {
|
||||
val subscriber = TestSubscriber<TaskScoringResult>()
|
||||
val data = TaskDirectionData()
|
||||
data.lvl = 11
|
||||
user.stats?.lvl = 10
|
||||
every { apiClient.postTaskDirection(any(), "up") } returns Flowable.just(data)
|
||||
repository.taskChecked(user, task, true, false, null).subscribe(subscriber)
|
||||
|
||||
subscriber.assertComplete()
|
||||
subscriber.values().first().level shouldBe 11
|
||||
subscriber.values().first().hasLeveledUp shouldBe true
|
||||
coEvery { apiClient.postTaskDirection(any(), "up") } returns data
|
||||
val result = repository.taskChecked(user, task, true, false, null)
|
||||
result?.level shouldBe 11
|
||||
result?.hasLeveledUp shouldBe true
|
||||
}
|
||||
"handle stats not being there" {
|
||||
val subscriber = TestSubscriber<TaskScoringResult>()
|
||||
val data = TaskDirectionData()
|
||||
data.lvl = 1
|
||||
user.stats = null
|
||||
every { apiClient.postTaskDirection(any(), "up") } returns Flowable.just(data)
|
||||
repository.taskChecked(user, task, true, false, null).subscribe(subscriber)
|
||||
subscriber.assertComplete()
|
||||
coEvery { apiClient.postTaskDirection(any(), "up") } returns data
|
||||
repository.taskChecked(user, task, true, false, null)
|
||||
}
|
||||
"update daily streak" {
|
||||
val subscriber = TestSubscriber<TaskScoringResult>()
|
||||
val data = TaskDirectionData()
|
||||
data.delta = 1.0f
|
||||
data.lvl = 1
|
||||
task.type = TaskType.DAILY
|
||||
task.value = 0.0
|
||||
every { apiClient.postTaskDirection(any(), "up") } returns Flowable.just(data)
|
||||
repository.taskChecked(user, task, true, false, null).subscribe(subscriber)
|
||||
|
||||
subscriber.assertComplete()
|
||||
coEvery { apiClient.postTaskDirection(any(), "up") } returns data
|
||||
repository.taskChecked(user, task, true, false, null)
|
||||
task.streak shouldBe 1
|
||||
task.completed shouldBe true
|
||||
}
|
||||
"update habit counter" {
|
||||
val subscriber = TestSubscriber<TaskScoringResult>()
|
||||
val data = TaskDirectionData()
|
||||
data.delta = 1.0f
|
||||
data.lvl = 1
|
||||
task.type = TaskType.HABIT
|
||||
task.value = 0.0
|
||||
every { apiClient.postTaskDirection(any(), "up") } returns Flowable.just(data)
|
||||
repository.taskChecked(user, task, true, false, null).subscribe(subscriber)
|
||||
subscriber.assertComplete()
|
||||
coEvery { apiClient.postTaskDirection(any(), "up") } returns data
|
||||
repository.taskChecked(user, task, true, false, null)
|
||||
task.counterUp shouldBe 1
|
||||
|
||||
data.delta = -10.0f
|
||||
every { apiClient.postTaskDirection(any(), "down") } returns Flowable.just(data)
|
||||
val downSubscriber = TestSubscriber<TaskScoringResult>()
|
||||
repository.taskChecked(user, task, false, true, null).subscribe(downSubscriber)
|
||||
downSubscriber.assertComplete()
|
||||
coEvery { apiClient.postTaskDirection(any(), "down") } returns data
|
||||
repository.taskChecked(user, task, false, true, null)
|
||||
task.counterUp shouldBe 1
|
||||
task.counterDown shouldBe 1
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue