Make equipment available in shop. Fixes #825

This commit is contained in:
Phillip Thelen 2017-10-31 18:31:06 +01:00
parent d0c7c9633f
commit 8035920079
55 changed files with 898 additions and 1070 deletions

View file

@ -20,7 +20,7 @@
tools:context=".ui.activities.MainActivity">
<android.support.v4.view.ViewPager
android:id="@+id/view_pager"
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"

View file

@ -5,7 +5,7 @@
xmlns:tools="http://schemas.android.com/tools"
tools:background="@color/brand">
<android.support.v4.view.ViewPager
android:id="@+id/view_pager"
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<RelativeLayout

View file

@ -24,7 +24,7 @@
app:tabMode="fixed" />
<android.support.v4.view.ViewPager
android:id="@+id/view_pager"
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="0px"
android:layout_weight="1"

View file

@ -3,7 +3,7 @@
android:layout_width="match_parent" android:layout_height="match_parent">
<com.habitrpg.android.habitica.ui.views.FadingViewPager
android:id="@+id/view_pager"
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/bottomBar" />

View file

@ -18,7 +18,7 @@
android:scrollbars="vertical"
android:paddingBottom="?attr/actionBarSize" />
<LinearLayout
android:id="@+id/empty_view"
android:id="@+id/emptyView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="48dp"

View file

@ -2,4 +2,4 @@
<com.habitrpg.android.habitica.ui.views.FadingViewPager xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/view_pager" />
android:id="@+id/viewPager" />

View file

@ -44,7 +44,7 @@
android:layout_marginBottom="8dp"/>
<LinearLayout
android:id="@+id/empty_view"
android:id="@+id/emptyView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"

View file

@ -18,7 +18,7 @@
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/empty_view"
android:id="@+id/emptyView"
style="@style/EmptyView"
android:visibility="gone"/>

View file

@ -22,7 +22,7 @@
android:paddingBottom="?attr/actionBarSize" />
<LinearLayout
android:id="@+id/empty_view"
android:id="@+id/emptyView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"

View file

@ -28,7 +28,7 @@
android:paddingBottom="?attr/actionBarSize" />
<FrameLayout
android:id="@+id/empty_view"
android:id="@+id/emptyView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"

View file

@ -2,4 +2,4 @@
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/view_pager" />
android:id="@+id/viewPager" />

View file

@ -21,7 +21,7 @@
android:background="@drawable/gradient_white"/>
<TextView
android:id="@+id/name_plate"
android:id="@+id/namePlate"
android:layout_width="wrap_content"
android:layout_height="28dp"
tools:text="Justin"

View file

@ -14,13 +14,21 @@
android:layout_height="wrap_content">
<TextView
android:id="@+id/label"
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_marginLeft="24dp"
android:layout_marginRight="24dp"
tools:text="Section Header"
android:layout_marginTop="12dp"
android:layout_marginBottom="12dp" />
<Spinner
android:id="@+id/classSelectionSpinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:layout_gravity="bottom"
/>
</LinearLayout>
</LinearLayout>

View file

@ -1,10 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent"
android:id="@+id/TV_simple_textview"
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:padding="@dimen/content_border">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/textView"
android:color="#FF000000"
android:textSize="15sp">
android:textSize="15sp"/>
</TextView>
</FrameLayout>

View file

@ -23,7 +23,7 @@
android:background="@color/widget_background" />
</FrameLayout>
<TextView
android:id="@+id/empty_view"
android:id="@+id/emptyView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"

View file

@ -712,4 +712,6 @@
<string name="distribute_class_help">Assigns more points to the attributes important to your Class.</string>
<string name="distribute_task_help">Assigns points based on the Strength, Intelligence, Constitution, and Perception categories associated with the tasks you complete.</string>
<string name="allocating_points">Allocating Points</string>
<string name="class_equipment">Class Equipment</string>
<string name="equipment_empty">You already have all equipment! More will be released during the Grand Galas, near the solstices and equinoxes.</string>
</resources>

View file

