mirror of
https://github.com/sudoxnym/habitica-android.git
synced 2026-07-14 02:01:56 +00:00
Handle april fools. Fixes #1109
This commit is contained in:
parent
76332b74ab
commit
81a9de01b9
8 changed files with 114 additions and 167 deletions
|
|
@ -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"
|
||||
}
|
||||
|
||||
|
|
|
|||
20
Habitica/res/xml/remote_config_defaults.xml
Normal file
20
Habitica/res/xml/remote_config_defaults.xml
Normal 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 -->
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -105,7 +105,7 @@ public class AppModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
RemoteConfigManager providesRemoteConfiigManager(Context context) {
|
||||
return new RemoteConfigManager(context);
|
||||
RemoteConfigManager providesRemoteConfiigManager() {
|
||||
return new RemoteConfigManager();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 = ""
|
||||
|
|
|
|||
Loading…
Reference in a new issue