Handle april fools. Fixes #1109

This commit is contained in:
Phillip Thelen 2019-03-04 11:58:10 +01:00
parent 76332b74ab
commit 81a9de01b9
8 changed files with 114 additions and 167 deletions

View file

@ -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"
}

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- START xml_defaults -->
<defaultsMap>
<entry>
<key>maxChatLength</key>
<value>3000</value>
</entry>
<entry>
<key>enableGiftOneGetOne</key>
<value>false</value>
</entry>
<entry>
<key>shopSpriteSuffix</key>
</entry>
<entry>
<key>spriteSubstitutions</key>
<value>{}</value>
</entry>
</defaultsMap>
<!-- END xml_defaults -->

View file

@ -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

View file

@ -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<String, String, String> {
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());
}
}
}

View file

@ -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<String, Map<String, String>> {
val type = object : TypeToken<Map<String, Map<String, String>>>() {}.type
return Gson().fromJson(remoteConfig.getString("spriteSubstitutions"), type)
}
}

View file

@ -105,7 +105,7 @@ public class AppModule {
@Provides
@Singleton
RemoteConfigManager providesRemoteConfiigManager(Context context) {
return new RemoteConfigManager(context);
RemoteConfigManager providesRemoteConfiigManager() {
return new RemoteConfigManager();
}
}

View file

@ -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<LayerType, String> {
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<String, String>?, name: String): String {
for (key in substitutions?.keys ?: arrayListOf<String>()) {
if (name.contains(key)) {
return substitutions?.get(key) ?: name
}
}
return name
}
@Suppress("ReturnCount")
private fun getAvatarLayerMap(avatar: Avatar): EnumMap<AvatarView.LayerType, String> {
private fun getAvatarLayerMap(avatar: Avatar, substitutions: Map<String, Map<String, String>>): EnumMap<AvatarView.LayerType, String> {
val layerMap = EnumMap<AvatarView.LayerType, String>(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

View file

@ -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 = ""