@ -273,7 +273,9 @@ public interface ApiService {
Observable<HabitResponse<PostChatMessageResult>> postPrivateMessage(@Body Map<String, String> messageDetails);
@GET("shops/{identifier}")
Observable<HabitResponse<Shop>> fetchShopInventory(@Path("identifier") String identifier);
Observable<HabitResponse<Shop>> retrieveShopInventory(@Path("identifier") String identifier);
@GET("shops/market-gear")
Observable<HabitResponse<Shop>> retrieveMarketGear();
//Push notifications
@POST("user/push-devices")

View file

@ -188,7 +188,7 @@ public interface ApiClient {
Observable<PostChatMessageResult> postPrivateMessage(Map<String, String> messageDetails);
Observable<Shop> fetchShopInventory(String identifier);
Observable<Shop> retrieveShopIventory(String identifier);
//Push notifications
Observable<List<Void>> addPushDevice(Map<String, String> pushDeviceData);
@ -251,4 +251,6 @@ public interface ApiClient {
Observable<Stats> allocatePoint(String stat);
Observable<Stats> bulkAllocatePoints(int strength, int intelligence, int constitution, int perception);
Observable<Shop> retrieveMarketGear();
}

View file

@ -75,7 +75,8 @@ public interface InventoryRepository extends ContentRepository {
Observable<BuyResponse> buyItem(User user, String id, double value);
Observable<Shop> fetchShopInventory(String identifier);
Observable<Shop> retrieveShopInventory(String identifier);
Observable<Shop> retrieveMarketGear();
Observable<Void> purchaseMysterySet(String categoryIdentifier);

View file

@ -850,8 +850,8 @@ public class ApiClientImpl implements Action1<Throwable>, ApiClient {
}
@Override
public Observable<Shop> fetchShopInventory(String identifier) {
return apiService.fetchShopInventory(identifier).compose(configureApiCallObserver());
public Observable<Shop> retrieveShopIventory(String identifier) {
return apiService.retrieveShopInventory(identifier).compose(configureApiCallObserver());
}
@Override
@ -998,4 +998,9 @@ public class ApiClientImpl implements Action1<Throwable>, ApiClient {
stats.put("per", perception);
return apiService.bulkAllocatePoints(stats).compose(configureApiCallObserver());
}
@Override
public Observable<Shop> retrieveMarketGear() {
return apiService.retrieveMarketGear().compose(configureApiCallObserver());
}
}

View file

@ -68,7 +68,7 @@ public class InventoryRepositoryImpl extends ContentRepositoryImpl<InventoryLoca
.map(items -> {
List<String> itemKeys = new ArrayList<>();
for (ShopItem item : items) {
itemKeys.add(item.key);
itemKeys.add(item.getKey());
}
itemKeys.add("potion");
itemKeys.add("armoire");
@ -80,17 +80,17 @@ public class InventoryRepositoryImpl extends ContentRepositoryImpl<InventoryLoca
if (items != null) {
for (Equipment item : items) {
ShopItem shopItem = new ShopItem();
shopItem.key = item.key;
shopItem.text = item.text;
shopItem.notes = item.notes;
shopItem.value = (int)item.value;
shopItem.currency = "gold";
shopItem.setKey(item.key);
shopItem.setText(item.text);
shopItem.setNotes(item.notes);
shopItem.setValue((int) item.value);
shopItem.setCurrency("gold");
if ("potion".equals(item.key)) {
shopItem.purchaseType = "potion";
shopItem.setPurchaseType("potion");
} else if ("armoire".equals(item.key)) {
shopItem.purchaseType = "armoire";
shopItem.setPurchaseType("armoire");
} else {
shopItem.purchaseType = "gear";
shopItem.setPurchaseType("gear");
}
buyableItems.add(shopItem);
@ -303,8 +303,13 @@ public class InventoryRepositoryImpl extends ContentRepositoryImpl<InventoryLoca
}
@Override
public Observable<Shop> fetchShopInventory(String identifier) {
return apiClient.fetchShopInventory(identifier);
public Observable<Shop> retrieveShopInventory(String identifier) {
return apiClient.retrieveShopIventory(identifier);
}
@Override
public Observable<Shop> retrieveMarketGear() {
return apiClient.retrieveMarketGear();
}
@Override
@ -332,7 +337,7 @@ public class InventoryRepositoryImpl extends ContentRepositoryImpl<InventoryLoca
if (!item.isValid()) {
return Observable.just(null);
}
return apiClient.togglePinnedItem(item.pinType, item.path)
return apiClient.togglePinnedItem(item.getPinType(), item.getPath())
.flatMap(aVoid -> retrieveInAppRewards());
}
}

View file

@ -0,0 +1,9 @@
package com.habitrpg.android.habitica.extensions
import android.support.annotation.IdRes
import android.view.View
fun <T : View> bindView(container: View, @IdRes res: Int) : Lazy<T> {
@Suppress("UNCHECKED_CAST")
return lazy(LazyThreadSafetyMode.NONE) { container.findViewById<T>(res) }
}

View file

@ -1,80 +0,0 @@
package com.habitrpg.android.habitica.models.shops;
import android.content.Context;
import com.habitrpg.android.habitica.R;
import java.util.List;
public class Shop {
public static final String MARKET = "market";
public static final String QUEST_SHOP = "questShop";
public static final String TIME_TRAVELERS_SHOP = "timeTravelersShop";
public static final String SEASONAL_SHOP = "seasonalShop";
public String identifier;
public String text;
public String notes;
public String imageName;
public List<ShopCategory> categories;
public String getIdentifier() {
return identifier;
}
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getNotes() {
return notes;
}
public void setNotes(String notes) {
this.notes = notes;
}
public String getImageName() {
return imageName;
}
public void setImageName(String imageName) {
this.imageName = imageName;
}
public List<ShopCategory> getCategories() {
return categories;
}
public void setCategories(List<ShopCategory> categories) {
this.categories = categories;
}
public int getNpcNameResource() {
switch (getIdentifier()) {
case "market":
return R.string.market_owner;
case "questShop":
return R.string.questShop_owner;
case "seasonalShop":
return R.string.seasonalShop_owner;
case "timeTravelersShop":
return R.string.timetravelers_owner;
default:
return R.string.market_owner;
}
}
public String getNpcName(Context context) {
return context.getString(getNpcNameResource());
}
}

View file

@ -0,0 +1,32 @@
package com.habitrpg.android.habitica.models.shops
import android.content.Context
import com.habitrpg.android.habitica.R
class Shop {
var identifier: String = ""
var text: String = ""
var notes: String = ""
var imageName: String = ""
var categories: MutableList<ShopCategory> = ArrayList()
val npcNameResource: Int
get() = when (identifier) {
MARKET -> R.string.market_owner
QUEST_SHOP -> R.string.questShop_owner
SEASONAL_SHOP -> R.string.seasonalShop_owner
TIME_TRAVELERS_SHOP -> R.string.timetravelers_owner
else -> R.string.market_owner
}
fun getNpcName(context: Context): String = context.getString(npcNameResource)
companion object {
const val MARKET = "market"
const val QUEST_SHOP = "questShop"
const val TIME_TRAVELERS_SHOP = "timeTravelersShop"
const val SEASONAL_SHOP = "seasonalShop"
}
}

View file

@ -1,53 +0,0 @@
package com.habitrpg.android.habitica.models.shops;
import java.util.List;
public class ShopCategory {
public String identifier;
public String text;
public String notes;
public Boolean purchaseAll;
public List<ShopItem> items;
public String getIdentifier() {
return identifier;
}
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getNotes() {
return notes;
}
public void setNotes(String notes) {
this.notes = notes;
}
public Boolean getPurchaseAll() {
return purchaseAll;
}
public void setPurchaseAll(Boolean purchaseAll) {
this.purchaseAll = purchaseAll;
}
public List<ShopItem> getItems() {
return items;
}
public void setItems(List<ShopItem> items) {
this.items = items;
}
}

View file

@ -0,0 +1,11 @@
package com.habitrpg.android.habitica.models.shops
class ShopCategory {
var identifier: String = ""
var text: String = ""
var notes: String = ""
var purchaseAll: Boolean? = null
var items: MutableList<ShopItem> = ArrayList()
}

View file

@ -1,186 +0,0 @@
package com.habitrpg.android.habitica.models.shops;
import android.content.res.Resources;
import com.google.gson.annotations.SerializedName;
import com.habitrpg.android.habitica.R;
import com.habitrpg.android.habitica.models.tasks.Task;
import com.habitrpg.android.habitica.models.user.User;
import io.realm.RealmObject;
import io.realm.annotations.PrimaryKey;
public class ShopItem extends RealmObject {
public static final String GEM_FOR_GOLD = "gem";
@PrimaryKey
public String key;
public String text;
public String notes;
@SerializedName("class")
public String imageName;
public Integer value;
public boolean locked;
public boolean limited;
public String currency;
public String purchaseType;
public String categoryIdentifier;
public Integer limitedNumberLeft;
public ShopItemUnlockCondition unlockCondition;
public String path;
public String isSuggested;
public String pinType;
public static ShopItem makeGemItem(Resources res) {
ShopItem item = new ShopItem();
item.key = GEM_FOR_GOLD;
item.text = res.getString(R.string.gem_shop);
item.notes = res.getString(R.string.gem_for_gold_description);
item.imageName = "gem_shop";
item.value = 20;
item.currency = "gold";
item.purchaseType = "gems";
return item;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getNotes() {
return notes;
}
public void setNotes(String notes) {
this.notes = notes;
}
public String getImageName() {
if (imageName != null) {
if (imageName.contains(" ")) {
return imageName.split(" ")[1];
} else {
return imageName;
}
} else {
return "shop_" + key;
}
}
public void setImageName(String imageName) {
this.imageName = imageName;
}
public Integer getValue() {
return value;
}
public void setValue(Integer value) {
this.value = value;
}
public Boolean getLocked() {
return locked;
}
public void setLocked(Boolean locked) {
this.locked = locked;
}
public String getCurrency() {
if (currency == null) {
return "";
}
return currency;
}
public void setCurrency(String currency) {
this.currency = currency;
}
public String getPurchaseType() {
return purchaseType;
}
public void setPurchaseType(String purchaseType) {
this.purchaseType = purchaseType;
}
public String getCategoryIdentifier() {
return categoryIdentifier;
}
public void setCategoryIdentifier(String categoryIdentifier) {
this.categoryIdentifier = categoryIdentifier;
}
public Integer getLimitedNumberLeft() {
return limitedNumberLeft;
}
public void setLimitedNumberLeft(Integer limitedNumberLeft) {
this.limitedNumberLeft = limitedNumberLeft;
}
public ShopItemUnlockCondition getUnlockCondition() {
return unlockCondition;
}
public void setUnlockCondition(ShopItemUnlockCondition unlockCondition) {
this.unlockCondition = unlockCondition;
}
public boolean canBuy(User user) {
if (user == null || user.getStats() == null) {
return false;
}
if (getCurrency().equals("gold")) {
return getValue() <= user.getStats().getGp();
} else if (getCurrency().equals("gems")) {
return getValue() <= (user.getBalance() * 4);
} else {
return false;
}
}
public boolean isLimited() {
return limited;
}
public boolean isTypeItem() {
return "eggs".equals(purchaseType) || "hatchingPotions".equals(purchaseType) || "food".equals(purchaseType) || "armoire".equals(purchaseType) || "potion".equals(purchaseType);
}
public boolean isTypeQuest() {
return "quests".equals(purchaseType);
}
public boolean isTypeGear() {
return "gear".equals(purchaseType);
}
public boolean isTypeAnimal() {
return "pets".equals(purchaseType) || "mounts".equals(purchaseType);
}
@Override
public boolean equals(Object obj) {
if (ShopItem.class.isAssignableFrom(obj.getClass())) {
ShopItem otherItem = (ShopItem) obj;
return this.key.equals(otherItem.key);
}
return super.equals(obj);
}
}

View file

@ -0,0 +1,90 @@
package com.habitrpg.android.habitica.models.shops
import android.content.res.Resources
import com.google.gson.annotations.SerializedName
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.models.user.User
import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
open class ShopItem : RealmObject() {
@PrimaryKey
var key: String = ""
var text: String = ""
var notes: String = ""
@SerializedName("class")
var imageName: String? = null
get() {
return if (field != null) {
if (field!!.contains(" ")) {
field!!.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[1]
} else {
field
}
} else {
"shop_" + key
}
}
var value: Int = 0
var locked: Boolean = false
var isLimited: Boolean = false
var currency: String = ""
var purchaseType: String = ""
var categoryIdentifier: String = ""
var limitedNumberLeft: Int? = null
var unlockCondition: ShopItemUnlockCondition? = null
var path: String? = null
var isSuggested: String? = null
var pinType: String? = null
val isTypeItem: Boolean
get() = "eggs" == purchaseType || "hatchingPotions" == purchaseType || "food" == purchaseType || "armoire" == purchaseType || "potion" == purchaseType
val isTypeQuest: Boolean
get() = "quests" == purchaseType
val isTypeGear: Boolean
get() = "gear" == purchaseType
val isTypeAnimal: Boolean
get() = "pets" == purchaseType || "mounts" == purchaseType
fun canBuy(user: User?): Boolean {
if (user == null || user.stats == null) {
return false
}
return when(currency) {
"gold" -> value <= user.stats.getGp()
"gems" -> value <= user.balance * 4
else -> false
}
}
override fun equals(other: Any?): Boolean {
if (ShopItem::class.java.isAssignableFrom(other!!.javaClass)) {
val otherItem = other as ShopItem?
return this.key == otherItem!!.key
}
return super.equals(other)
}
companion object {
const val GEM_FOR_GOLD = "gem"
fun makeGemItem(res: Resources?): ShopItem {
val item = ShopItem()
item.key = GEM_FOR_GOLD
item.text = res?.getString(R.string.gem_shop) ?: ""
item.notes = res?.getString(R.string.gem_for_gold_description) ?: ""
item.imageName = "gem_shop"
item.value = 20
item.currency = "gold"
item.purchaseType = "gems"
return item
}
}
}

View file

@ -1,25 +0,0 @@
package com.habitrpg.android.habitica.models.shops;
import com.habitrpg.android.habitica.R;
import io.realm.RealmObject;
import io.realm.annotations.PrimaryKey;
public class ShopItemUnlockCondition extends RealmObject {
@PrimaryKey
String condition;
public int readableUnlockConditionId() {
switch (this.condition) {
case "party invite":
return R.string.party_invite;
case "login incentive":
return R.string.login_incentive;
case "create account":
return R.string.create_account;
default:
return R.string.empty;
}
}
}

View file

@ -0,0 +1,17 @@
package com.habitrpg.android.habitica.models.shops
import com.habitrpg.android.habitica.R
import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
open class ShopItemUnlockCondition : RealmObject() {
@PrimaryKey
internal var condition: String? = null
fun readableUnlockConditionId(): Int = when (this.condition) {
"party invite" -> R.string.party_invite
else -> R.string.empty
}
}

View file

@ -42,7 +42,7 @@ public class GemPurchaseActivity extends BaseActivity implements InAppMessageLis
CrashlyticsProxy crashlyticsProxy;
@BindView(R.id.tab_layout)
TabLayout tabLayout;
@BindView(R.id.view_pager)
@BindView(R.id.viewPager)
ViewPager viewPager;
List<CheckoutFragment> fragments = new ArrayList<>();
private ActivityCheckout checkout;

View file

@ -31,7 +31,7 @@ public class IntroActivity extends BaseActivity implements View.OnClickListener,
@Inject
public ApiClient apiClient;
@BindView(R.id.view_pager)
@BindView(R.id.viewPager)
ViewPager pager;
@BindView(R.id.view_pager_indicator)
IconPageIndicator indicator;

View file

@ -48,7 +48,7 @@ public class PartyInviteActivity extends BaseActivity {
UserRepository userRepository;
@BindView(R.id.tab_layout)
TabLayout tabLayout;
@BindView(R.id.view_pager)
@BindView(R.id.viewPager)
ViewPager viewPager;
List<PartyInviteFragment> fragments = new ArrayList<>();
private String userIdToInvite;

View file

@ -36,7 +36,6 @@ import com.habitrpg.android.habitica.ui.views.FadingViewPager;
import com.viewpagerindicator.IconPageIndicator;
import com.viewpagerindicator.IconPagerAdapter;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import java.util.Calendar;
@ -61,7 +60,7 @@ public class SetupActivity extends BaseActivity implements ViewPager.OnPageChang
protected UserRepository userRepository;
@Inject
protected TaskRepository taskRepository;
@BindView(R.id.view_pager)
@BindView(R.id.viewPager)
FadingViewPager pager;
@BindView(R.id.nextButton)
Button nextButton;

View file

@ -1,256 +0,0 @@
package com.habitrpg.android.habitica.ui.adapter.inventory;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import com.facebook.common.executors.CallerThreadExecutor;
import com.facebook.common.references.CloseableReference;
import com.facebook.datasource.DataSource;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.view.SimpleDraweeView;
import com.facebook.imagepipeline.core.ImagePipeline;
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber;
import com.facebook.imagepipeline.image.CloseableImage;
import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.imagepipeline.request.ImageRequestBuilder;
import com.habitrpg.android.habitica.R;
import com.habitrpg.android.habitica.events.commands.OpenGemPurchaseFragmentCommand;
import com.habitrpg.android.habitica.helpers.RxErrorHandler;
import com.habitrpg.android.habitica.models.inventory.Item;
import com.habitrpg.android.habitica.models.shops.Shop;
import com.habitrpg.android.habitica.models.shops.ShopCategory;
import com.habitrpg.android.habitica.models.shops.ShopItem;
import com.habitrpg.android.habitica.models.user.User;
import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils;
import com.habitrpg.android.habitica.ui.viewHolders.SectionViewHolder;
import com.habitrpg.android.habitica.ui.viewHolders.ShopItemViewHolder;
import org.greenrobot.eventbus.EventBus;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import butterknife.BindView;
import butterknife.ButterKnife;
import io.realm.RealmResults;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
public class ShopRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<Object> items;
private String shopIdentifier;
private Map<String, Item> ownedItems = new HashMap<>();
private String shopSpriteSuffix;
private User user;
private List<String> pinnedItemKeys;
public void setShop(Shop shop, String shopSpriteSuffix) {
this.shopSpriteSuffix = shopSpriteSuffix;
shopIdentifier = shop.identifier;
items = new ArrayList<>();
items.add(shop);
for (ShopCategory category : shop.categories) {
if (category.items != null && category.items.size() > 0) {
items.add(category);
for (ShopItem item : category.items) {
item.categoryIdentifier = category.getIdentifier();
items.add(item);
}
}
}
notifyDataSetChanged();
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == 0) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.shop_header, parent, false);
return new ShopHeaderViewHolder(view);
} else if (viewType == 1) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.shop_section_header, parent, false);
return new SectionViewHolder(view);
} else if (viewType == 2) {
View view = LayoutInflater.from(parent.getContext())
.inflate(getEmptyViewResource(), parent, false);
return new EmptyStateViewHolder(view);
} else {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.row_shopitem, parent, false);
ShopItemViewHolder viewHolder = new ShopItemViewHolder(view);
viewHolder.shopIdentifier = shopIdentifier;
return viewHolder;
}
}
private int getEmptyViewResource() {
if (Shop.SEASONAL_SHOP.equals(this.shopIdentifier)) {
return R.layout.empty_view_seasonal_shop;
} else if (Shop.TIME_TRAVELERS_SHOP.equals(this.shopIdentifier)) {
return R.layout.empty_view_timetravelers;
}
return R.layout.simple_textview;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (position > (this.items.size()-1)) {
return;
}
Object obj = this.items.get(position);
if (obj.getClass().equals(Shop.class)) {
((ShopHeaderViewHolder) holder).bind((Shop) obj, shopSpriteSuffix);
} else if (obj.getClass().equals(ShopCategory.class)) {
((SectionViewHolder) holder).bind(((ShopCategory) obj).getText());
} else if (obj.getClass().equals(ShopItem.class)) {
ShopItem item = (ShopItem) items.get(position);
((ShopItemViewHolder) holder).bind(item, item.canBuy(user));
if (ownedItems.containsKey(item.getKey())) {
((ShopItemViewHolder) holder).setItemCount(ownedItems.get(item.getKey()).getOwned());
}
if (pinnedItemKeys != null) {
((ShopItemViewHolder) holder).setIsPinned(pinnedItemKeys.contains(item.getKey()));
} else {
((ShopItemViewHolder) holder).setIsPinned(false);
}
}
}
@Override
public int getItemViewType(int position) {
if (position > (this.items.size()-1)) {
return 2;
} else if (this.items.get(position).getClass().equals(Shop.class)) {
return 0;
} else if (this.items.get(position).getClass().equals(ShopCategory.class)) {
return 1;
} else {
return 3;
}
}
@Override
public int getItemCount() {
int size = items != null ? items.size() : 0;
if (size == 1) {
return 2;
}
return size;
}
public void setOwnedItems(Map<String, Item> ownedItems) {
this.ownedItems = ownedItems;
this.notifyDataSetChanged();
}
public void setUser(User user) {
this.user = user;
this.notifyDataSetChanged();
}
public void setPinnedItemKeys(List<String> pinnedItemKeys) {
this.pinnedItemKeys = pinnedItemKeys;
this.notifyDataSetChanged();
}
static class ShopHeaderViewHolder extends RecyclerView.ViewHolder {
private final Context context;
@BindView(R.id.sceneView)
public SimpleDraweeView sceneView;
@BindView(R.id.backgroundView)
public ImageView backgroundView;
@BindView(R.id.name_plate)
public TextView namePlate;
@BindView(R.id.descriptionView)
public TextView descriptionView;
ShopHeaderViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
context = itemView.getContext();
descriptionView.setMovementMethod(LinkMovementMethod.getInstance());
}
public void bind(Shop shop, String shopSpriteSuffix) {
DataBindingUtils.loadImage(sceneView, shop.identifier+"_scene"+shopSpriteSuffix);
backgroundView.setScaleType(ImageView.ScaleType.FIT_START);
ImageRequest imageRequest = ImageRequestBuilder
.newBuilderWithSource(Uri.parse("https://habitica-assets.s3.amazonaws.com/mobileApp/images/" + shop.identifier+"_background"+shopSpriteSuffix+".png"))
.build();
ImagePipeline imagePipeline = Fresco.getImagePipeline();
final DataSource<CloseableReference<CloseableImage>>
dataSource = imagePipeline.fetchDecodedImage(imageRequest, this);
dataSource.subscribe(new BaseBitmapDataSubscriber() {
@Override
public void onNewResultImpl(@Nullable Bitmap bitmap) {
if (dataSource.isFinished() && bitmap != null){
float aspectRatio = bitmap.getWidth() /
(float) bitmap.getHeight();
int height = (int) context.getResources().getDimension(R.dimen.shop_height);
int width = Math.round(height * aspectRatio);
BitmapDrawable drawable = new BitmapDrawable(context.getResources(), Bitmap.createScaledBitmap(bitmap, width, height, false));
drawable.setTileModeX(Shader.TileMode.REPEAT);
Observable.just(drawable)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(bitmapDrawable -> backgroundView.setBackground(bitmapDrawable), RxErrorHandler.handleEmptyError());
dataSource.close();
}
}
@Override
public void onFailureImpl(DataSource dataSource) {
if (dataSource != null) {
dataSource.close();
}
}
}, CallerThreadExecutor.getInstance());
descriptionView.setText(Html.fromHtml(shop.getNotes()));
namePlate.setText(shop.getNpcNameResource());
}
}
public static class EmptyStateViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.subscribeButton)
@Nullable
Button subscribeButton;
public EmptyStateViewHolder(View view) {
super(view);
ButterKnife.bind(this, view);
if (subscribeButton != null) {
subscribeButton.setOnClickListener(view1 -> EventBus.getDefault().post(new OpenGemPurchaseFragmentCommand()));
}
}
}
}

