mirror of
https://github.com/sudoxnym/habitica-android.git
synced 2026-08-01 03:30:34 +00:00
Implement secret feature
This commit is contained in:
parent
07dfdd3f36
commit
abc930d217
10 changed files with 108 additions and 30 deletions
|
|
@ -150,8 +150,8 @@ android {
|
|||
buildConfigField "String", "TESTING_LEVEL", "\"production\""
|
||||
resConfigs "en", "bg", "de", "en-rGB", "es", "fr", "hr-rHR", "in", "it", "iw", "ja", "ko", "lt", "nl", "pl", "pt-rBR", "pt-rPT", "ru", "tr", "zh", "zh-rTW"
|
||||
|
||||
versionCode 2868
|
||||
versionName "3.2.1"
|
||||
versionCode 2871
|
||||
versionName "3.2.2"
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import androidx.preference.PreferenceManager
|
|||
import com.habitrpg.android.habitica.data.ApiClient
|
||||
import com.habitrpg.android.habitica.data.ContentRepository
|
||||
import com.habitrpg.android.habitica.data.local.ContentLocalRepository
|
||||
import com.habitrpg.android.habitica.helpers.AprilFoolsHandler
|
||||
import com.habitrpg.android.habitica.models.ContentResult
|
||||
import com.habitrpg.android.habitica.models.WorldState
|
||||
import com.habitrpg.android.habitica.models.inventory.SpecialItem
|
||||
|
|
@ -43,6 +44,11 @@ abstract class ContentRepositoryImpl<T : ContentLocalRepository>(localRepository
|
|||
lastWorldStateSync = now
|
||||
apiClient.worldState.doOnNext {
|
||||
localRepository.saveWorldState(it)
|
||||
for (event in it.events) {
|
||||
if (event.aprilFools != null && event.isCurrentlyActive) {
|
||||
AprilFoolsHandler.handle(event.aprilFools)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Flowable.empty()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
package com.habitrpg.android.habitica.helpers
|
||||
|
||||
import com.habitrpg.android.habitica.helpers.postProcessors.InvertPostProcessor
|
||||
import com.habitrpg.android.habitica.ui.AvatarView
|
||||
|
||||
class AprilFoolsHandler {
|
||||
|
||||
companion object {
|
||||
fun handle(name: String?) {
|
||||
when(name) {
|
||||
"invert" -> invertFools()
|
||||
}
|
||||
}
|
||||
|
||||
private fun invertFools() {
|
||||
AvatarView.postProcessors[AvatarView.LayerType.PET] = { InvertPostProcessor() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package com.habitrpg.android.habitica.helpers.postProcessors
|
||||
|
||||
import android.graphics.*
|
||||
import com.facebook.cache.common.CacheKey
|
||||
import com.facebook.cache.common.SimpleCacheKey
|
||||
import com.facebook.imagepipeline.request.BasePostprocessor
|
||||
|
||||
|
||||
class InvertPostProcessor: BasePostprocessor() {
|
||||
|
||||
override fun getName(): String {
|
||||
return "invertPostProcessor"
|
||||
}
|
||||
|
||||
|
||||
override fun process(bitmap: Bitmap) {
|
||||
val canvas = Canvas(bitmap)
|
||||
val paint = Paint()
|
||||
|
||||
val matrixGrayscale = ColorMatrix()
|
||||
matrixGrayscale.setSaturation(0f)
|
||||
|
||||
val matrixInvert = ColorMatrix()
|
||||
matrixInvert.set(floatArrayOf(
|
||||
-1.0f, 0.0f, 0.0f, 0.0f, 255.0f,
|
||||
0.0f, -1.0f, 0.0f, 0.0f, 255.0f,
|
||||
0.0f, 0.0f, -1.0f, 0.0f, 255.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f, 0.0f
|
||||
))
|
||||
matrixInvert.preConcat(matrixGrayscale)
|
||||
|
||||
val filter = ColorMatrixColorFilter(matrixInvert)
|
||||
paint.colorFilter = filter
|
||||
|
||||
canvas.drawBitmap(bitmap, 0f, 0f, paint)
|
||||
}
|
||||
|
||||
override fun getPostprocessorCacheKey(): CacheKey {
|
||||
return SimpleCacheKey("0")
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.habitrpg.android.habitica.models
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import com.habitrpg.android.habitica.models.inventory.QuestProgress
|
||||
import com.habitrpg.android.habitica.models.inventory.QuestRageStrike
|
||||
import io.realm.RealmList
|
||||
|
|
@ -16,5 +17,6 @@ open class WorldState: RealmObject() {
|
|||
var npcImageSuffix: String? = null
|
||||
|
||||
var currentEvent: WorldStateEvent? = null
|
||||
@SerializedName("currentEventList")
|
||||
var events: RealmList<WorldStateEvent> = RealmList()
|
||||
}
|
||||
|
|
@ -7,6 +7,12 @@ import io.realm.annotations.PrimaryKey
|
|||
import java.util.*
|
||||
|
||||
open class WorldStateEvent: RealmObject(), BaseObject {
|
||||
val isCurrentlyActive: Boolean
|
||||
get() {
|
||||
val now = Date()
|
||||
return (start?.before(now) == true) && (end?.after(now) == true)
|
||||
}
|
||||
|
||||
@PrimaryKey
|
||||
@SerializedName("event")
|
||||
var eventKey: String? = null
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import android.content.Context
|
|||
import android.graphics.*
|
||||
import android.graphics.drawable.Animatable
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.net.Uri
|
||||
import android.text.TextUtils
|
||||
import android.util.AttributeSet
|
||||
import android.util.Log
|
||||
|
|
@ -15,6 +16,8 @@ import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder
|
|||
import com.facebook.drawee.view.DraweeHolder
|
||||
import com.facebook.drawee.view.MultiDraweeHolder
|
||||
import com.facebook.imagepipeline.image.ImageInfo
|
||||
import com.facebook.imagepipeline.request.BasePostprocessor
|
||||
import com.facebook.imagepipeline.request.ImageRequestBuilder
|
||||
import com.habitrpg.android.habitica.BuildConfig
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.helpers.AppConfigManager
|
||||
|
|
@ -60,7 +63,6 @@ class AvatarView : View {
|
|||
}
|
||||
private var lastSubstitutionCheck: Date? = null
|
||||
|
||||
|
||||
private val originalRect: Rect
|
||||
get() = if (showMount || showPet) FULL_HERO_RECT else if (showBackground) COMPACT_HERO_RECT else HERO_ONLY_RECT
|
||||
|
||||
|
|
@ -132,8 +134,14 @@ class AvatarView : View {
|
|||
draweeHolder.topLevelDrawable?.callback = this
|
||||
multiDraweeHolder.add(draweeHolder)
|
||||
|
||||
val uri = Uri.parse(IMAGE_URI_ROOT + DataBindingUtils.getFullFilename(layerName, null))
|
||||
var request = ImageRequestBuilder.newBuilderWithSource(uri)
|
||||
postProcessors[layerKey]?.let {
|
||||
request = request.setPostprocessor(it())
|
||||
}
|
||||
|
||||
val controller = Fresco.newDraweeControllerBuilder()
|
||||
.setUri(IMAGE_URI_ROOT + DataBindingUtils.getFullFilename(layerName, null))
|
||||
.setImageRequest(request.build())
|
||||
.setControllerListener(object : BaseControllerListener<ImageInfo>() {
|
||||
override fun onFinalImageSet(
|
||||
id: String?,
|
||||
|
|
@ -252,6 +260,7 @@ class AvatarView : View {
|
|||
hasVisualBuffs = true
|
||||
}
|
||||
|
||||
val hair = prefs.hair
|
||||
if (!hasVisualBuffs) {
|
||||
if (!TextUtils.isEmpty(prefs.chair)) {
|
||||
layerMap[LayerType.CHAIR] = prefs.chair
|
||||
|
|
@ -288,7 +297,6 @@ class AvatarView : View {
|
|||
layerMap[LayerType.SHIRT] = prefs.size + "_shirt_" + prefs.shirt
|
||||
layerMap[LayerType.HEAD_0] = "head_0"
|
||||
|
||||
val hair = prefs.hair
|
||||
if (hair != null) {
|
||||
val hairColor = hair.color
|
||||
|
||||
|
|
@ -304,17 +312,11 @@ class AvatarView : View {
|
|||
if (hair.isAvailable(hair.beard)) {
|
||||
layerMap[LayerType.HAIR_BEARD] = "hair_beard_" + hair.beard + "_" + hairColor
|
||||
}
|
||||
if (hair.isAvailable(hair.flower)) {
|
||||
layerMap[LayerType.HAIR_FLOWER] = "hair_flower_" + hair.flower
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val hair = prefs.hair
|
||||
}
|
||||
|
||||
// Show flower all the time!
|
||||
if (hair != null && hair.isAvailable(hair.flower)) {
|
||||
layerMap[LayerType.HAIR_FLOWER] = "hair_flower_" + hair.flower
|
||||
}
|
||||
if (hair != null && hair.isAvailable(hair.flower)) {
|
||||
layerMap[LayerType.HAIR_FLOWER] = "hair_flower_" + hair.flower
|
||||
}
|
||||
|
||||
return layerMap
|
||||
|
|
@ -418,7 +420,7 @@ class AvatarView : View {
|
|||
|
||||
val equals = currentLayers != null && currentLayers == newLayerMap
|
||||
|
||||
if (!equals) {
|
||||
if (!equals || postProcessors.isNotEmpty()) {
|
||||
multiDraweeHolder.clear()
|
||||
numberLayersInProcess.set(0)
|
||||
}
|
||||
|
|
@ -530,5 +532,6 @@ class AvatarView : View {
|
|||
private val COMPACT_HERO_RECT = Rect(0, 0, 114, 114)
|
||||
private val HERO_ONLY_RECT = Rect(0, 0, 90, 90)
|
||||
|
||||
val postProcessors: MutableMap<LayerType, (() -> BasePostprocessor)> = mutableMapOf()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -634,17 +634,18 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction {
|
|||
|
||||
protected fun retrieveUser(forced: Boolean = false) {
|
||||
if (hostConfig.hasAuthentication()) {
|
||||
compositeSubscription.add(this.userRepository.retrieveUser(true, forced)
|
||||
.doOnNext { user1 ->
|
||||
FirebaseAnalytics.getInstance(this).setUserProperty("has_party", if (user1.party?.id?.isNotEmpty() == true) "true" else "false")
|
||||
FirebaseAnalytics.getInstance(this).setUserProperty("is_subscribed", if (user1.isSubscribed) "true" else "false")
|
||||
pushNotificationManager.setUser(user1)
|
||||
pushNotificationManager.addPushDeviceUsingStoredToken()
|
||||
}
|
||||
.flatMap { userRepository.retrieveTeamPlans() }
|
||||
.flatMap { contentRepository.retrieveContent(this,false) }
|
||||
.flatMap { contentRepository.retrieveWorldState(this) }
|
||||
.subscribe({ }, RxErrorHandler.handleEmptyError()))
|
||||
compositeSubscription.add(
|
||||
contentRepository.retrieveWorldState(this)
|
||||
.flatMap { userRepository.retrieveUser(true, forced) }
|
||||
.doOnNext { user1 ->
|
||||
FirebaseAnalytics.getInstance(this).setUserProperty("has_party", if (user1.party?.id?.isNotEmpty() == true) "true" else "false")
|
||||
FirebaseAnalytics.getInstance(this).setUserProperty("is_subscribed", if (user1.isSubscribed) "true" else "false")
|
||||
pushNotificationManager.setUser(user1)
|
||||
pushNotificationManager.addPushDeviceUsingStoredToken()
|
||||
}
|
||||
.flatMap { userRepository.retrieveTeamPlans() }
|
||||
.flatMap { contentRepository.retrieveContent(this) }
|
||||
.subscribe({ }, RxErrorHandler.handleEmptyError()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,9 +56,9 @@ class WorldStateSerialization: JsonDeserializer<WorldState> {
|
|||
if (event != null) {
|
||||
state.currentEvent = context?.deserialize(event, WorldStateEvent::class.java)
|
||||
}
|
||||
if (json.asJsonObject.has("events")) {
|
||||
if (json.asJsonObject.has("currentEventList")) {
|
||||
val events = RealmList<WorldStateEvent>()
|
||||
for (element in json.asJsonObject.getAsJsonArray("events")) {
|
||||
for (element in json.asJsonObject.getAsJsonArray("currentEventList")) {
|
||||
context?.deserialize<WorldStateEvent>(element, WorldStateEvent::class.java)?.let { events.add(it) }
|
||||
}
|
||||
state.events = events
|
||||
|
|
|
|||
|
|
@ -14,12 +14,12 @@ buildscript {
|
|||
classpath 'com.android.tools.build:gradle:4.1.2'
|
||||
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
|
||||
classpath 'com.google.gms:google-services:4.3.5'
|
||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.5.0'
|
||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.5.1'
|
||||
classpath "io.realm:realm-gradle-plugin:10.3.0"
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.1.0"
|
||||
classpath "android.arch.navigation:navigation-safe-args-gradle-plugin:1.0.0"
|
||||
classpath 'com.google.firebase:perf-plugin:1.3.4'
|
||||
classpath 'com.google.firebase:perf-plugin:1.3.5'
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue