From 81a9de01b989742bed3457c6512414b893729433 Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Mon, 4 Mar 2019 11:58:10 +0100 Subject: [PATCH] Handle april fools. Fixes #1109 --- Habitica/build.gradle | 3 +- Habitica/res/xml/remote_config_defaults.xml | 20 +++ .../habitica/HabiticaBaseApplication.kt | 16 ++ .../habitica/helpers/RemoteConfigManager.java | 155 ------------------ .../habitica/helpers/RemoteConfigManager.kt | 45 +++++ .../android/habitica/modules/AppModule.java | 4 +- .../android/habitica/ui/AvatarView.kt | 36 +++- .../habitica/ui/views/social/ChatBarView.kt | 2 +- 8 files changed, 114 insertions(+), 167 deletions(-) create mode 100644 Habitica/res/xml/remote_config_defaults.xml delete mode 100644 Habitica/src/main/java/com/habitrpg/android/habitica/helpers/RemoteConfigManager.java create mode 100644 Habitica/src/main/java/com/habitrpg/android/habitica/helpers/RemoteConfigManager.kt diff --git a/Habitica/build.gradle b/Habitica/build.gradle index 1a361209b..b29275a22 100644 --- a/Habitica/build.gradle +++ b/Habitica/build.gradle @@ -118,6 +118,7 @@ dependencies { //Push Notifications implementation 'com.google.firebase:firebase-core:16.0.7' implementation 'com.google.firebase:firebase-messaging:17.4.0' + implementation 'com.google.firebase:firebase-config:16.3.0' implementation 'com.google.android.gms:play-services-auth:16.0.1' implementation 'io.realm:android-adapters:3.1.0' implementation(project(':seeds-sdk')) { @@ -147,7 +148,7 @@ android { buildConfigField "String", "STORE", "\"google\"" multiDexEnabled true - versionCode 2067 + versionCode 2068 versionName "1.8" } diff --git a/Habitica/res/xml/remote_config_defaults.xml b/Habitica/res/xml/remote_config_defaults.xml new file mode 100644 index 000000000..1788d298b --- /dev/null +++ b/Habitica/res/xml/remote_config_defaults.xml @@ -0,0 +1,20 @@ + + + + + maxChatLength + 3000 + + + enableGiftOneGetOne + false + + + shopSpriteSuffix + + + spriteSubstitutions + {} + + + \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/HabiticaBaseApplication.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/HabiticaBaseApplication.kt index 97fa85347..df79bc2a2 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/HabiticaBaseApplication.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/HabiticaBaseApplication.kt @@ -17,6 +17,8 @@ import com.amplitude.api.Amplitude import com.amplitude.api.Identify import com.facebook.drawee.backends.pipeline.Fresco import com.facebook.imagepipeline.core.ImagePipelineConfig +import com.google.firebase.remoteconfig.FirebaseRemoteConfig +import com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings import com.habitrpg.android.habitica.api.HostConfig import com.habitrpg.android.habitica.components.AppComponent import com.habitrpg.android.habitica.data.ApiClient @@ -79,6 +81,7 @@ abstract class HabiticaBaseApplication : MultiDexApplication() { } setupRealm() setupDagger() + setupRemoteConfig() refWatcher = LeakCanary.install(this) setupInstabug() createBillingAndCheckout() @@ -200,6 +203,19 @@ abstract class HabiticaBaseApplication : MultiDexApplication() { billing.notNull { checkout = Checkout.forApplication(it) } } + private fun setupRemoteConfig() { + val remoteConfig = FirebaseRemoteConfig.getInstance() + val configSettings = FirebaseRemoteConfigSettings.Builder() + .setDeveloperModeEnabled(BuildConfig.DEBUG) + .build() + remoteConfig.setConfigSettings(configSettings) + remoteConfig.setDefaults(R.xml.remote_config_defaults) + remoteConfig.fetch(if (BuildConfig.DEBUG) 0 else 3600) + .addOnCompleteListener { + remoteConfig.activateFetched() + } + } + companion object { var component: AppComponent? = null diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/RemoteConfigManager.java b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/RemoteConfigManager.java deleted file mode 100644 index 7329ff2b9..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/RemoteConfigManager.java +++ /dev/null @@ -1,155 +0,0 @@ -package com.habitrpg.android.habitica.helpers; - -import android.content.Context; -import android.os.AsyncTask; -import androidx.preference.PreferenceManager; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.URL; -import java.net.URLConnection; - -public class RemoteConfigManager { - - private Context context; - private Boolean enableRepeatbles = false; - private Boolean enableNewShops = false; - private String shopSpriteSuffix = ""; - private Integer maxChatLength = 3000; - private Boolean enableGiftOneGetOne = false; - private String REMOTE_STRING_KEY = "remote-string"; - - public RemoteConfigManager(Context context) { - this.context = context; - loadFromPreferences(); - new DownloadFileFromURL().execute("https://s3.amazonaws.com/habitica-assets/mobileApp/endpoint/config-android.json"); - } - - public Boolean repeatablesAreEnabled() { - return enableRepeatbles; - } - - public Boolean newShopsEnabled() { - return enableNewShops; - } - - public String shopSpriteSuffix() { - return shopSpriteSuffix; - } - - public Integer maxChatLength() { return maxChatLength; } - - public boolean enableGiftOneGetOne() { return enableGiftOneGetOne; } - - private void loadFromPreferences () { - String storedPreferences = PreferenceManager.getDefaultSharedPreferences(context) - .getString(REMOTE_STRING_KEY, ""); - - if (storedPreferences.isEmpty()) { - return; - } - - parseConfig(storedPreferences); - } - - private void parseConfig(String jsonString) { - try { - JSONObject obj = new JSONObject(jsonString); - enableRepeatbles = obj.getBoolean("enableRepeatables"); - if (obj.has("enableNewShops")) { - enableNewShops = obj.getBoolean("enableNewShops"); - } - if (obj.has("shopSpriteSuffix")) { - shopSpriteSuffix = obj.getString("shopSpriteSuffix"); - } - if (obj.has("maxChatLength")) { - maxChatLength = obj.getInt("maxChatLength"); - } - if (obj.has("enableGiftOneGetOne")) { - enableGiftOneGetOne = obj.getBoolean("enableGiftOneGetOne"); - } - } catch (JSONException e) { - e.printStackTrace(); - } - } - - - private class DownloadFileFromURL extends AsyncTask { - private String filename = "config.json"; - - @Override - protected void onPreExecute() { - super.onPreExecute(); - } - - @Override - protected String doInBackground(String ...fileUrl) { - int count; - try { - URL url = new URL(fileUrl[0]); - URLConnection conection = url.openConnection(); - conection.connect(); - - int lenghtOfFile = conection.getContentLength(); - - InputStream input = new BufferedInputStream(url.openStream(), - 8192); - - OutputStream output = context.openFileOutput(filename, Context.MODE_PRIVATE); - - byte data[] = new byte[1024]; - - long total = 0; - - while ((count = input.read(data)) != -1) { - total += count; - publishProgress("" + (int) ((total * 100) / lenghtOfFile)); - output.write(data, 0, count); - } - - output.flush(); - - output.close(); - input.close(); - } catch (Exception e) { - e.printStackTrace(); - } - - return null; - } - - @Override - protected void onPostExecute(String file_url) { - File file = new File(context.getFilesDir(), filename); - StringBuilder text = new StringBuilder(); - - try { - BufferedReader br = new BufferedReader(new FileReader(file)); - String line; - - while ((line = br.readLine()) != null) { - text.append(line); - text.append('\n'); - } - br.close(); - } - catch (IOException e) { - e.printStackTrace(); - } - - PreferenceManager.getDefaultSharedPreferences(context) - .edit().putString(REMOTE_STRING_KEY, text.toString()).apply(); - - parseConfig(text.toString()); - } - - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/RemoteConfigManager.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/RemoteConfigManager.kt new file mode 100644 index 000000000..a1b6b2713 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/RemoteConfigManager.kt @@ -0,0 +1,45 @@ +package com.habitrpg.android.habitica.helpers + +import android.content.Context +import android.os.AsyncTask +import androidx.preference.PreferenceManager +import com.google.firebase.remoteconfig.FirebaseRemoteConfig +import com.google.gson.Gson +import com.google.gson.JsonObject +import com.google.gson.reflect.TypeToken +import okhttp3.OkHttpClient +import okhttp3.Request + +import org.json.JSONException +import org.json.JSONObject +import java.io.* + +class RemoteConfigManager { + + private val remoteConfig = FirebaseRemoteConfig.getInstance() + + fun repeatablesAreEnabled(): Boolean { + return true + } + + fun newShopsEnabled(): Boolean { + return true + } + + fun shopSpriteSuffix(): String { + return remoteConfig.getString("shopSpriteSuffix") + } + + fun maxChatLength(): Long { + return remoteConfig.getLong("maxChatLength") + } + + fun enableGiftOneGetOne(): Boolean { + return remoteConfig.getBoolean("enableGiftOneGetOne") + } + + fun spriteSubstitutions(): Map> { + val type = object : TypeToken>>() {}.type + return Gson().fromJson(remoteConfig.getString("spriteSubstitutions"), type) + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/modules/AppModule.java b/Habitica/src/main/java/com/habitrpg/android/habitica/modules/AppModule.java index ba6c09b27..df52b40c9 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/modules/AppModule.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/modules/AppModule.java @@ -105,7 +105,7 @@ public class AppModule { @Provides @Singleton - RemoteConfigManager providesRemoteConfiigManager(Context context) { - return new RemoteConfigManager(context); + RemoteConfigManager providesRemoteConfiigManager() { + return new RemoteConfigManager(); } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarView.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarView.kt index 63401d1b2..7ba54ee08 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarView.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarView.kt @@ -17,6 +17,7 @@ import com.facebook.drawee.view.MultiDraweeHolder import com.facebook.imagepipeline.image.ImageInfo import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.extensions.notNull +import com.habitrpg.android.habitica.helpers.RemoteConfigManager import com.habitrpg.android.habitica.models.Avatar import java.util.* import java.util.concurrent.atomic.AtomicInteger @@ -153,7 +154,8 @@ class AvatarView : View { } private fun getLayerMap(avatar: Avatar, resetHasAttributes: Boolean): Map { - val layerMap = getAvatarLayerMap(avatar) + val substitutions = RemoteConfigManager().spriteSubstitutions() + val layerMap = getAvatarLayerMap(avatar, substitutions) if (resetHasAttributes) { hasPet = false @@ -161,21 +163,24 @@ class AvatarView : View { hasBackground = hasMount } - val mountName = avatar.currentMount - if (showMount && !TextUtils.isEmpty(mountName)) { + var mountName = avatar.currentMount + if (showMount && mountName?.isNotEmpty() == true) { + mountName = substituteOrReturn(substitutions["mounts"], mountName) layerMap[LayerType.MOUNT_BODY] = "Mount_Body_$mountName" layerMap[LayerType.MOUNT_HEAD] = "Mount_Head_$mountName" if (resetHasAttributes) hasMount = true } - val petName = avatar.currentPet - if (showPet && !TextUtils.isEmpty(petName)) { + var petName = avatar.currentPet + if (showPet && petName?.isNotEmpty() == true) { + petName = substituteOrReturn(substitutions["pets"], petName) layerMap[LayerType.PET] = "Pet-$petName" if (resetHasAttributes) hasPet = true } - val backgroundName = avatar.preferences?.background - if (showBackground && !TextUtils.isEmpty(backgroundName)) { + var backgroundName = avatar.preferences?.background + if (showBackground && backgroundName?.isNotEmpty() == true) { + backgroundName = substituteOrReturn(substitutions["backgrounds"], backgroundName) layerMap[LayerType.BACKGROUND] = "background_$backgroundName" if (resetHasAttributes) hasBackground = true } @@ -187,8 +192,17 @@ class AvatarView : View { return layerMap } + private fun substituteOrReturn(substitutions: Map?, name: String): String { + for (key in substitutions?.keys ?: arrayListOf()) { + if (name.contains(key)) { + return substitutions?.get(key) ?: name + } + } + return name + } + @Suppress("ReturnCount") - private fun getAvatarLayerMap(avatar: Avatar): EnumMap { + private fun getAvatarLayerMap(avatar: Avatar, substitutions: Map>): EnumMap { val layerMap = EnumMap(AvatarView.LayerType::class.java) if (!avatar.isValid) { @@ -228,6 +242,12 @@ class AvatarView : View { } } + val substitutedVisualBuff = substitutions["visualBuff"]?.get("full") + if (substitutedVisualBuff != null) { + layerMap[AvatarView.LayerType.VISUAL_BUFF] = substitutedVisualBuff + hasVisualBuffs = true + } + if (!hasVisualBuffs) { if (!TextUtils.isEmpty(prefs.chair)) { layerMap[AvatarView.LayerType.CHAIR] = prefs.chair diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/ChatBarView.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/ChatBarView.kt index 44a6628ab..14253bb71 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/ChatBarView.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/ChatBarView.kt @@ -32,7 +32,7 @@ class ChatBarView : FrameLayout { private val spacing: Space by bindView(R.id.spacing) private var navBarAccountedHeightCalculated = false - internal var maxChatLength = 3000 + internal var maxChatLength = 3000L var sendAction: ((String) -> Unit)? = null var autocompleteContext: String = ""