View file

@ -0,0 +1,286 @@
package com.habitrpg.android.habitica.ui.adapter.inventory
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Shader
import android.graphics.drawable.BitmapDrawable
import android.net.Uri
import android.support.v7.widget.RecyclerView
import android.text.Html
import android.text.method.LinkMovementMethod
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import butterknife.ButterKnife
import com.facebook.common.executors.CallerThreadExecutor
import com.facebook.common.references.CloseableReference
import com.facebook.datasource.DataSource
import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.drawee.view.SimpleDraweeView
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber
import com.facebook.imagepipeline.image.CloseableImage
import com.facebook.imagepipeline.request.ImageRequestBuilder
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.events.commands.OpenGemPurchaseFragmentCommand
import com.habitrpg.android.habitica.extensions.bindView
import com.habitrpg.android.habitica.extensions.inflate
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.models.inventory.Item
import com.habitrpg.android.habitica.models.shops.Shop
import com.habitrpg.android.habitica.models.shops.ShopCategory
import com.habitrpg.android.habitica.models.shops.ShopItem
import com.habitrpg.android.habitica.models.user.User
import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils
import com.habitrpg.android.habitica.ui.viewHolders.SectionViewHolder
import com.habitrpg.android.habitica.ui.viewHolders.ShopItemViewHolder
import org.greenrobot.eventbus.EventBus
import rx.Observable
import rx.android.schedulers.AndroidSchedulers
import rx.functions.Action1
class ShopRecyclerAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private val items: MutableList<Any> = ArrayList()
private var shopIdentifier: String? = null
private var ownedItems: Map<String, Item> = HashMap()
private var shopSpriteSuffix: String? = null
var context: Context? = null
var user: User? = null
set(value) {
field = value
this.notifyDataSetChanged()
}
private var pinnedItemKeys: List<String> = ArrayList()
var gearCategories: MutableList<ShopCategory> = ArrayList()
set(value) {
field = value
notifyDataSetChanged()
}
internal var selectedGearCategory: String = ""
set(value) {
field = value
if (field != "") {
notifyDataSetChanged()
}
}
private val emptyViewResource: Int
get() = when (this.shopIdentifier) {
Shop.SEASONAL_SHOP -> R.layout.empty_view_seasonal_shop
Shop.TIME_TRAVELERS_SHOP -> R.layout.empty_view_timetravelers
else -> R.layout.simple_textview
}
fun setShop(shop: Shop?, shopSpriteSuffix: String) {
if (shop == null) {
return
}
this.shopSpriteSuffix = shopSpriteSuffix
shopIdentifier = shop.identifier
items.clear()
items.add(shop)
for (category in shop.categories) {
if (category.items.size > 0) {
items.add(category)
for (item in category.items) {
item.categoryIdentifier = category.identifier
items.add(item)
}
}
}
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder =
when (viewType) {
0 -> {
val view = parent.inflate(R.layout.shop_header)
ShopHeaderViewHolder(view)
}
1 -> {
val view = parent.inflate(R.layout.shop_section_header)
SectionViewHolder(view)
}
2 -> {
val view = parent.inflate(emptyViewResource)
EmptyStateViewHolder(view)
}
else -> {
val view = parent.inflate(R.layout.row_shopitem)
val viewHolder = ShopItemViewHolder(view)
viewHolder.shopIdentifier = shopIdentifier
viewHolder
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val obj = getItem(position)
if (obj != null) {
when (obj.javaClass) {
Shop::class.java -> (holder as ShopHeaderViewHolder).bind(obj as Shop, shopSpriteSuffix)
ShopCategory::class.java -> {
val category = obj as ShopCategory
(holder as SectionViewHolder).bind((category).text)
if (gearCategories.contains(category)) {
val adapter = ArrayAdapter<CharSequence>(context, android.R.layout.simple_spinner_dropdown_item, gearCategories.map { it.identifier })
holder.spinnerAdapter = adapter
holder.selectedItem = gearCategories.indexOf(category)
holder.spinnerSelectionChanged = {
if (selectedGearCategory != gearCategories[holder.selectedItem].identifier) {
selectedGearCategory = gearCategories[holder.selectedItem].identifier
}
}
}
}
ShopItem::class.java -> {
val item = obj as ShopItem
(holder as ShopItemViewHolder).bind(item, item.canBuy(user))
if (ownedItems.containsKey(item.key)) {
holder.setItemCount(ownedItems[item.key]?.owned ?: 0)
}
holder.setIsPinned(pinnedItemKeys.contains(item.key))
}
String::class.java -> (holder as EmptyStateViewHolder).text = obj as String
}
}
}
private fun getItem(position: Int): Any? {
if (items.size == 0) {
return null
}
if (position == 0) {
return items[0]
}
if (position <= getGearItemCount()) {
return when {
position == 1 -> getSelectedShopCategory()
getSelectedShopCategory()?.items?.size ?: 0 <= position-2 -> return context?.getString(R.string.equipment_empty)
else -> getSelectedShopCategory()?.items?.get(position-2)
}
} else {
val itemPosition = position - getGearItemCount()
if (itemPosition > items.size-1) {
return null
}
return items[itemPosition]
}
}
override fun getItemViewType(position: Int): Int = when(getItem(position)?.javaClass) {
Shop::class.java -> 0
ShopCategory::class.java -> 1
ShopItem::class.java -> 3
else -> 2
}
override fun getItemCount(): Int {
val size = items.size + getGearItemCount()
return if (size == 1) {
2
} else size
}
private fun getGearItemCount(): Int {
return if (selectedGearCategory == "") {
0
} else {
val selectedCategory: ShopCategory? = getSelectedShopCategory()
return if (selectedCategory != null) {
return if (selectedCategory.items.size == 0) {
2
} else {
selectedCategory.items.size+1
}
} else {
0
}
}
}
private fun getSelectedShopCategory() =
gearCategories.firstOrNull { selectedGearCategory == it.identifier }
fun setOwnedItems(ownedItems: Map<String, Item>) {
this.ownedItems = ownedItems
this.notifyDataSetChanged()
}
fun setPinnedItemKeys(pinnedItemKeys: List<String>) {
this.pinnedItemKeys = pinnedItemKeys
this.notifyDataSetChanged()
}
internal class ShopHeaderViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val context: Context
private val descriptionView: TextView by bindView(itemView, R.id.descriptionView)
private val sceneView: SimpleDraweeView by bindView(itemView, R.id.sceneView)
private val backgroundView: ImageView by bindView(itemView, R.id.backgroundView)
private val namePlate: TextView by bindView(itemView, R.id.namePlate)
init {
ButterKnife.bind(this, itemView)
context = itemView.context
descriptionView.movementMethod = LinkMovementMethod.getInstance()
}
fun bind(shop: Shop, shopSpriteSuffix: String?) {
DataBindingUtils.loadImage(sceneView, shop.identifier + "_scene" + shopSpriteSuffix)
backgroundView.scaleType = ImageView.ScaleType.FIT_START
val imageRequest = ImageRequestBuilder
.newBuilderWithSource(Uri.parse("https://habitica-assets.s3.amazonaws.com/mobileApp/images/" + shop.identifier + "_background" + shopSpriteSuffix + ".png"))
.build()
val imagePipeline = Fresco.getImagePipeline()
val dataSource = imagePipeline.fetchDecodedImage(imageRequest, this)
dataSource.subscribe(object : BaseBitmapDataSubscriber() {
override fun onFailureImpl(dataSource: DataSource<CloseableReference<CloseableImage>>?) {
dataSource?.close()
}
public override fun onNewResultImpl(bitmap: Bitmap?) {
if (dataSource.isFinished && bitmap != null) {
val aspectRatio = bitmap.width / bitmap.height.toFloat()
val height = context.resources.getDimension(R.dimen.shop_height).toInt()
val width = Math.round(height * aspectRatio)
val drawable = BitmapDrawable(context.resources, Bitmap.createScaledBitmap(bitmap, width, height, false))
drawable.tileModeX = Shader.TileMode.REPEAT
Observable.just(drawable)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(Action1 { backgroundView.background = it }, RxErrorHandler.handleEmptyError())
dataSource.close()
}
}
}, CallerThreadExecutor.getInstance())
descriptionView.text = Html.fromHtml(shop.notes)
namePlate.setText(shop.npcNameResource)
}
}
class EmptyStateViewHolder(view: View) : RecyclerView.ViewHolder(view) {
private val subscribeButton: Button? by bindView(itemView, R.id.subscribeButton)
private val textView: TextView? by bindView(itemView, R.id.textView)
init {
ButterKnife.bind(this, view)
subscribeButton?.setOnClickListener { EventBus.getDefault().post(OpenGemPurchaseFragmentCommand()) }
}
var text: String? = null
set(value) {
field = value
textView?.text = field
}
}
}

