Code cleanup

This commit is contained in:
Phillip Thelen 2018-07-25 12:40:50 +02:00
parent d4a2cf3e3d
commit 62f03a9888
68 changed files with 753 additions and 852 deletions

View file

@ -124,6 +124,8 @@ dependencies {
exclude group: 'com.android.support', module: 'multidex'
}
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.android.support:multidex:1.0.3'
}
@ -135,6 +137,7 @@ android {
applicationId "com.habitrpg.android.habitica"
vectorDrawables.useSupportLibrary = true
buildConfigField "String", "STORE", "\"google\""
multiDexEnabled true
}
lintOptions {
@ -161,7 +164,7 @@ android {
release {
signingConfig signingConfigs.release
debuggable false
multiDexEnabled false
multiDexEnabled true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
resValue "string", "content_provider", "com.habitrpg.android.habitica.fileprovider"

View file

@ -178,3 +178,5 @@
-dontwarn com.viewpagerindicator.**
#-ignorewarnings
-keep class com.google.firebase.provider.FirebaseInitProvider
-keep class com.example.instabug.**

View file

@ -21,7 +21,7 @@
<attr name="showSeedsPromo" format="boolean" />
</declare-styleable>
<declare-styleable name="MaxHeightScrollView">
<declare-styleable name="MaxHeightLinearLayout">
<attr name="maxHeightMultiplier" format="float" />
</declare-styleable>
<declare-styleable name="SubscriptionOptionView">

View file

@ -10,6 +10,7 @@ import android.content.res.Resources
import android.database.DatabaseErrorHandler
import android.database.sqlite.SQLiteDatabase
import android.preference.PreferenceManager
import android.support.multidex.MultiDexApplication
import android.support.v7.app.AppCompatDelegate
import android.util.Log
@ -50,7 +51,7 @@ import io.realm.Realm
import io.realm.RealmConfiguration
//contains all HabiticaApplicationLogic except dagger componentInitialisation
abstract class HabiticaBaseApplication : Application() {
abstract class HabiticaBaseApplication : MultiDexApplication() {
var refWatcher: RefWatcher? = null
@Inject
internal lateinit var lazyApiHelper: ApiClient

View file

@ -1,6 +1,5 @@
package com.habitrpg.android.habitica.api;
import com.habitrpg.android.habitica.models.responses.HabitResponse;
import com.habitrpg.android.habitica.models.responses.MaintenanceResponse;
import io.reactivex.Flowable;
@ -9,9 +8,9 @@ import retrofit2.http.GET;
public interface MaintenanceApiService {
@GET("maintenance-android.json")
Flowable<HabitResponse<MaintenanceResponse>> getMaintenanceStatus();
Flowable<MaintenanceResponse> getMaintenanceStatus();
@GET("deprecation-android.json")
Flowable<HabitResponse<MaintenanceResponse>> getDepricationStatus();
Flowable<MaintenanceResponse> getDepricationStatus();
}

View file

@ -1,14 +0,0 @@
package com.habitrpg.android.habitica.data;
import com.habitrpg.android.habitica.models.ContentResult;
import com.habitrpg.android.habitica.models.WorldState;
import io.reactivex.Flowable;
public interface ContentRepository extends BaseRepository {
Flowable<ContentResult> retrieveContent();
Flowable<ContentResult> retrieveContent(boolean forced);
Flowable<WorldState> retrieveWorldState();
}

View file

@ -0,0 +1,14 @@
package com.habitrpg.android.habitica.data
import com.habitrpg.android.habitica.models.ContentResult
import com.habitrpg.android.habitica.models.WorldState
import io.reactivex.Flowable
interface ContentRepository : BaseRepository {
fun retrieveContent(): Flowable<ContentResult>
fun retrieveContent(forced: Boolean): Flowable<ContentResult>
fun retrieveWorldState(): Flowable<WorldState>
}

View file

@ -1,10 +0,0 @@
package com.habitrpg.android.habitica.data;
import com.habitrpg.android.habitica.models.inventory.Customization;
import io.reactivex.Flowable;
import io.realm.RealmResults;
public interface CustomizationRepository extends ContentRepository {
Flowable<RealmResults<Customization>> getCustomizations(String type, String category, boolean onlyAvailable);
}

View file

@ -0,0 +1,10 @@
package com.habitrpg.android.habitica.data
import com.habitrpg.android.habitica.models.inventory.Customization
import io.reactivex.Flowable
import io.realm.RealmResults
interface CustomizationRepository : ContentRepository {
fun getCustomizations(type: String, category: String?, onlyAvailable: Boolean): Flowable<RealmResults<Customization>>
}

View file

@ -1,11 +0,0 @@
package com.habitrpg.android.habitica.data;
import com.habitrpg.android.habitica.models.FAQArticle;
import io.reactivex.Flowable;
import io.realm.RealmResults;
public interface FAQRepository extends BaseRepository {
Flowable<RealmResults<FAQArticle>> getArticles();
}

View file

@ -0,0 +1,11 @@
package com.habitrpg.android.habitica.data
import com.habitrpg.android.habitica.models.FAQArticle
import io.reactivex.Flowable
import io.realm.RealmResults
interface FAQRepository : BaseRepository {
fun getArticles(): Flowable<RealmResults<FAQArticle>>
}

View file

@ -1,92 +0,0 @@
package com.habitrpg.android.habitica.data;
import com.habitrpg.android.habitica.models.inventory.Egg;
import com.habitrpg.android.habitica.models.inventory.Equipment;
import com.habitrpg.android.habitica.models.inventory.Food;
import com.habitrpg.android.habitica.models.inventory.HatchingPotion;
import com.habitrpg.android.habitica.models.inventory.Item;
import com.habitrpg.android.habitica.models.inventory.Mount;
import com.habitrpg.android.habitica.models.inventory.Pet;
import com.habitrpg.android.habitica.models.inventory.Quest;
import com.habitrpg.android.habitica.models.inventory.QuestContent;
import com.habitrpg.android.habitica.models.responses.BuyResponse;
import com.habitrpg.android.habitica.models.responses.FeedResponse;
import com.habitrpg.android.habitica.models.shops.Shop;
import com.habitrpg.android.habitica.models.shops.ShopItem;
import com.habitrpg.android.habitica.models.user.Items;
import com.habitrpg.android.habitica.models.user.User;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Map;
import io.reactivex.Flowable;
import io.realm.RealmResults;
public interface InventoryRepository extends ContentRepository {
Flowable<QuestContent> getQuestContent(String key);
Flowable<RealmResults<Equipment>> getItems(List<String> searchedKeys);
long getArmoireRemainingCount();
Flowable<RealmResults<ShopItem>> getInAppRewards();
Flowable<List<ShopItem>> retrieveInAppRewards();
Flowable<RealmResults<Equipment>> getOwnedEquipment(@NotNull String type);
Flowable<RealmResults<Equipment>> getOwnedEquipment();
Flowable<? extends RealmResults<? extends Item>> getOwnedItems(Class<? extends Item> itemClass, User user);
Flowable<? extends Map<String, Item>> getOwnedItems(@NotNull User user);
Flowable<Equipment> getEquipment(String key);
Flowable<Equipment> openMysteryItem(User user);
void saveEquipment(Equipment equipment);
Flowable<RealmResults<Mount>> getMounts();
Flowable<RealmResults<Mount>> getMounts(@NotNull String type, @NotNull String group);
Flowable<RealmResults<Mount>> getOwnedMounts();
Flowable<RealmResults<Mount>> getOwnedMounts(@NotNull String animalType, @NotNull String animalGroup);
Flowable<RealmResults<Pet>> getPets();
Flowable<RealmResults<Pet>> getPets(@NotNull String type, @NotNull String group);
Flowable<RealmResults<Pet>> getOwnedPets();
Flowable<RealmResults<Pet>> getOwnedPets(@NotNull String type, @NotNull String group);
void updateOwnedEquipment(User user);
void changeOwnedCount(String type, String key, int amountToAdd);
Flowable<User> sellItem(User user, String type, String key);
Flowable<User> sellItem(User user, Item item);
Flowable<Items> equipGear(User user, String equipment, boolean asCostume);
Flowable<Items> equip(User user, String type, String key);
Flowable<FeedResponse> feedPet(Pet pet, Food food);
Flowable<Items> hatchPet(Egg egg, HatchingPotion hatchingPotion);
Flowable<Quest> inviteToQuest(QuestContent quest);
Flowable<BuyResponse> buyItem(User user, String id, double value);
Flowable<Shop> retrieveShopInventory(String identifier);
Flowable<Shop> retrieveMarketGear();
Flowable<Void> purchaseMysterySet(String categoryIdentifier);
Flowable<Void> purchaseHourglassItem(String purchaseType, String key);
Flowable<Void> purchaseQuest(String key);
Flowable<Void> purchaseItem(String purchaseType, String key);
Flowable<List<ShopItem>> togglePinnedItem(ShopItem item);
}

View file

@ -0,0 +1,87 @@
package com.habitrpg.android.habitica.data
import com.habitrpg.android.habitica.models.inventory.Egg
import com.habitrpg.android.habitica.models.inventory.Equipment
import com.habitrpg.android.habitica.models.inventory.Food
import com.habitrpg.android.habitica.models.inventory.HatchingPotion
import com.habitrpg.android.habitica.models.inventory.Item
import com.habitrpg.android.habitica.models.inventory.Mount
import com.habitrpg.android.habitica.models.inventory.Pet
import com.habitrpg.android.habitica.models.inventory.Quest
import com.habitrpg.android.habitica.models.inventory.QuestContent
import com.habitrpg.android.habitica.models.responses.BuyResponse
import com.habitrpg.android.habitica.models.responses.FeedResponse
import com.habitrpg.android.habitica.models.shops.Shop
import com.habitrpg.android.habitica.models.shops.ShopItem
import com.habitrpg.android.habitica.models.user.Items
import com.habitrpg.android.habitica.models.user.User
import io.reactivex.Flowable
import io.realm.RealmResults
interface InventoryRepository : ContentRepository {
fun getArmoireRemainingCount(): Long
fun getInAppRewards(): Flowable<RealmResults<ShopItem>>
fun getOwnedEquipment(): Flowable<RealmResults<Equipment>>
fun getMounts(): Flowable<RealmResults<Mount>>
fun getOwnedMounts(): Flowable<RealmResults<Mount>>
fun getPets(): Flowable<RealmResults<Pet>>
fun getOwnedPets(): Flowable<RealmResults<Pet>>
fun getQuestContent(key: String): Flowable<QuestContent>
fun getItems(searchedKeys: List<String>): Flowable<RealmResults<Equipment>>
fun retrieveInAppRewards(): Flowable<List<ShopItem>>
fun getOwnedEquipment(type: String): Flowable<RealmResults<Equipment>>
fun getOwnedItems(itemClass: Class<out Item>, user: User?): Flowable<out RealmResults<out Item>>
fun getOwnedItems(user: User): Flowable<out Map<String, Item>>
fun getEquipment(key: String): Flowable<Equipment>
fun openMysteryItem(user: User?): Flowable<Equipment>
fun saveEquipment(equipment: Equipment)
fun getMounts(type: String, group: String): Flowable<RealmResults<Mount>>
fun getOwnedMounts(animalType: String, animalGroup: String): Flowable<RealmResults<Mount>>
fun getPets(type: String, group: String): Flowable<RealmResults<Pet>>
fun getOwnedPets(type: String, group: String): Flowable<RealmResults<Pet>>
fun updateOwnedEquipment(user: User)
fun changeOwnedCount(type: String, key: String, amountToAdd: Int)
fun sellItem(user: User?, type: String, key: String): Flowable<User>
fun sellItem(user: User?, item: Item): Flowable<User>
fun equipGear(user: User?, equipment: String, asCostume: Boolean): Flowable<Items>
fun equip(user: User?, type: String, key: String): Flowable<Items>
fun feedPet(pet: Pet, food: Food): Flowable<FeedResponse>
fun hatchPet(egg: Egg, hatchingPotion: HatchingPotion): Flowable<Items>
fun inviteToQuest(quest: QuestContent): Flowable<Quest>
fun buyItem(user: User?, id: String, value: Double): Flowable<BuyResponse>
fun retrieveShopInventory(identifier: String): Flowable<Shop>
fun retrieveMarketGear(): Flowable<Shop>
fun purchaseMysterySet(categoryIdentifier: String): Flowable<Void>
fun purchaseHourglassItem(purchaseType: String, key: String): Flowable<Void>
fun purchaseQuest(key: String): Flowable<Void>
fun purchaseItem(purchaseType: String, key: String): Flowable<Void>
fun togglePinnedItem(item: ShopItem): Flowable<List<ShopItem>>
}

View file

@ -1,13 +0,0 @@
package com.habitrpg.android.habitica.data;
import com.habitrpg.android.habitica.models.SetupCustomization;
import com.habitrpg.android.habitica.models.user.User;
import java.util.List;
public interface SetupCustomizationRepository {
List<SetupCustomization> getCustomizations(String type, User user);
List<SetupCustomization> getCustomizations(String type, String subtype, User user);
}

View file

@ -0,0 +1,11 @@
package com.habitrpg.android.habitica.data
import com.habitrpg.android.habitica.models.SetupCustomization
import com.habitrpg.android.habitica.models.user.User
interface SetupCustomizationRepository {
fun getCustomizations(type: String, user: User): List<SetupCustomization>
fun getCustomizations(type: String, subtype: String?, user: User): List<SetupCustomization>
}

View file

@ -71,7 +71,9 @@ class ApiClientImpl//private OnHabitsAPIResult mResultListener;
private val apiService: ApiService
private val apiCallTransformer = FlowableTransformer<HabitResponse<Any>, Any> { observable ->
observable.map { habitResponse ->
observable
.filter { it.data != null }
.map { habitResponse ->
if (habitResponse.notifications != null) {
popupNotificationsManager.showNotificationDialog(habitResponse.notifications)
}

View file

@ -10,7 +10,7 @@ import io.realm.RealmResults
class CustomizationRepositoryImpl(localRepository: CustomizationLocalRepository, apiClient: ApiClient) : ContentRepositoryImpl<CustomizationLocalRepository>(localRepository, apiClient), CustomizationRepository {
override fun getCustomizations(type: String, category: String, onlyAvailable: Boolean): Flowable<RealmResults<Customization>> {
override fun getCustomizations(type: String, category: String?, onlyAvailable: Boolean): Flowable<RealmResults<Customization>> {
return localRepository.getCustomizations(type, category, onlyAvailable)
}
}

View file

@ -55,7 +55,7 @@ class InventoryRepositoryImpl(localRepository: InventoryLocalRepository, apiClie
return localRepository.getEquipment(key)
}
override fun openMysteryItem(user: User): Flowable<Equipment> {
override fun openMysteryItem(user: User?): Flowable<Equipment> {
return apiClient.openMysteryItem().doOnNext { itemData ->
itemData.owned = true
localRepository.save(itemData)
@ -107,7 +107,7 @@ class InventoryRepositoryImpl(localRepository: InventoryLocalRepository, apiClie
localRepository.changeOwnedCount(type, key, amountToAdd)
}
override fun sellItem(user: User, type: String, key: String): Flowable<User> {
override fun sellItem(user: User?, type: String, key: String): Flowable<User> {
return localRepository.getItem(type, key)
.flatMap { item -> sellItem(user, item) }
}
@ -135,7 +135,7 @@ class InventoryRepositoryImpl(localRepository: InventoryLocalRepository, apiClie
}
}
override fun equipGear(user: User, key: String, asCostume: Boolean): Flowable<Items> {
override fun equipGear(user: User?, key: String, asCostume: Boolean): Flowable<Items> {
return equip(user, if (asCostume) "costume" else "equipped", key)
}
@ -181,9 +181,12 @@ class InventoryRepositoryImpl(localRepository: InventoryLocalRepository, apiClie
.doOnNext { localRepository.changeOwnedCount(quest, -1) }
}
override fun buyItem(user: User, key: String, value: Double): Flowable<BuyResponse> {
return apiClient.buyItem(key)
override fun buyItem(user: User?, id: String, value: Double): Flowable<BuyResponse> {
return apiClient.buyItem(id)
.doOnNext { buyResponse ->
if (user == null) {
return@doOnNext
}
val copiedUser = localRepository.getUnmanagedCopy(user)
if (buyResponse.items != null) {
buyResponse.items.userId = user.id

View file

@ -77,14 +77,14 @@ constructor(private val context: Context) : SetupCustomizationRepository {
SetupCustomization.createSkin("6bd049", R.color.skin_6bd049)
)
override fun getCustomizations(category: String, user: User): List<SetupCustomization> {
return getCustomizations(category, null, user)
override fun getCustomizations(type: String, user: User): List<SetupCustomization> {
return getCustomizations(type, null, user)
}
override fun getCustomizations(category: String, subcategory: String?, user: User): List<SetupCustomization> {
when (category) {
override fun getCustomizations(type: String, subtype: String?, user: User): List<SetupCustomization> {
when (type) {
"body" -> {
return when (subcategory) {
return when (subtype) {
"size" -> sizes
"shirt" -> getShirts(user.preferences?.size ?: "slim")
else -> emptyList()
@ -92,7 +92,7 @@ constructor(private val context: Context) : SetupCustomizationRepository {
}
"skin" -> return skins
"hair" -> {
return when (subcategory) {
return when (subtype) {
"bangs" -> getBangs(user.preferences?.hair!!.color)
"ponytail" -> getHairBases(user.preferences?.hair!!.color)
"color" -> hairColors
@ -100,7 +100,7 @@ constructor(private val context: Context) : SetupCustomizationRepository {
}
}
"extras" -> {
return when (subcategory) {
return when (subtype) {
"flower" -> flowers
"glasses" -> glasses
"wheelchair" -> wheelchairs

View file

@ -6,5 +6,5 @@ import io.reactivex.Flowable
import io.realm.RealmResults
interface CustomizationLocalRepository : ContentLocalRepository {
fun getCustomizations(type: String, category: String, onlyAvailable: Boolean): Flowable<RealmResults<Customization>>
fun getCustomizations(type: String, category: String?, onlyAvailable: Boolean): Flowable<RealmResults<Customization>>
}

View file

@ -42,7 +42,7 @@ interface InventoryLocalRepository : ContentLocalRepository {
fun getItem(type: String, key: String): Flowable<Item>
fun decrementMysteryItemCount(user: User)
fun decrementMysteryItemCount(user: User?)
fun saveInAppRewards(onlineItems: List<ShopItem>)
fun changePetFeedStatus(key: String?, feedStatus: Int)

View file

@ -10,7 +10,7 @@ import java.util.*
class RealmCustomizationLocalRepository(realm: Realm) : RealmContentLocalRepository(realm), CustomizationLocalRepository {
override fun getCustomizations(type: String, category: String, onlyAvailable: Boolean): Flowable<RealmResults<Customization>> {
override fun getCustomizations(type: String, category: String?, onlyAvailable: Boolean): Flowable<RealmResults<Customization>> {
var query = realm.where(Customization::class.java)
.equalTo("type", type)
.equalTo("category", category)

View file

@ -216,7 +216,10 @@ class RealmInventoryLocalRepository(realm: Realm, private val context: Context)
.cast(Item::class.java)
}
override fun decrementMysteryItemCount(user: User) {
override fun decrementMysteryItemCount(user: User?) {
if (user == null) {
return
}
val item = realm.where(SpecialItem::class.java).equalTo("isMysteryItem", true).findFirst()
realm.executeTransaction {
if (item != null && item.isValid) {

View file

@ -23,6 +23,7 @@ public class RemoteConfigManager {
private Boolean enableRepeatbles = false;
private Boolean enableNewShops = false;
private String shopSpriteSuffix = "";
private Integer maxChatLength = 3000;
private String REMOTE_STRING_KEY = "remote-string";
public RemoteConfigManager(Context context) {
@ -43,6 +44,8 @@ public class RemoteConfigManager {
return shopSpriteSuffix;
}
public Integer maxChatLength() { return maxChatLength; }
private void loadFromPreferences () {
String storedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
.getString(REMOTE_STRING_KEY, "");
@ -64,6 +67,9 @@ public class RemoteConfigManager {
if (obj.has("shopSpriteSuffix")) {
shopSpriteSuffix = obj.getString("shopSpriteSuffix");
}
if (obj.has("maxChatLength")) {
maxChatLength = obj.getInt("maxChatLength");
}
} catch (JSONException e) {
e.printStackTrace();
}

View file

@ -1,30 +0,0 @@
package com.habitrpg.android.habitica.helpers;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import com.facebook.imagepipeline.request.BasePostprocessor;
/**
* Created by phillip on 21.07.17.
*/
public class TiledBitmapPostProcessor extends BasePostprocessor {
private final Resources resources;
public TiledBitmapPostProcessor(Resources resources) {
super();
this.resources = resources;
}
@Override
public void process(Bitmap bitmap) {
BitmapDrawable TileMe = new BitmapDrawable(resources, bitmap);
TileMe.setTileModeX(Shader.TileMode.REPEAT);
TileMe.setTileModeY(Shader.TileMode.REPEAT);
super.process(TileMe.getBitmap());
}
}

View file

@ -1,123 +0,0 @@
package com.habitrpg.android.habitica.ui;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.app.AlertDialog;
import android.view.Gravity;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.facebook.drawee.view.SimpleDraweeView;
import com.habitrpg.android.habitica.R;
import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils;
import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper;
public class ItemDetailDialog extends AlertDialog {
private final SimpleDraweeView itemImageView;
private final TextView contentTextView;
private final TextView priceTextView;
private final ImageView currencyImageView;
public ItemDetailDialog(@NonNull Context context) {
super(context);
// External ContentView
LinearLayout contentViewLayout = new LinearLayout(context);
contentViewLayout.setOrientation(LinearLayout.VERTICAL);
// Gear Image
itemImageView = new SimpleDraweeView(context);
LinearLayout.LayoutParams gearImageLayoutParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
gearImageLayoutParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL;
gearImageLayoutParams.setMargins(0, 0, 0, 20);
itemImageView.setMinimumWidth(200);
itemImageView.setMinimumHeight(200);
itemImageView.setLayoutParams(gearImageLayoutParams);
itemImageView.setVisibility(View.GONE);
// Gear Description
contentTextView = new TextView(context, null);
contentTextView.setPadding(16, 0, 16, 0);
contentTextView.setVisibility(View.GONE);
// GoldPrice View
LinearLayout goldPriceLayout = new LinearLayout(context);
goldPriceLayout.setGravity(Gravity.CENTER_HORIZONTAL);
LinearLayout.LayoutParams goldPriceLayoutParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
goldPriceLayoutParams.setMargins(0, 0, 0, 16);
goldPriceLayoutParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL;
goldPriceLayout.setOrientation(LinearLayout.HORIZONTAL);
goldPriceLayout.setLayoutParams(goldPriceLayoutParams);
goldPriceLayout.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL);
// Price View
priceTextView = new TextView(context);
priceTextView.setPadding(10, 0, 0, 0);
currencyImageView = new ImageView(context);
currencyImageView.setMinimumHeight(50);
currencyImageView.setMinimumWidth(50);
currencyImageView.setPadding(0, 0, 5, 0);
goldPriceLayout.addView(currencyImageView);
goldPriceLayout.addView(priceTextView);
contentViewLayout.setGravity(Gravity.CENTER_VERTICAL);
contentViewLayout.addView(itemImageView);
contentViewLayout.addView(goldPriceLayout);
contentViewLayout.addView(contentTextView);
setView(contentViewLayout);
this.setButton(AlertDialog.BUTTON_NEGATIVE, context.getText(R.string.reward_dialog_dismiss), (clickedDialog, which) -> {
clickedDialog.dismiss();
});
}
public void setDescription(CharSequence description) {
contentTextView.setText(description);
contentTextView.setVisibility(View.VISIBLE);
}
public void setCurrency(String currency) {
switch (currency) {
case "gold":
currencyImageView.setImageBitmap(HabiticaIconsHelper.imageOfGold());
break;
case "gems":
currencyImageView.setImageBitmap(HabiticaIconsHelper.imageOfGem());
break;
default:
currencyImageView.setImageDrawable(null);
break;
}
}
public void setValue(Double value) {
priceTextView.setText(value.toString());
}
public void setValue(Integer value) {
priceTextView.setText(value.toString());
}
public void setImage(String imageName) {
itemImageView.setVisibility(View.VISIBLE);
DataBindingUtils.INSTANCE.loadImage(itemImageView, imageName);
}
public void setBuyListener(OnClickListener listener) {
this.setButton(BUTTON_POSITIVE, getContext().getText(R.string.reward_dialog_buy), listener);
}
}

View file

@ -0,0 +1,114 @@
package com.habitrpg.android.habitica.ui
import android.content.Context
import android.content.DialogInterface
import android.support.v7.app.AlertDialog
import android.view.Gravity
import android.view.View
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import com.facebook.drawee.view.SimpleDraweeView
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils
import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper
class ItemDetailDialog(context: Context) : AlertDialog(context) {
private val itemImageView: SimpleDraweeView
private val contentTextView: TextView
private val priceTextView: TextView
private val currencyImageView: ImageView
init {
// External ContentView
val contentViewLayout = LinearLayout(context)
contentViewLayout.orientation = LinearLayout.VERTICAL
// Gear Image
itemImageView = SimpleDraweeView(context)
val gearImageLayoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)
gearImageLayoutParams.gravity = Gravity.CENTER_HORIZONTAL or Gravity.CENTER_VERTICAL
gearImageLayoutParams.setMargins(0, 0, 0, 20)
itemImageView.minimumWidth = 200
itemImageView.minimumHeight = 200
itemImageView.layoutParams = gearImageLayoutParams
itemImageView.visibility = View.GONE
// Gear Description
contentTextView = TextView(context, null)
contentTextView.setPadding(16, 0, 16, 0)
contentTextView.visibility = View.GONE
// GoldPrice View
val goldPriceLayout = LinearLayout(context)
goldPriceLayout.gravity = Gravity.CENTER_HORIZONTAL
val goldPriceLayoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)
goldPriceLayoutParams.setMargins(0, 0, 0, 16)
goldPriceLayoutParams.gravity = Gravity.CENTER_HORIZONTAL or Gravity.CENTER_VERTICAL
goldPriceLayout.orientation = LinearLayout.HORIZONTAL
goldPriceLayout.layoutParams = goldPriceLayoutParams
goldPriceLayout.gravity = Gravity.CENTER_HORIZONTAL or Gravity.CENTER_VERTICAL
// Price View
priceTextView = TextView(context)
priceTextView.setPadding(10, 0, 0, 0)
currencyImageView = ImageView(context)
currencyImageView.minimumHeight = 50
currencyImageView.minimumWidth = 50
currencyImageView.setPadding(0, 0, 5, 0)
goldPriceLayout.addView(currencyImageView)
goldPriceLayout.addView(priceTextView)
contentViewLayout.gravity = Gravity.CENTER_VERTICAL
contentViewLayout.addView(itemImageView)
contentViewLayout.addView(goldPriceLayout)
contentViewLayout.addView(contentTextView)
setView(contentViewLayout)
this.setButton(AlertDialog.BUTTON_NEGATIVE, context.getText(R.string.reward_dialog_dismiss)) { clickedDialog, which -> clickedDialog.dismiss() }
}
fun setDescription(description: CharSequence) {
contentTextView.text = description
contentTextView.visibility = View.VISIBLE
}
fun setCurrency(currency: String) {
when (currency) {
"gold" -> currencyImageView.setImageBitmap(HabiticaIconsHelper.imageOfGold())
"gems" -> currencyImageView.setImageBitmap(HabiticaIconsHelper.imageOfGem())
else -> currencyImageView.setImageDrawable(null)
}
}
fun setValue(value: Double?) {
priceTextView.text = value?.toString()
}
fun setValue(value: Int?) {
priceTextView.text = value?.toString()
}
fun setImage(imageName: String) {
itemImageView.visibility = View.VISIBLE
DataBindingUtils.loadImage(itemImageView, imageName)
}
fun setBuyListener(listener: DialogInterface.OnClickListener) {
this.setButton(DialogInterface.BUTTON_POSITIVE, context.getText(R.string.reward_dialog_buy), listener)
}
}

View file

@ -1,69 +0,0 @@
package com.habitrpg.android.habitica.ui;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.WindowManager;
import android.widget.LinearLayout;
import com.habitrpg.android.habitica.R;
public class MaxHeightLinearLayout extends LinearLayout {
private final float defaultHeight = 0.9f;
private float maxHeight;
private DisplayMetrics displaymetrics = new DisplayMetrics();
public MaxHeightLinearLayout(Context context) {
super(context);
}
public MaxHeightLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
if (!isInEditMode()) {
init(context, attrs);
}
}
public MaxHeightLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
if (!isInEditMode()) {
init(context, attrs);
}
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public MaxHeightLinearLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
if (!isInEditMode()) {
init(context, attrs);
}
}
private void init(Context context, AttributeSet attrs) {
if (attrs != null) {
TypedArray styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.MaxHeightScrollView);
//200 is a defualt value
maxHeight = styledAttrs.getFloat(R.styleable.MaxHeightScrollView_maxHeightMultiplier, defaultHeight);
styledAttrs.recycle();
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
windowManager.getDefaultDisplay().getMetrics(displaymetrics);
int height = (int) (displaymetrics.heightPixels * maxHeight);
heightMeasureSpec = Math.min(heightMeasureSpec, View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST));
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}

View file

@ -0,0 +1,64 @@
package com.habitrpg.android.habitica.ui
import android.annotation.TargetApi
import android.content.Context
import android.content.res.TypedArray
import android.os.Build
import android.util.AttributeSet
import android.util.DisplayMetrics
import android.view.View
import android.view.WindowManager
import android.widget.LinearLayout
import com.habitrpg.android.habitica.R
class MaxHeightLinearLayout : LinearLayout {
private val defaultHeight = 0.9f
private var maxHeight: Float = 0.toFloat()
private val displaymetrics = DisplayMetrics()
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
if (!isInEditMode) {
init(context, attrs)
}
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
if (!isInEditMode) {
init(context, attrs)
}
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {
if (!isInEditMode) {
init(context, attrs)
}
}
private fun init(context: Context, attrs: AttributeSet?) {
if (attrs != null) {
val styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.MaxHeightLinearLayout)
//200 is a defualt value
maxHeight = styledAttrs.getFloat(R.styleable.MaxHeightLinearLayout_maxHeightMultiplier, defaultHeight)
styledAttrs.recycle()
}
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
var heightMeasurement = heightMeasureSpec
val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
windowManager.defaultDisplay.getMetrics(displaymetrics)
val height = (displaymetrics.heightPixels * maxHeight).toInt()
heightMeasurement = Math.min(heightMeasurement, View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST))
super.onMeasure(widthMeasureSpec, heightMeasurement)
}
}

View file

@ -33,8 +33,8 @@ import com.habitrpg.android.habitica.models.user.Stats
import com.habitrpg.android.habitica.ui.AvatarView
import com.habitrpg.android.habitica.ui.AvatarWithBarsViewModel
import com.habitrpg.android.habitica.ui.adapter.social.AchievementAdapter
import com.habitrpg.android.habitica.ui.helpers.KeyboardUtil
import com.habitrpg.android.habitica.ui.helpers.MarkdownParser
import com.habitrpg.android.habitica.ui.helpers.UiUtils
import com.habitrpg.android.habitica.ui.helpers.bindView
import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar
import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar.SnackbarDisplayType
@ -142,9 +142,9 @@ class FullProfileActivity : BaseActivity() {
String.format(getString(R.string.profile_message_sent_to), userName), SnackbarDisplayType.NORMAL)
}, RxErrorHandler.handleEmptyError())
UiUtils.dismissKeyboard(this)
KeyboardUtil.dismissKeyboard(this)
}
.setNegativeButton(android.R.string.cancel) { _, _ -> UiUtils.dismissKeyboard(this) }
.setNegativeButton(android.R.string.cancel) { _, _ -> KeyboardUtil.dismissKeyboard(this) }
.create()
@ -154,11 +154,7 @@ class FullProfileActivity : BaseActivity() {
}
private fun updateView(user: Member) {
val profile = user.profile
if (profile == null) {
return
}
val profile = user.profile ?: return
userName = profile.name

View file

@ -16,8 +16,8 @@ import android.widget.LinearLayout
import android.widget.Spinner
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.components.AppComponent
import com.habitrpg.android.habitica.ui.helpers.KeyboardUtil
import com.habitrpg.android.habitica.ui.helpers.MarkdownParser
import com.habitrpg.android.habitica.ui.helpers.UiUtils
import com.habitrpg.android.habitica.ui.helpers.bindView
import net.pherth.android.emoji_library.EmojiEditText
import net.pherth.android.emoji_library.EmojiPopup
@ -152,13 +152,13 @@ class GroupFormActivity : BaseActivity() {
override fun onSupportNavigateUp(): Boolean {
finish()
UiUtils.dismissKeyboard(this)
KeyboardUtil.dismissKeyboard(this)
return true
}
override fun onBackPressed() {
finish()
UiUtils.dismissKeyboard(this)
KeyboardUtil.dismissKeyboard(this)
}
private fun finishActivitySuccessfuly() {
@ -170,7 +170,7 @@ class GroupFormActivity : BaseActivity() {
resultIntent.putExtras(bundle)
setResult(Activity.RESULT_OK, resultIntent)
finish()
UiUtils.dismissKeyboard(this)
KeyboardUtil.dismissKeyboard(this)
}
private inner class EmojiClickListener(internal var view: EmojiEditText) : View.OnClickListener {

View file

@ -41,7 +41,7 @@ import com.habitrpg.android.habitica.helpers.AmplitudeManager
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.models.auth.UserAuthResponse
import com.habitrpg.android.habitica.prefs.scanner.IntentIntegrator
import com.habitrpg.android.habitica.ui.helpers.UiUtils
import com.habitrpg.android.habitica.ui.helpers.KeyboardUtil
import com.habitrpg.android.habitica.ui.helpers.bindView
import com.habitrpg.android.habitica.ui.views.login.LockableScrollView
import com.habitrpg.android.habitica.ui.views.login.LoginBackgroundView
@ -556,10 +556,10 @@ class LoginActivity : BaseActivity(), Consumer<UserAuthResponse> {
showAnimation.play(newGameAlphaAnimation).after(scrollViewAlphaAnimation)
showAnimation.play(showLoginAlphaAnimation).after(scrollViewAlphaAnimation)
showAnimation.start()
UiUtils.dismissKeyboard(this)
KeyboardUtil.dismissKeyboard(this)
}
fun onForgotPasswordClicked() {
private fun onForgotPasswordClicked() {
val input = EditText(this)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
input.setAutofillHints(EditText.AUTOFILL_HINT_EMAIL_ADDRESS)

View file

@ -1,6 +1,7 @@
package com.habitrpg.android.habitica.ui.activities
import android.annotation.SuppressLint
import android.annotation.TargetApi
import android.appwidget.AppWidgetManager
import android.content.ComponentName
import android.content.Intent
@ -69,6 +70,7 @@ import io.reactivex.Completable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.functions.Action
import io.reactivex.functions.Consumer
import io.reactivex.schedulers.Schedulers
import io.realm.Realm
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
@ -142,6 +144,7 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction {
private var drawerFragment: NavigationDrawerFragment? = null
private var drawerToggle: ActionBarDrawerToggle? = null
private var keyboardUtil: KeyboardUtil? = null
private var resumeFromActivity = false
private val statusBarHeight: Int
get() {
@ -257,8 +260,12 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction {
override fun onResume() {
super.onResume()
retrieveUser()
this.checkMaintenance()
if(!resumeFromActivity){
retrieveUser()
this.checkMaintenance()
}
resumeFromActivity = false
if (this.sharedPreferences.getLong("lastReminderSchedule", 0) < Date().time - 86400000) {
try {
@ -290,6 +297,21 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction {
super.onPause()
}
override fun startActivity(intent: Intent?) {
resumeFromActivity = true
super.startActivity(intent)
}
override fun startActivityForResult(intent: Intent?, requestCode: Int) {
resumeFromActivity = true
super.startActivityForResult(intent, requestCode)
}
override fun startActivity(intent: Intent?, options: Bundle?) {
resumeFromActivity = true
super.startActivity(intent, options)
}
private fun updateWidgets() {
updateWidget(AvatarStatsWidgetProvider::class.java)
updateWidget(TodoListWidgetProvider::class.java)
@ -499,7 +521,8 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction {
}
if (event.Reward.specialTag != null && event.Reward.specialTag == "item") {
inventoryRepository.buyItem(user, event.Reward.id, event.Reward.value)
val id = event.Reward.id ?: return
inventoryRepository.buyItem(user, id, event.Reward.value)
.subscribe(Consumer { buyResponse ->
var snackbarMessage = getString(R.string.successful_purchase, event.Reward.text)
if (event.Reward.id == "armoire") {
@ -801,7 +824,8 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction {
private fun checkMaintenance() {
this.maintenanceService.maintenanceStatus
.compose(apiClient.configureApiCallObserver())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(Consumer { maintenanceResponse ->
if (maintenanceResponse == null) {
return@Consumer

View file

@ -15,7 +15,9 @@ import com.habitrpg.android.habitica.data.ApiClient
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.ui.helpers.MarkdownParser
import com.habitrpg.android.habitica.ui.helpers.bindView
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.functions.Consumer
import io.reactivex.schedulers.Schedulers
import net.pherth.android.emoji_library.EmojiTextView
import javax.inject.Inject
@ -66,7 +68,8 @@ class MaintenanceActivity : BaseActivity() {
super.onResume()
if (!isDeprecationNotice) {
this.maintenanceService.maintenanceStatus
.compose(apiClient.configureApiCallObserver())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(Consumer { maintenanceResponse ->
if (!maintenanceResponse.activeMaintenance) {
finish()

View file

@ -178,7 +178,7 @@ class NavigationDrawerFragment : DialogFragment() {
subscriptions?.add(socialRepository.getGroup(Group.TAVERN_ID)
.doOnNext({ quest = it.quest })
.filter { it.hasActiveQuest }
.flatMapMaybe { inventoryRepository.getQuestContent(it.quest?.key).firstElement() }
.flatMapMaybe { inventoryRepository.getQuestContent(it.quest?.key ?: "").firstElement() }
.subscribe(Consumer {
questContent = it
}, RxErrorHandler.handleEmptyError()))

View file

@ -62,7 +62,7 @@ class FAQOverviewFragment : BaseMainFragment() {
if (user == null || adapter == null) {
return
}
faqRepository.articles.subscribe(Consumer { adapter?.setArticles(it) }, RxErrorHandler.handleEmptyError())
faqRepository.getArticles().subscribe(Consumer { adapter?.setArticles(it) }, RxErrorHandler.handleEmptyError())
}
override fun customTitle(): String {

View file

@ -114,14 +114,11 @@ class AvatarCustomizationFragment : BaseMainFragment() {
}
private fun loadCustomizations() {
if (user == null) {
return
}
val type = this.type ?: return
compositeSubscription.add(customizationRepository.getCustomizations(type, category, true).subscribe(Consumer<RealmResults<Customization>> { adapter.setCustomizations(it) }, RxErrorHandler.handleEmptyError()))
if (type == "hair" && (category == "beard" || category == "mustache")) {
val otherCategory = if (category == "mustache") "beard" else "mustache"
compositeSubscription.add(customizationRepository.getCustomizations(type, otherCategory, true).subscribe(Consumer<RealmResults<Customization>> { adapter.additionalSetItems = it }, RxErrorHandler.handleEmptyError()))
}
}

View file

@ -54,7 +54,7 @@ class EquipmentOverviewFragment : BaseMainFragment() {
setImageNames()
if (this.nameMapping.isEmpty()) {
compositeSubscription.add(inventoryRepository.ownedEquipment.subscribe(Consumer {
compositeSubscription.add(inventoryRepository.getOwnedEquipment().subscribe(Consumer {
for (gear in it) {
this.nameMapping[gear.key ?: ""] = gear.text
}

View file

@ -117,24 +117,28 @@ class ItemRecyclerFragment : BaseFragment() {
this.itemType = savedInstanceState.getString(ITEM_TYPE_KEY, "")
}
if (this.isHatching) {
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
this.titleView?.text = getString(R.string.hatch_with, this.hatchingItem?.text)
this.titleView?.visibility = View.VISIBLE
this.footerView?.text = getString(R.string.hatching_market_info)
this.footerView?.visibility = View.VISIBLE
this.openMarketButton?.visibility = View.VISIBLE
} else if (this.isFeeding) {
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
this.titleView?.text = getString(R.string.dialog_feeding, this.feedingPet?.colorText, this.feedingPet?.animalText)
this.titleView?.visibility = View.VISIBLE
this.footerView?.text = getString(R.string.feeding_market_info)
this.footerView?.visibility = View.VISIBLE
this.openMarketButton?.visibility = View.VISIBLE
} else {
this.titleView?.visibility = View.GONE
this.footerView?.visibility = View.GONE
this.openMarketButton?.visibility = View.GONE
when {
this.isHatching -> {
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
this.titleView?.text = getString(R.string.hatch_with, this.hatchingItem?.text)
this.titleView?.visibility = View.VISIBLE
this.footerView?.text = getString(R.string.hatching_market_info)
this.footerView?.visibility = View.VISIBLE
this.openMarketButton?.visibility = View.VISIBLE
}
this.isFeeding -> {
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
this.titleView?.text = getString(R.string.dialog_feeding, this.feedingPet?.colorText, this.feedingPet?.animalText)
this.titleView?.visibility = View.VISIBLE
this.footerView?.text = getString(R.string.feeding_market_info)
this.footerView?.visibility = View.VISIBLE
this.openMarketButton?.visibility = View.VISIBLE
}
else -> {
this.titleView?.visibility = View.GONE
this.footerView?.visibility = View.GONE
this.openMarketButton?.visibility = View.GONE
}
}
openMarketButton?.setOnClickListener {
@ -164,13 +168,13 @@ class ItemRecyclerFragment : BaseFragment() {
}
private fun loadItems() {
var itemClass: Class<out Item>? = null
when (itemType) {
"eggs" -> itemClass = Egg::class.java
"hatchingPotions" -> itemClass = HatchingPotion::class.java
"food" -> itemClass = Food::class.java
"quests" -> itemClass = QuestContent::class.java
"special" -> itemClass = SpecialItem::class.java
val itemClass: Class<out Item> = when (itemType) {
"eggs" -> Egg::class.java
"hatchingPotions" -> HatchingPotion::class.java
"food" -> Food::class.java
"quests" -> QuestContent::class.java
"special" -> SpecialItem::class.java
else -> Egg::class.java
}
inventoryRepository.getOwnedItems(itemClass, user).firstElement().subscribe(Consumer { items ->
if (items.size > 0) {
@ -178,7 +182,7 @@ class ItemRecyclerFragment : BaseFragment() {
}
}, RxErrorHandler.handleEmptyError())
compositeSubscription.add(inventoryRepository?.ownedPets.subscribe(Consumer { adapter?.setOwnedPets(it) }, RxErrorHandler.handleEmptyError()))
compositeSubscription.add(inventoryRepository?.getOwnedPets().subscribe(Consumer { adapter?.setOwnedPets(it) }, RxErrorHandler.handleEmptyError()))
}
private fun openMarket() {
@ -187,6 +191,6 @@ class ItemRecyclerFragment : BaseFragment() {
companion object {
private val ITEM_TYPE_KEY = "CLASS_TYPE_KEY"
private const val ITEM_TYPE_KEY = "CLASS_TYPE_KEY"
}
}

View file

@ -153,14 +153,14 @@ class ShopFragment : BaseFragment() {
compositeSubscription.add(this.inventoryRepository.getOwnedItems(it)
.subscribe(Consumer { adapter?.setOwnedItems(it) }, RxErrorHandler.handleEmptyError()))
}
compositeSubscription.add(this.inventoryRepository.inAppRewards
compositeSubscription.add(this.inventoryRepository.getInAppRewards()
.map<List<String>> { it.map { it.key } }
.subscribe(Consumer { adapter?.setPinnedItemKeys(it) }, RxErrorHandler.handleEmptyError()))
}
private fun loadMarketGear() {
inventoryRepository.retrieveMarketGear()
.zipWith(inventoryRepository.ownedEquipment.map { it.map { it.key } }, BiFunction<Shop, List<String?>, Shop> { shop, equipment ->
.zipWith(inventoryRepository.getOwnedEquipment().map { it.map { it.key } }, BiFunction<Shop, List<String?>, Shop> { shop, equipment ->
for (category in shop.categories) {
val items = category.items.filter {
!equipment.contains(it.key)

View file

@ -120,9 +120,9 @@ class StableRecyclerFragment : BaseFragment() {
private fun loadItems() {
val observable: Flowable<out Animal> = if ("pets" == itemType) {
inventoryRepository.pets.firstElement().toFlowable().flatMap { Flowable.fromIterable(it) }
inventoryRepository.getPets().firstElement().toFlowable().flatMap { Flowable.fromIterable(it) }
} else {
inventoryRepository.mounts.firstElement().toFlowable().flatMap { Flowable.fromIterable(it) }
inventoryRepository.getMounts().firstElement().toFlowable().flatMap { Flowable.fromIterable(it) }
}
observable.toList().flatMap { unsortedAnimals ->

View file

@ -126,9 +126,8 @@ class AvatarSetupFragment : BaseFragment() {
}
private fun loadCustomizations() {
if (this.user == null || this.adapter == null || this.activeCategory == null) {
return
}
val user = this.user ?: return
val activeCategory = this.activeCategory ?: return
this.adapter?.setCustomizationList(customizationRepository.getCustomizations(activeCategory, activeSubCategory, user))
}
@ -151,7 +150,7 @@ class AvatarSetupFragment : BaseFragment() {
}
fun selectedBodyCategory() {
private fun selectedBodyCategory() {
activateButton(bodyButton)
this.activeCategory = "body"
this.subCategoryTabs?.removeAllTabs()
@ -161,7 +160,7 @@ class AvatarSetupFragment : BaseFragment() {
loadCustomizations()
}
fun selectedSkinCategory() {
private fun selectedSkinCategory() {
activateButton(skinButton)
this.activeCategory = "skin"
this.subCategoryTabs?.removeAllTabs()
@ -170,7 +169,7 @@ class AvatarSetupFragment : BaseFragment() {
loadCustomizations()
}
fun selectedHairCategory() {
private fun selectedHairCategory() {
activateButton(hairButton)
this.activeCategory = "hair"
this.subCategoryTabs?.removeAllTabs()
@ -181,7 +180,7 @@ class AvatarSetupFragment : BaseFragment() {
loadCustomizations()
}
fun selectedExtrasCategory() {
private fun selectedExtrasCategory() {
activateButton(extrasButton)
this.activeCategory = "extras"
this.subCategoryTabs?.removeAllTabs()
@ -192,10 +191,8 @@ class AvatarSetupFragment : BaseFragment() {
loadCustomizations()
}
fun randomizeCharacter() {
if (user == null) {
return
}
private fun randomizeCharacter() {
val user = this.user ?: return
val command = UpdateUserCommand()
val updateData = HashMap<String, Any>()
updateData["preferences.size"] = chooseRandomKey(customizationRepository.getCustomizations("body", "size", user), false)

View file

@ -18,6 +18,7 @@ import com.habitrpg.android.habitica.components.AppComponent
import com.habitrpg.android.habitica.data.SocialRepository
import com.habitrpg.android.habitica.data.UserRepository
import com.habitrpg.android.habitica.extensions.notNull
import com.habitrpg.android.habitica.helpers.RemoteConfigManager
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.models.social.ChatMessage
import com.habitrpg.android.habitica.models.user.User
@ -43,6 +44,9 @@ class ChatListFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener {
lateinit var socialRepository: SocialRepository
@Inject
lateinit var userRepository: UserRepository
@Inject
lateinit var configManager: RemoteConfigManager
private var isTavern: Boolean = false
internal var layoutManager: LinearLayoutManager? = null
private var groupId: String = ""
@ -117,6 +121,7 @@ class ChatListFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener {
}
chatBarView.sendAction = { sendChatMessage(it) }
chatBarView.maxChatLength = configManager.maxChatLength()
recyclerView.adapter = chatAdapter
recyclerView.itemAnimator = SafeDefaultItemAnimator()

View file

@ -19,7 +19,7 @@ import com.habitrpg.android.habitica.models.social.ChatMessage
import com.habitrpg.android.habitica.modules.AppModule
import com.habitrpg.android.habitica.prefs.scanner.IntentIntegrator
import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment
import com.habitrpg.android.habitica.ui.helpers.UiUtils
import com.habitrpg.android.habitica.ui.helpers.KeyboardUtil
import io.reactivex.functions.Consumer
import io.realm.RealmResults
import kotlinx.android.synthetic.main.fragment_inbox.*
@ -94,7 +94,7 @@ class InboxFragment : BaseMainFragment(), SwipeRefreshLayout.OnRefreshListener,
openInboxMessages(uuidEditText.text.toString(), "")
}
.setNeutralButton(getString(R.string.action_cancel)) { dialog, _ ->
UiUtils.dismissKeyboard(thisActivity)
KeyboardUtil.dismissKeyboard(thisActivity)
dialog.cancel()
}
.create()

View file

@ -10,7 +10,6 @@ import android.support.v7.widget.LinearLayoutManager
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.components.AppComponent
import com.habitrpg.android.habitica.data.SocialRepository
@ -22,8 +21,8 @@ import com.habitrpg.android.habitica.ui.activities.FullProfileActivity
import com.habitrpg.android.habitica.ui.activities.MainActivity
import com.habitrpg.android.habitica.ui.adapter.social.ChatRecyclerViewAdapter
import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment
import com.habitrpg.android.habitica.ui.helpers.KeyboardUtil
import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator
import com.habitrpg.android.habitica.ui.helpers.UiUtils
import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar
import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar.Companion.showSnackbar
import io.reactivex.functions.Action
@ -127,7 +126,7 @@ class InboxMessageListFragment : BaseMainFragment(), SwipeRefreshLayout.OnRefres
replyToUserUUID?.notNull {
socialRepository.postPrivateMessage(it, chatText)
.subscribe(Consumer { this.refreshUserInbox() }, RxErrorHandler.handleEmptyError())
UiUtils.dismissKeyboard(getActivity())
KeyboardUtil.dismissKeyboard(getActivity())
}
}

View file

@ -11,11 +11,12 @@ import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.components.AppComponent
import com.habitrpg.android.habitica.data.SocialRepository
import com.habitrpg.android.habitica.extensions.inflate
import com.habitrpg.android.habitica.extensions.notNull
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.ui.adapter.social.PublicGuildsRecyclerViewAdapter
import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment
import com.habitrpg.android.habitica.ui.helpers.KeyboardUtil
import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator
import com.habitrpg.android.habitica.ui.helpers.UiUtils
import com.habitrpg.android.habitica.ui.helpers.bindView
import com.habitrpg.android.habitica.ui.helpers.resetViews
import io.reactivex.functions.Consumer
@ -83,8 +84,8 @@ class PublicGuildsFragment : BaseMainFragment(), SearchView.OnQueryTextListener
override fun onQueryTextSubmit(s: String): Boolean {
viewAdapter.filter.filter(s)
if (this.activity != null) {
UiUtils.dismissKeyboard(this.activity!!)
activity.notNull {
KeyboardUtil.dismissKeyboard(it)
}
return true
}

View file

@ -87,7 +87,7 @@ class QuestDetailFragment : BaseMainFragment() {
super.onResume()
compositeSubscription.add(socialRepository.getGroup(partyId).subscribe(Consumer { this.updateParty(it) }, RxErrorHandler.handleEmptyError()))
if (questKey != null) {
compositeSubscription.add(inventoryRepository.getQuestContent(questKey).subscribe(Consumer { this.updateQuestContent(it) }, RxErrorHandler.handleEmptyError()))
compositeSubscription.add(inventoryRepository.getQuestContent(questKey ?: "").subscribe(Consumer { this.updateQuestContent(it) }, RxErrorHandler.handleEmptyError()))
}
}

View file

@ -85,7 +85,7 @@ class TavernDetailFragment : BaseFragment() {
.doOnNext { if (!it.hasActiveQuest) worldBossSection.visibility = View.GONE }
.filter { it.hasActiveQuest }
.doOnNext { questProgressView.progress = it.quest}
.flatMapMaybe { inventoryRepository.getQuestContent(it.quest?.key).firstElement() }
.flatMapMaybe { inventoryRepository.getQuestContent(it.quest?.key ?: "").firstElement() }
.subscribe(Consumer {
questProgressView.quest = it
worldBossSection.visibility = View.VISIBLE

View file

@ -130,7 +130,7 @@ class PartyDetailFragment : BaseFragment() {
questImageWrapper?.visibility = View.VISIBLE
val mainHandler = Handler(context?.mainLooper)
mainHandler.postDelayed({
inventoryRepository.getQuestContent(quest?.key)
inventoryRepository.getQuestContent(quest?.key ?: "")
.firstElement()
.subscribe(Consumer<QuestContent> { this@PartyDetailFragment.updateQuestContent(it) }, RxErrorHandler.handleEmptyError())
}, 500)

View file

@ -45,7 +45,7 @@ class RewardsRecyclerviewFragment : TaskRecyclerViewFragment() {
}
recyclerView.itemAnimator = SafeDefaultItemAnimator()
inventoryRepository.inAppRewards.subscribe(Consumer {
inventoryRepository.getInAppRewards().subscribe(Consumer {
(recyclerAdapter as RewardsRecyclerViewAdapter?)?.updateItemRewards(it)
}, RxErrorHandler.handleEmptyError())
}

View file

@ -77,17 +77,12 @@ class KeyboardUtil(activity: Activity, private val contentView: View) {
}
}
/**
* Helper to hide the keyboard
*
* @param act
*/
fun hideKeyboard(act: Activity?) {
if (act != null && act.currentFocus != null) {
val inputMethodManager = act.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
inputMethodManager.hideSoftInputFromWindow(act.currentFocus?.windowToken, 0)
companion object {
fun dismissKeyboard(act: Activity?) {
if (act != null && act.currentFocus != null) {
val inputMethodManager = act.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
inputMethodManager.hideSoftInputFromWindow(act.currentFocus?.windowToken, 0)
}
}
}
}

View file

@ -1,40 +0,0 @@
package com.habitrpg.android.habitica.ui.helpers;
import android.app.Activity;
import android.content.Context;
import android.support.annotation.Nullable;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
/**
* Simple utilities class for UI related stuff.
*/
public class UiUtils {
/**
* Hides soft keyboard if it's opened.
*
* @param activity Currently visible activity.
*/
public static void dismissKeyboard(Activity activity) {
InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
View currentFocus = activity.getCurrentFocus();
if (currentFocus != null) {
imm.hideSoftInputFromWindow(currentFocus.getWindowToken(), 0);
}
}
/**
* Hides soft keyboard if it's opened.
* This eliminates weird behavior when hiding keyboard from within Dialog
*
* @param view View that currently has focus
* @param activity - Current activity
*/
public static void dismissKeyboard(Activity activity, @Nullable View view) {
InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
if (view != null) {
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
}
}

View file

@ -1,5 +1,6 @@
package com.habitrpg.android.habitica.ui.viewHolders.tasks
import android.content.DialogInterface
import android.support.v4.content.ContextCompat
import android.view.View
import android.widget.ImageView
@ -49,11 +50,11 @@ class RewardViewHolder(itemView: View) : BaseTaskViewHolder(itemView) {
if (isItem) {
val dialog = ItemDetailDialog(context)
dialog.setTitle(task?.text)
dialog.setDescription(task?.notes)
dialog.setDescription(task?.notes ?: "")
dialog.setImage("shop_" + this.task?.id)
dialog.setCurrency("gold")
dialog.setValue(task!!.value)
dialog.setBuyListener { _, _ -> this.buyReward() }
dialog.setBuyListener( DialogInterface.OnClickListener { _, _ -> this.buyReward() })
dialog.show()
} else {
val event = TaskTappedEvent()

View file

@ -1,54 +0,0 @@
package com.habitrpg.android.habitica.ui.views;
import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class FadingViewPager extends ViewPager {
public boolean disableFading;
public FadingViewPager(Context context) {
super(context);
setTransformer();
}
public FadingViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
setTransformer();
}
private void setTransformer() {
this.setPageTransformer(true, (page, position) -> {
page.setTranslationX(page.getWidth() * -position);
if(position <= -1.0F || position >= 1.0F) {
page.setAlpha(0.0F);
page.setVisibility(View.INVISIBLE);
} else if( position == 0.0F ) {
page.setVisibility(View.VISIBLE);
page.setAlpha(1.0F);
} else {
if (disableFading) {
return;
}
page.setVisibility(View.VISIBLE);
// position is between -1.0F & 0.0F OR 0.0F & 1.0F
page.setAlpha(1.0F - Math.abs(position));
}
});
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
return false;
}
@Override
public boolean onInterceptHoverEvent(MotionEvent event) {
return false;
}
}

View file

@ -0,0 +1,49 @@
package com.habitrpg.android.habitica.ui.views
import android.content.Context
import android.support.v4.view.ViewPager
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
class FadingViewPager : ViewPager {
var disableFading: Boolean = false
constructor(context: Context) : super(context) {
setTransformer()
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
setTransformer()
}
private fun setTransformer() {
this.setPageTransformer(true) { page, position ->
page.translationX = page.width * -position
if (position <= -1.0f || position >= 1.0f) {
page.alpha = 0.0f
page.visibility = View.INVISIBLE
} else if (position == 0.0f) {
page.visibility = View.VISIBLE
page.alpha = 1.0f
} else {
if (disableFading) {
return@setPageTransformer
}
page.visibility = View.VISIBLE
// position is between -1.0F & 0.0F OR 0.0F & 1.0F
page.alpha = 1.0f - Math.abs(position)
}
}
}
override fun onTouchEvent(ev: MotionEvent): Boolean {
return false
}
override fun onInterceptHoverEvent(event: MotionEvent): Boolean {
return false
}
}

View file

@ -1,72 +0,0 @@
package com.habitrpg.android.habitica.ui.views;
import android.content.Context;
import android.os.Handler;
import android.support.v4.content.ContextCompat;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.style.ForegroundColorSpan;
import android.util.AttributeSet;
import com.habitrpg.android.habitica.R;
// http://stackoverflow.com/a/6700718/1315039
public class Typewriter extends android.support.v7.widget.AppCompatTextView {
private SpannableStringBuilder stringBuilder;
private Object visibleSpan;
private Object hiddenSpan;
private int index;
private long delay = 30;
public Typewriter(Context context) {
super(context);
setupTextColors(context);
}
public Typewriter(Context context, AttributeSet attrs) {
super(context, attrs);
setupTextColors(context);
}
private void setupTextColors(Context context) {
visibleSpan = new ForegroundColorSpan(ContextCompat.getColor(context, R.color.textColorLight));
hiddenSpan = new ForegroundColorSpan(ContextCompat.getColor(context, R.color.transparent));
}
private Handler handler = new Handler();
private Runnable characterAdder = new Runnable() {
@Override
public void run() {
stringBuilder.setSpan(visibleSpan, 0, index++, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
setText(stringBuilder);
if(index <= stringBuilder.length()) {
handler.postDelayed(characterAdder, delay);
}
}
};
public void animateText(CharSequence text) {
stringBuilder = new SpannableStringBuilder(text);
stringBuilder.setSpan(hiddenSpan, 0, stringBuilder.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
index = 0;
setText(stringBuilder);
handler.removeCallbacks(characterAdder);
handler.postDelayed(characterAdder, delay);
}
public void setCharacterDelay(long millis) {
delay = millis;
}
public boolean isAnimating() {
return index < stringBuilder.length();
}
public void stopTextAnimation() {
index = stringBuilder.length();
}
}

View file

@ -0,0 +1,68 @@
package com.habitrpg.android.habitica.ui.views
import android.content.Context
import android.os.Handler
import android.support.v4.content.ContextCompat
import android.text.Spannable
import android.text.SpannableStringBuilder
import android.text.style.ForegroundColorSpan
import android.util.AttributeSet
import com.habitrpg.android.habitica.R
// http://stackoverflow.com/a/6700718/1315039
class Typewriter : android.support.v7.widget.AppCompatTextView {
private var stringBuilder: SpannableStringBuilder? = null
private var visibleSpan: Any? = null
private var hiddenSpan: Any? = null
private var index: Int = 0
private var delay: Long = 30
private val textHandler = Handler()
private val characterAdder = object : Runnable {
override fun run() {
stringBuilder?.setSpan(visibleSpan, 0, index++, Spannable.SPAN_INCLUSIVE_INCLUSIVE)
text = stringBuilder
if (index <= stringBuilder?.length ?: 0) {
textHandler.postDelayed(this, delay)
}
}
}
val isAnimating: Boolean
get() = index < stringBuilder?.length ?: 0
constructor(context: Context) : super(context) {
setupTextColors(context)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
setupTextColors(context)
}
private fun setupTextColors(context: Context) {
visibleSpan = ForegroundColorSpan(ContextCompat.getColor(context, R.color.textColorLight))
hiddenSpan = ForegroundColorSpan(ContextCompat.getColor(context, R.color.transparent))
}
fun animateText(text: CharSequence) {
stringBuilder = SpannableStringBuilder(text)
stringBuilder?.setSpan(hiddenSpan, 0, stringBuilder?.length ?: 0, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
index = 0
setText(stringBuilder)
textHandler.removeCallbacks(characterAdder)
textHandler.postDelayed(characterAdder, delay)
}
fun setCharacterDelay(millis: Long) {
delay = millis
}
fun stopTextAnimation() {
index = stringBuilder?.length ?: 0
}
}

View file

@ -1,70 +0,0 @@
package com.habitrpg.android.habitica.ui.views;
import android.content.Context;
import android.graphics.drawable.Animatable;
import android.net.Uri;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import com.facebook.drawee.backends.pipeline.PipelineDraweeControllerBuilder;
import com.facebook.drawee.controller.BaseControllerListener;
import com.facebook.drawee.controller.ControllerListener;
import com.facebook.drawee.generic.GenericDraweeHierarchy;
import com.facebook.drawee.interfaces.DraweeController;
import com.facebook.drawee.view.SimpleDraweeView;
import com.facebook.imagepipeline.image.ImageInfo;
//https://stackoverflow.com/questions/33955510/facebook-fresco-using-wrap-content
public class WrapContentDraweeView extends SimpleDraweeView {
// we set a listener and update the view's aspect ratio depending on the loaded image
private final ControllerListener listener = new BaseControllerListener<ImageInfo>() {
@Override
public void onIntermediateImageSet(String id, @Nullable ImageInfo imageInfo) {
updateViewSize(imageInfo);
}
@Override
public void onFinalImageSet(String id, @Nullable ImageInfo imageInfo, @Nullable Animatable animatable) {
updateViewSize(imageInfo);
}
};
public WrapContentDraweeView(Context context, GenericDraweeHierarchy hierarchy) {
super(context, hierarchy);
}
public WrapContentDraweeView(Context context) {
super(context);
}
public WrapContentDraweeView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public WrapContentDraweeView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public WrapContentDraweeView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public void setImageURI(Uri uri, Object callerContext) {
DraweeController controller = ((PipelineDraweeControllerBuilder)getControllerBuilder())
.setControllerListener(listener)
.setCallerContext(callerContext)
.setUri(uri)
.setAutoPlayAnimations(true)
.setOldController(getController())
.build();
setController(controller);
}
void updateViewSize(@Nullable ImageInfo imageInfo) {
if (imageInfo != null) {
setAspectRatio((float) imageInfo.getWidth() / imageInfo.getHeight());
}
}
}

View file

@ -0,0 +1,49 @@
package com.habitrpg.android.habitica.ui.views
import android.content.Context
import android.graphics.drawable.Animatable
import android.net.Uri
import android.util.AttributeSet
import com.facebook.drawee.backends.pipeline.PipelineDraweeControllerBuilder
import com.facebook.drawee.controller.BaseControllerListener
import com.facebook.drawee.view.SimpleDraweeView
import com.facebook.imagepipeline.image.ImageInfo
//https://stackoverflow.com/questions/33955510/facebook-fresco-using-wrap-content
class WrapContentDraweeView : SimpleDraweeView {
// we set a listener and update the view's aspect ratio depending on the loaded image
private val listener = object : BaseControllerListener<ImageInfo>() {
override fun onIntermediateImageSet(id: String?, imageInfo: ImageInfo?) {
updateViewSize(imageInfo)
}
override fun onFinalImageSet(id: String?, imageInfo: ImageInfo?, animatable: Animatable?) {
updateViewSize(imageInfo)
}
}
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle)
override fun setImageURI(uri: Uri, callerContext: Any?) {
val controller = (controllerBuilder as PipelineDraweeControllerBuilder)
.setControllerListener(listener)
.setCallerContext(callerContext)
.setUri(uri)
.setAutoPlayAnimations(true)
.setOldController(controller)
.build()
setController(controller)
}
internal fun updateViewSize(imageInfo: ImageInfo?) {
if (imageInfo != null) {
aspectRatio = imageInfo.width.toFloat() / imageInfo.height
}
}
}

View file

@ -1,41 +0,0 @@
package com.habitrpg.android.habitica.ui.views.login;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ScrollView;
public class LockableScrollView extends ScrollView {
private boolean scrollable = true;
public LockableScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setScrollingEnabled(boolean enabled) {
scrollable = enabled;
}
public boolean isScrollable() {
return scrollable;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
if (scrollable) return super.onTouchEvent(ev);
return scrollable; // mScrollable is always false at this point
default:
return super.onTouchEvent(ev);
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (!scrollable) return false;
else return super.onInterceptTouchEvent(ev);
}
}

View file

@ -0,0 +1,33 @@
package com.habitrpg.android.habitica.ui.views.login
import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import android.widget.ScrollView
class LockableScrollView(context: Context, attrs: AttributeSet) : ScrollView(context, attrs) {
private var isScrollable = true
fun setScrollingEnabled(enabled: Boolean) {
isScrollable = enabled
}
override fun onTouchEvent(ev: MotionEvent): Boolean {
return when (ev.action) {
MotionEvent.ACTION_DOWN -> {
if (isScrollable) super.onTouchEvent(ev) else isScrollable
// mScrollable is always false at this point
}
else -> super.onTouchEvent(ev)
}
}
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
return if (!isScrollable)
false
else
super.onInterceptTouchEvent(ev)
}
}

View file

@ -1,75 +0,0 @@
package com.habitrpg.android.habitica.ui.views.login;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.support.annotation.Nullable;
import android.support.v7.widget.AppCompatImageView;
import android.util.AttributeSet;
import android.view.View;
import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper;
import java.util.List;
public class StarView extends AppCompatImageView {
private List<Integer> blinkDurations;
private int blinkIndex = 0;
public StarView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public StarView(Context context) {
super(context);
this.setScaleType(ScaleType.CENTER);
}
public void setStarSize(int size) {
switch (size) {
case 0: {
this.setImageBitmap(HabiticaIconsHelper.imageOfStarSmall());
break;
}
case 1: {
this.setImageBitmap(HabiticaIconsHelper.imageOfStarMedium());
break;
}
case 2: {
this.setImageBitmap(HabiticaIconsHelper.imageOfStarLarge());
break;
}
}
}
public void setBlinkDurations(List<Integer> blinkDurations) {
this.blinkDurations = blinkDurations;
runBlink();
}
private void runBlink() {
if (blinkIndex >= blinkDurations.size()) {
blinkIndex = 0;
}
ValueAnimator animator = ObjectAnimator.ofFloat(this, View.ALPHA, 0);
animator.setDuration(1000);
animator.setStartDelay(blinkDurations.get(blinkIndex));
animator.setRepeatCount(1);
animator.setRepeatMode(ValueAnimator.REVERSE);
animator.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
blinkIndex++;
runBlink();
}
});
try {
animator.start();
} catch (NullPointerException ignored) {
}
}
}

View file

@ -0,0 +1,68 @@
package com.habitrpg.android.habitica.ui.views.login
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ObjectAnimator
import android.animation.ValueAnimator
import android.content.Context
import android.support.v7.widget.AppCompatImageView
import android.util.AttributeSet
import android.view.View
import android.widget.ImageView
import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper
class StarView : AppCompatImageView {
private var blinkDurations: List<Int>? = null
private var blinkIndex = 0
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context) : super(context) {
this.scaleType = ImageView.ScaleType.CENTER
}
fun setStarSize(size: Int) {
when (size) {
0 -> {
this.setImageBitmap(HabiticaIconsHelper.imageOfStarSmall())
}
1 -> {
this.setImageBitmap(HabiticaIconsHelper.imageOfStarMedium())
}
2 -> {
this.setImageBitmap(HabiticaIconsHelper.imageOfStarLarge())
}
}
}
fun setBlinkDurations(blinkDurations: List<Int>) {
this.blinkDurations = blinkDurations
runBlink()
}
private fun runBlink() {
if (blinkIndex >= blinkDurations!!.size) {
blinkIndex = 0
}
val animator = ObjectAnimator.ofFloat<View>(this, View.ALPHA, 0f)
animator.duration = 1000
animator.startDelay = blinkDurations?.get(blinkIndex)?.toLong() ?: 0
animator.repeatCount = 1
animator.repeatMode = ValueAnimator.REVERSE
animator.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
blinkIndex++
runBlink()
}
})
try {
animator.start()
} catch (ignored: NullPointerException) {
}
}
}

View file

@ -1,19 +0,0 @@
package com.habitrpg.android.habitica.ui.views.setup;
import android.content.Context;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.widget.LinearLayout;
import com.habitrpg.android.habitica.R;
public class AvatarCustomizationDrawer extends LinearLayout {
public AvatarCustomizationDrawer(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
inflate(context, R.layout.avatar_setup_drawer, this);
}
}

View file

@ -0,0 +1,14 @@
package com.habitrpg.android.habitica.ui.views.setup
import android.content.Context
import android.util.AttributeSet
import android.widget.LinearLayout
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.extensions.inflate
class AvatarCustomizationDrawer(context: Context, attrs: AttributeSet?) : LinearLayout(context, attrs) {
init {
inflate(R.layout.avatar_setup_drawer, true)
}
}

View file

@ -27,7 +27,7 @@ class ChatBarView : FrameLayout {
private var navBarAccountedHeightCalculated = false
private var maxChatLength = 200
internal var maxChatLength = 200
var sendAction: ((String) -> Unit)? = null

View file

@ -4,3 +4,4 @@ amplitude_app_id=CHANGE_ME
seeds_app_key=CHANGE_ME
seeds_interstitial_gems=CHANGE_ME
seeds_interstitial_sharing=CHANGE_ME
instabug_key=CHANGE_ME