View file

@ -47,7 +47,7 @@ public class ItemRecyclerFragment extends BaseFragment {
private static final String ITEM_TYPE_KEY = "CLASS_TYPE_KEY";
@BindView(R.id.recyclerView)
public RecyclerViewEmptySupport recyclerView;
@BindView(R.id.empty_view)
@BindView(R.id.emptyView)
public View emptyView;
@BindView(R.id.empty_text_view)
public TextView emptyTextView;

View file

@ -27,7 +27,7 @@ public class ItemsFragment extends BaseMainFragment {
super.onCreateView(inflater, container, savedInstanceState);
View v = inflater.inflate(R.layout.fragment_viewpager, container, false);
viewPager = (ViewPager) v.findViewById(R.id.view_pager);
viewPager = (ViewPager) v.findViewById(R.id.viewPager);
viewPager.setCurrentItem(0);

View file

@ -1,193 +0,0 @@
package com.habitrpg.android.habitica.ui.fragments.inventory.shops;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.widget.GridLayoutManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.TextView;
import com.habitrpg.android.habitica.R;
import com.habitrpg.android.habitica.components.AppComponent;
import com.habitrpg.android.habitica.data.InventoryRepository;
import com.habitrpg.android.habitica.data.UserRepository;
import com.habitrpg.android.habitica.helpers.RemoteConfigManager;
import com.habitrpg.android.habitica.helpers.RxErrorHandler;
import com.habitrpg.android.habitica.models.shops.Shop;
import com.habitrpg.android.habitica.models.shops.ShopCategory;
import com.habitrpg.android.habitica.models.shops.ShopItem;
import com.habitrpg.android.habitica.models.user.User;
import com.habitrpg.android.habitica.ui.adapter.inventory.ShopRecyclerAdapter;
import com.habitrpg.android.habitica.ui.fragments.BaseFragment;
import com.habitrpg.android.habitica.ui.helpers.RecyclerViewEmptySupport;
import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import butterknife.BindView;
import butterknife.ButterKnife;
public class ShopFragment extends BaseFragment {
private static final String SHOP_IDENTIFIER_KEY = "SHOP_IDENTIFIER_KEY";
@BindView(R.id.recyclerView)
public RecyclerViewEmptySupport recyclerView;
@BindView(R.id.empty_view)
public TextView emptyView;
public ShopRecyclerAdapter adapter;
public String shopIdentifier;
public User user;
public Shop shop;
@Inject
InventoryRepository inventoryRepository;
@Inject
UserRepository userRepository;
@Inject
RemoteConfigManager configManager;
private View view;
private GridLayoutManager layoutManager;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
if (view == null) {
view = inflater.inflate(R.layout.fragment_recyclerview, container, false);
}
unbinder = ButterKnife.bind(this, view);
recyclerView.setBackgroundResource(R.color.white);
adapter = (ShopRecyclerAdapter) recyclerView.getAdapter();
if (adapter == null) {
adapter = new ShopRecyclerAdapter();
recyclerView.setAdapter(adapter);
recyclerView.setItemAnimator(new SafeDefaultItemAnimator());
}
if (layoutManager == null) {
layoutManager = new GridLayoutManager(getContext(), 2);
layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
if (adapter.getItemViewType(position) < 3) {
return layoutManager.getSpanCount();
} else {
return 1;
}
}
});
recyclerView.setLayoutManager(layoutManager);
}
if (savedInstanceState != null) {
this.shopIdentifier = savedInstanceState.getString(SHOP_IDENTIFIER_KEY, "");
}
if (shop == null) {
loadShopInventory();
} else {
adapter.setShop(shop, configManager.shopSpriteSuffix());
}
adapter.setUser(user);
return view;
}
@Override
public void onDestroyView() {
userRepository.close();
inventoryRepository.close();
super.onDestroyView();
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
final View finalView = view;
finalView.post(() -> setGridSpanCount(finalView.getWidth()));
}
private void loadShopInventory() {
String shopUrl = "";
switch (this.shopIdentifier) {
case Shop.MARKET:
shopUrl = "market";
break;
case Shop.QUEST_SHOP:
shopUrl = "quests";
break;
case Shop.TIME_TRAVELERS_SHOP:
shopUrl = "time-travelers";
break;
case Shop.SEASONAL_SHOP:
shopUrl = "seasonal";
break;
}
this.inventoryRepository.fetchShopInventory(shopUrl)
.map(shop1 -> {
if (shop1.identifier.equals(Shop.MARKET)) {
if (user != null && user.isValid() && user.getPurchased().getPlan().isActive()) {
ShopCategory specialCategory = new ShopCategory();
specialCategory.text = getString(R.string.special);
specialCategory.items = new ArrayList<>();
ShopItem item = ShopItem.makeGemItem(getContext().getResources());
item.limitedNumberLeft = user.getPurchased().getPlan().numberOfGemsLeft();
specialCategory.items.add(item);
shop1.categories.add(specialCategory);
}
}
return shop1;
})
.subscribe(shop -> {
this.shop = shop;
this.adapter.setShop(shop, configManager.shopSpriteSuffix());
}, RxErrorHandler.handleEmptyError());
compositeSubscription.add(this.inventoryRepository.getOwnedItems(user)
.subscribe(ownedItems -> adapter.setOwnedItems(ownedItems), RxErrorHandler.handleEmptyError()));
compositeSubscription.add(this.inventoryRepository.getInAppRewards()
.map(shopItems -> {
List<String> itemKeys = new ArrayList<>();
for (ShopItem item : shopItems) {
itemKeys.add(item.getKey());
}
return itemKeys;
})
.subscribe(pinnedItems -> adapter.setPinnedItemKeys(pinnedItems), RxErrorHandler.handleEmptyError()));
}
@Override
public void injectFragment(AppComponent component) {
component.inject(this);
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(SHOP_IDENTIFIER_KEY, this.shopIdentifier);
}
private void setGridSpanCount(int width) {
int spanCount = 0;
if (getContext() != null && getContext().getResources() != null) {
float itemWidth;
itemWidth = getContext().getResources().getDimension(R.dimen.pet_width);
spanCount = (int) (width / itemWidth);
}
if (spanCount == 0) {
spanCount = 1;
}
layoutManager.setSpanCount(spanCount);
layoutManager.requestLayout();
}
}

View file

@ -0,0 +1,179 @@
package com.habitrpg.android.habitica.ui.fragments.inventory.shops
import android.os.Bundle
import android.support.v7.widget.GridLayoutManager
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.components.AppComponent
import com.habitrpg.android.habitica.data.InventoryRepository
import com.habitrpg.android.habitica.data.UserRepository
import com.habitrpg.android.habitica.helpers.RemoteConfigManager
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.models.shops.Shop
import com.habitrpg.android.habitica.models.shops.ShopCategory
import com.habitrpg.android.habitica.models.shops.ShopItem
import com.habitrpg.android.habitica.models.user.User
import com.habitrpg.android.habitica.ui.adapter.inventory.ShopRecyclerAdapter
import com.habitrpg.android.habitica.ui.fragments.BaseFragment
import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator
import kotlinx.android.synthetic.main.fragment_recyclerview.*
import rx.functions.Action1
import javax.inject.Inject
class ShopFragment : BaseFragment() {
var adapter: ShopRecyclerAdapter? = null
var shopIdentifier: String? = null
var user: User? = null
var shop: Shop? = null
@Inject
lateinit var inventoryRepository: InventoryRepository
@Inject
lateinit var userRepository: UserRepository
@Inject
lateinit var configManager: RemoteConfigManager
private val layoutManager: GridLayoutManager by lazy {
val layoutManager = GridLayoutManager(context, 2)
layoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int): Int {
return if (adapter?.getItemViewType(position) ?: 0 < 3) {
layoutManager.spanCount
} else {
1
}
}
}
return@lazy layoutManager
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
super.onCreateView(inflater, container, savedInstanceState)
return inflater.inflate(R.layout.fragment_recyclerview, container, false)
}
override fun onDestroyView() {
userRepository.close()
inventoryRepository.close()
super.onDestroyView()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
recyclerView.setBackgroundResource(R.color.white)
adapter = recyclerView.adapter as ShopRecyclerAdapter?
if (adapter == null) {
adapter = ShopRecyclerAdapter()
adapter?.context = context
recyclerView.adapter = adapter
recyclerView.itemAnimator = SafeDefaultItemAnimator()
}
if (recyclerView.layoutManager == null) {
recyclerView.layoutManager = layoutManager
}
if (savedInstanceState != null) {
this.shopIdentifier = savedInstanceState.getString(SHOP_IDENTIFIER_KEY, "")
}
if (shop == null) {
loadShopInventory()
} else {
adapter?.setShop(shop, configManager.shopSpriteSuffix())
}
adapter?.user = user
view.post { setGridSpanCount(view.width) }
}
private fun loadShopInventory() {
val shopUrl = when (this.shopIdentifier) {
Shop.MARKET -> "market"
Shop.QUEST_SHOP -> "quests"
Shop.TIME_TRAVELERS_SHOP -> "time-travelers"
Shop.SEASONAL_SHOP -> "seasonal"
else -> ""
}
this.inventoryRepository.retrieveShopInventory(shopUrl)
.map { shop1 ->
if (shop1.identifier == Shop.MARKET) {
val user = user
if (user != null && user.isValid && user.purchased.plan.isActive) {
val specialCategory = ShopCategory()
specialCategory.text = getString(R.string.special)
val item = ShopItem.makeGemItem(context?.resources)
item.limitedNumberLeft = user.purchased.plan.numberOfGemsLeft()
specialCategory.items.add(item)
shop1.categories.add(specialCategory)
}
}
shop1
}
.subscribe(Action1 {
this.shop = it
if (Shop.MARKET == shopIdentifier) {
loadMarketGear()
}
this.adapter?.setShop(it, configManager.shopSpriteSuffix())
}, RxErrorHandler.handleEmptyError())
compositeSubscription.add(this.inventoryRepository.getOwnedItems(user)
.subscribe(Action1 { adapter?.setOwnedItems(it) }, RxErrorHandler.handleEmptyError()))
compositeSubscription.add(this.inventoryRepository.inAppRewards
.map<List<String>> { it.map { it.key } }
.subscribe(Action1 { adapter?.setPinnedItemKeys(it) }, RxErrorHandler.handleEmptyError()))
}
private fun loadMarketGear() {
inventoryRepository.retrieveMarketGear()
.zipWith(inventoryRepository.ownedEquipment.first().map { it.map { it.key } }, { shop, equipment ->
for (category in shop.categories) {
val items = category.items.filter({
!equipment.contains(it.key)
})
category.items.clear()
category.items.addAll(items)
}
shop
})
.subscribe(Action1 {
adapter?.selectedGearCategory = user?.stats?.habitClass ?: ""
adapter?.gearCategories = it.categories
}, RxErrorHandler.handleEmptyError())
}
override fun injectFragment(component: AppComponent) {
component.inject(this)
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putString(SHOP_IDENTIFIER_KEY, this.shopIdentifier)
}
private fun setGridSpanCount(width: Int) {
var spanCount = 0
val context = context
if (context != null && context.resources != null) {
val itemWidth: Float = context.resources.getDimension(R.dimen.pet_width)
spanCount = (width / itemWidth).toInt()
}
if (spanCount == 0) {
spanCount = 1
}
layoutManager.spanCount = spanCount
layoutManager.requestLayout()
}
companion object {
private const val SHOP_IDENTIFIER_KEY = "SHOP_IDENTIFIER_KEY"
}
}

View file

@ -1,156 +0,0 @@
package com.habitrpg.android.habitica.ui.fragments.inventory.shops;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.habitrpg.android.habitica.R;
import com.habitrpg.android.habitica.components.AppComponent;
import com.habitrpg.android.habitica.data.InventoryRepository;
import com.habitrpg.android.habitica.models.shops.Shop;
import com.habitrpg.android.habitica.models.user.User;
import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment;
import com.habitrpg.android.habitica.ui.views.CurrencyViews;
import javax.inject.Inject;
public class ShopsFragment extends BaseMainFragment {
@Inject
InventoryRepository inventoryRepository;
public ViewPager viewPager;
private CurrencyViews currencyView;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
this.usesTabLayout = true;
hideToolbar();
disableToolbarScrolling();
super.onCreateView(inflater, container, savedInstanceState);
View v = inflater.inflate(R.layout.fragment_viewpager, container, false);
viewPager = (ViewPager) v.findViewById(R.id.view_pager);
viewPager.setCurrentItem(0);
setViewPagerAdapter();
return v;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
currencyView = new CurrencyViews(getContext());
if (toolbarAccessoryContainer != null) {
toolbarAccessoryContainer.addView(currencyView);
}
updateCurrencyView();
}
@Override
public void onDestroyView() {
if (toolbarAccessoryContainer != null) {
toolbarAccessoryContainer.removeView(currencyView);
}
showToolbar();
enableToolbarScrolling();
inventoryRepository.close();
super.onDestroyView();
}
@Override
public void injectFragment(AppComponent component) {
component.inject(this);
}
public void setViewPagerAdapter() {
android.support.v4.app.FragmentManager fragmentManager = getChildFragmentManager();
viewPager.setAdapter(new FragmentPagerAdapter(fragmentManager) {
@Override
public Fragment getItem(int position) {
ShopFragment fragment = new ShopFragment();
switch (position) {
case 0: {
fragment.shopIdentifier = Shop.MARKET;
break;
}
case 1: {
fragment.shopIdentifier = Shop.QUEST_SHOP;
break;
}
case 2: {
fragment.shopIdentifier = Shop.SEASONAL_SHOP;
break;
}
case 3: {
fragment.shopIdentifier = Shop.TIME_TRAVELERS_SHOP;
break;
}
}
fragment.user = ShopsFragment.this.user;
return fragment;
}
@Override
public int getCount() {
return 4;
}
@Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return getContext().getString(R.string.market);
case 1:
return getContext().getString(R.string.quests);
case 2:
return getContext().getString(R.string.seasonalShop);
case 3:
return getContext().getString(R.string.timeTravelers);
}
return "";
}
});
if (tabLayout != null && viewPager != null) {
tabLayout.setupWithViewPager(viewPager);
}
}
@Override
public String customTitle() {
if (!isAdded()) {
return "";
}
return getString(R.string.sidebar_shops);
}
@Override
public void updateUserData(User user) {
super.updateUserData(user);
updateCurrencyView();
}
private void updateCurrencyView() {
if (user == null || currencyView == null) {
return;
}
currencyView.setGold(user.getStats().getGp());
currencyView.setGems(user.getGemCount());
currencyView.setHourglasses(user.getHourglassCount());
}
}

View file

@ -0,0 +1,115 @@
package com.habitrpg.android.habitica.ui.fragments.inventory.shops
import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentPagerAdapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.components.AppComponent
import com.habitrpg.android.habitica.data.InventoryRepository
import com.habitrpg.android.habitica.models.shops.Shop
import com.habitrpg.android.habitica.models.user.User
import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment
import com.habitrpg.android.habitica.ui.views.CurrencyViews
import kotlinx.android.synthetic.main.fragment_viewpager.*
import javax.inject.Inject
class ShopsFragment : BaseMainFragment() {
@Inject
lateinit var inventoryRepository: InventoryRepository
private val currencyView: CurrencyViews by lazy {
CurrencyViews(context)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
this.usesTabLayout = true
hideToolbar()
disableToolbarScrolling()
super.onCreateView(inflater, container, savedInstanceState)
return inflater.inflate(R.layout.fragment_viewpager, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewPager.currentItem = 0
setViewPagerAdapter()
toolbarAccessoryContainer?.addView(currencyView)
updateCurrencyView()
}
override fun onDestroyView() {
toolbarAccessoryContainer?.removeView(currencyView)
showToolbar()
enableToolbarScrolling()
inventoryRepository.close()
super.onDestroyView()
}
override fun injectFragment(component: AppComponent) {
component.inject(this)
}
private fun setViewPagerAdapter() {
val fragmentManager = childFragmentManager
viewPager!!.adapter = object : FragmentPagerAdapter(fragmentManager) {
override fun getItem(position: Int): Fragment {
val fragment = ShopFragment()
fragment.shopIdentifier = when (position) {
0 -> Shop.MARKET
1 -> Shop.QUEST_SHOP
2 -> Shop.SEASONAL_SHOP
3 -> Shop.TIME_TRAVELERS_SHOP
else -> ""
}
fragment.user = this@ShopsFragment.user
return fragment
}
override fun getCount(): Int = 4
override fun getPageTitle(position: Int): CharSequence? {
return when (position) {
0 -> return context?.getString(R.string.market)
1 -> return context?.getString(R.string.quests)
2 -> return context?.getString(R.string.seasonalShop)
3 -> return context?.getString(R.string.timeTravelers)
else -> ""
}
}
}
if (tabLayout != null && viewPager != null) {
tabLayout!!.setupWithViewPager(viewPager)
}
}
override fun customTitle(): String {
return if (!isAdded) {
""
} else getString(R.string.sidebar_shops)
}
override fun updateUserData(user: User) {
super.updateUserData(user)
updateCurrencyView()
}
private fun updateCurrencyView() {
if (user == null) {
return
}
currencyView.setGold(user!!.stats.getGp())
currencyView.setGems(user!!.gemCount)
currencyView.setHourglasses(user!!.hourglassCount)
}
}

View file

@ -23,7 +23,7 @@ public class StableFragment extends BaseMainFragment {
super.onCreateView(inflater, container, savedInstanceState);
View v = inflater.inflate(R.layout.fragment_viewpager, container, false);
viewPager = (ViewPager) v.findViewById(R.id.view_pager);
viewPager = (ViewPager) v.findViewById(R.id.viewPager);
viewPager.setCurrentItem(0);

View file

@ -40,7 +40,7 @@ public class StableRecyclerFragment extends BaseFragment {
@BindView(R.id.recyclerView)
public RecyclerViewEmptySupport recyclerView;
@BindView(R.id.empty_view)
@BindView(R.id.emptyView)
public TextView emptyView;
public StableRecyclerAdapter adapter;
public String itemType;

View file

@ -6,7 +6,6 @@ import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@ -51,7 +50,7 @@ public class GuildFragment extends BaseMainFragment implements Action1<Group> {
super.onCreateView(inflater, container, savedInstanceState);
View v = inflater.inflate(R.layout.fragment_viewpager, container, false);
viewPager = (ViewPager) v.findViewById(R.id.view_pager);
viewPager = (ViewPager) v.findViewById(R.id.viewPager);
viewPager.setCurrentItem(0);

View file

@ -41,7 +41,7 @@ public class TavernFragment extends BaseMainFragment {
super.onCreateView(inflater, container, savedInstanceState);
View v = inflater.inflate(R.layout.fragment_viewpager, container, false);
viewPager = (ViewPager) v.findViewById(R.id.view_pager);
viewPager = (ViewPager) v.findViewById(R.id.viewPager);
viewPager.setCurrentItem(0);

View file

@ -46,7 +46,7 @@ public class ChallengeListFragment extends BaseMainFragment implements SwipeRefr
SwipeRefreshLayout swipeRefreshLayout;
@BindView(R.id.recyclerView)
RecyclerViewEmptySupport recyclerView;
@BindView(R.id.empty_view)
@BindView(R.id.emptyView)
public View emptyView;
private ChallengesListViewAdapter challengeAdapter;

View file

@ -39,7 +39,7 @@ public class ChallengesOverviewFragment extends BaseMainFragment {
super.onCreateView(inflater, container, savedInstanceState);
View v = inflater.inflate(R.layout.fragment_viewpager, container, false);
viewPager = (ViewPager) v.findViewById(R.id.view_pager);
viewPager = (ViewPager) v.findViewById(R.id.viewPager);
setViewPagerAdapter();

View file

@ -63,7 +63,7 @@ public class PartyFragment extends BaseMainFragment {
super.onCreateView(inflater, container, savedInstanceState);
View v = inflater.inflate(R.layout.fragment_viewpager, container, false);
viewPager = (ViewPager) v.findViewById(R.id.view_pager);
viewPager = (ViewPager) v.findViewById(R.id.viewPager);
viewPager.setCurrentItem(0);

View file

@ -7,10 +7,8 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.SimpleItemAnimator;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.util.TypedValue;
import android.view.LayoutInflater;
@ -83,7 +81,7 @@ public class TaskRecyclerViewFragment extends BaseFragment implements View.OnCli
@BindView(R.id.recyclerView)
public RecyclerViewEmptySupport recyclerView;
@BindView(R.id.empty_view)
@BindView(R.id.emptyView)
ViewGroup emptyView;
@BindView(R.id.empty_view_title)
TextView emptyViewTitle;

View file

@ -77,7 +77,7 @@ public class TasksFragment extends BaseMainFragment {
View v = inflater.inflate(R.layout.fragment_viewpager, container, false);
viewPager = v.findViewById(R.id.view_pager);
viewPager = v.findViewById(R.id.viewPager);
View view = inflater.inflate(R.layout.floating_menu_tasks, floatingMenuWrapper, true);
if (FloatingActionMenu.class.equals(view.getClass())) {
floatingMenu = (FloatingActionMenu) view;

View file

@ -1,44 +0,0 @@
package com.habitrpg.android.habitica.ui.viewHolders;
import android.content.Context;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.habitrpg.android.habitica.R;
import butterknife.BindView;
import butterknife.ButterKnife;
public class SectionViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.label)
TextView label;
@BindView(R.id.purchaseSetButton)
@Nullable
Button purchaseSetButton;
Context context;
public SectionViewHolder(View itemView) {
super(itemView);
context = itemView.getContext();
ButterKnife.bind(this, itemView);
if (this.purchaseSetButton != null) {
this.purchaseSetButton.setVisibility(View.GONE);
}
}
public void bind(String title) {
try {
Integer stringID = context.getResources().getIdentifier("section" + title, "string", context.getPackageName());
this.label.setText(context.getString(stringID));
} catch (Exception e) {
this.label.setText(title);
}
}
}

View file

@ -0,0 +1,60 @@
package com.habitrpg.android.habitica.ui.viewHolders
import android.content.Context
import android.support.v7.widget.RecyclerView
import android.view.View
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.Button
import android.widget.Spinner
import android.widget.TextView
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.extensions.bindView
class SectionViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val label: TextView by bindView(itemView, R.id.label)
private val purchaseSetButton: Button? by bindView(itemView, R.id.purchaseSetButton)
private val selectionSpinner: Spinner? by bindView(itemView, R.id.classSelectionSpinner)
var context: Context = itemView.context
var spinnerSelectionChanged: (() -> Unit)? = null
init {
this.purchaseSetButton?.visibility = View.GONE
selectionSpinner?.onItemSelectedListener = object: AdapterView.OnItemSelectedListener {
override fun onNothingSelected(parent: AdapterView<*>?) {
spinnerSelectionChanged?.invoke()
}
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
spinnerSelectionChanged?.invoke()
}
};
}
fun bind(title: String) {
try {
val stringID = context.resources.getIdentifier("section" + title, "string", context.packageName)
this.label.text = context.getString(stringID)
} catch (e: Exception) {
this.label.text = title
}
}
var spinnerAdapter: ArrayAdapter<CharSequence>? = null
set(value) {
field = value
selectionSpinner?.adapter = field
selectionSpinner?.visibility = if (value != null) View.VISIBLE else View.GONE
}
var selectedItem: Int = 0
get() = selectionSpinner?.selectedItemPosition ?: 0
set(value) {
field = value
selectionSpinner?.setSelection(field)
}
}

View file

@ -101,8 +101,8 @@ public class PurchaseDialog extends AlertDialog {
currencyView.setGems(user.getGemCount());
currencyView.setHourglasses(user.getHourglassCount());
if ("gems".equals(shopItem.purchaseType)) {
int gemsLeft = shopItem.limitedNumberLeft != null ? shopItem.limitedNumberLeft : 0;
if ("gems".equals(shopItem.getPurchaseType())) {
int gemsLeft = shopItem.getLimitedNumberLeft() != null ? shopItem.getLimitedNumberLeft() : 0;
int maxGems = user.getPurchased().getPlan().totalNumberOfGems();
if (maxGems > 0) {
limitedTextView.setText(getContext().getString(R.string.gems_left_max, gemsLeft, maxGems));
@ -134,7 +134,7 @@ public class PurchaseDialog extends AlertDialog {
buyButton.setVisibility(View.VISIBLE);
if (item.getUnlockCondition() == null) {
priceLabel.setValue(Double.valueOf(item.getValue()));
priceLabel.setValue((double) item.getValue());
priceLabel.setCurrency(item.getCurrency());
} else {
setBuyButtonEnabled(false);
@ -158,7 +158,7 @@ public class PurchaseDialog extends AlertDialog {
} else if (shopItem.isTypeGear()) {
contentView = new PurchaseDialogGearContent(getContext());
inventoryRepository.getEquipment(item.getKey()).first().subscribe(((PurchaseDialogGearContent) contentView)::setEquipment, RxErrorHandler.handleEmptyError());
} else if ("gems".equals(shopItem.purchaseType)) {
} else if ("gems".equals(shopItem.getPurchaseType())) {
contentView = new PurchaseDialogGemsContent(getContext());
} else {
contentView = new PurchaseDialogBaseContent(getContext());
@ -209,17 +209,17 @@ public class PurchaseDialog extends AlertDialog {
if (shopItem.isValid()) {
if (shopItem.canBuy(user)) {
Observable<Void> observable;
if ((shopIdentifier != null && shopIdentifier.equals(Shop.TIME_TRAVELERS_SHOP)) || "mystery_set".equals(shopItem.purchaseType)) {
if (shopItem.purchaseType.equals("gear")) {
observable = inventoryRepository.purchaseMysterySet(shopItem.categoryIdentifier);
if ((shopIdentifier != null && shopIdentifier.equals(Shop.TIME_TRAVELERS_SHOP)) || "mystery_set".equals(shopItem.getPurchaseType())) {
if (shopItem.getPurchaseType().equals("gear")) {
observable = inventoryRepository.purchaseMysterySet(shopItem.getCategoryIdentifier());
} else {
observable = inventoryRepository.purchaseHourglassItem(shopItem.purchaseType, shopItem.key);
observable = inventoryRepository.purchaseHourglassItem(shopItem.getPurchaseType(), shopItem.getKey());
}
} else if (shopItem.purchaseType.equals("quests") && shopItem.getCurrency().equals("gold")) {
observable = inventoryRepository.purchaseQuest(shopItem.key);
} else if ("gold".equals(shopItem.currency) && !"gem".equals(shopItem.key)) {
observable = inventoryRepository.buyItem(user, shopItem.key, shopItem.value).flatMap(buyResponse -> {
if (shopItem.key.equals("armoire")) {
} else if (shopItem.getPurchaseType().equals("quests") && shopItem.getCurrency().equals("gold")) {
observable = inventoryRepository.purchaseQuest(shopItem.getKey());
} else if ("gold".equals(shopItem.getCurrency()) && !"gem".equals(shopItem.getKey())) {
observable = inventoryRepository.buyItem(user, shopItem.getKey(), shopItem.getValue()).flatMap(buyResponse -> {
if (shopItem.getKey().equals("armoire")) {
if (buyResponse.armoire.get("type").equals("gear")) {
snackbarText[0] = getContext().getString(R.string.armoireEquipment, buyResponse.armoire.get("dropText"));
} else if (buyResponse.armoire.get("type").equals("food")) {
@ -231,12 +231,12 @@ public class PurchaseDialog extends AlertDialog {
return Observable.just(null);
});
} else {
observable = inventoryRepository.purchaseItem(shopItem.purchaseType, shopItem.key);
observable = inventoryRepository.purchaseItem(shopItem.getPurchaseType(), shopItem.getKey());
}
observable
.doOnNext(aVoid -> {
ShowSnackbarEvent event = new ShowSnackbarEvent();
event.title = getContext().getString(R.string.successful_purchase, shopItem.text);
event.title = getContext().getString(R.string.successful_purchase, shopItem.getText());
if (snackbarText[0].length() > 0) {
event.text = snackbarText[0];
}
@ -259,11 +259,11 @@ public class PurchaseDialog extends AlertDialog {
});
} else {
InsufficientCurrencyDialog dialog = null;
if ("gold".equals(shopItem.currency)) {
if ("gold".equals(shopItem.getCurrency())) {
dialog = new InsufficientGoldDialog(getContext());
} else if ("gems".equals(shopItem.currency)) {
} else if ("gems".equals(shopItem.getCurrency())) {
dialog = new InsufficientGemsDialog(getContext());
} else if ("hourglasses".equals(shopItem.currency)) {
} else if ("hourglasses".equals(shopItem.getCurrency())) {
dialog = new InsufficientHourglassesDialog(getContext());
}
if (dialog != null) {

View file

@ -15,7 +15,6 @@ import com.habitrpg.android.habitica.R;
import com.habitrpg.android.habitica.data.ApiClient;
import com.habitrpg.android.habitica.data.TaskRepository;
import com.habitrpg.android.habitica.helpers.RxErrorHandler;
import com.habitrpg.android.habitica.models.responses.TaskDirection;
import com.habitrpg.android.habitica.modules.AppModule;
import com.habitrpg.android.habitica.ui.activities.MainActivity;
@ -86,7 +85,7 @@ public abstract class TaskListWidgetProvider extends BaseWidgetProvider {
intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.widget_task_list);
rv.setRemoteAdapter(appWidgetId, R.id.list_view, intent);
rv.setEmptyView(R.id.list, R.id.empty_view);
rv.setEmptyView(R.id.list, R.id.emptyView);
rv.setTextViewText(R.id.widget_title, context.getString(getTitleResId()));
// if the user click on the title: open App