diff --git a/Habitica/build.gradle b/Habitica/build.gradle
index f5fcf8509..ee762421c 100644
--- a/Habitica/build.gradle
+++ b/Habitica/build.gradle
@@ -88,7 +88,7 @@ dependencies {
compile 'de.greenrobot:eventbus:2.4.0'
// IAP Handling / Verification
- compile 'org.solovyev.android:checkout:0.7.4@aar'
+ compile 'org.solovyev.android:checkout:0.7.5@aar'
compile 'com.facebook.android:facebook-android-sdk:4.7.0'
//Material Dialogs
diff --git a/Habitica/res/layout/fragment_gem_purchase.xml b/Habitica/res/layout/fragment_gem_purchase.xml
index c4fc54f2a..acf89a30f 100644
--- a/Habitica/res/layout/fragment_gem_purchase.xml
+++ b/Habitica/res/layout/fragment_gem_purchase.xml
@@ -3,10 +3,22 @@
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
+
+
+
+
+ android:layout_gravity="center_horizontal"
+ android:drawableRight="@drawable/ic_header_gem"
+ android:drawablePadding="5dp"
+ android:textColor="@color/white"/>
\ No newline at end of file
diff --git a/Habitica/src/com/habitrpg/android/habitica/APIHelper.java b/Habitica/src/com/habitrpg/android/habitica/APIHelper.java
index 41ecced8d..9c0e8fdda 100644
--- a/Habitica/src/com/habitrpg/android/habitica/APIHelper.java
+++ b/Habitica/src/com/habitrpg/android/habitica/APIHelper.java
@@ -19,8 +19,11 @@ import com.habitrpg.android.habitica.callbacks.HabitRPGUserCallback;
import com.habitrpg.android.habitica.callbacks.TaskDeletionCallback;
import com.habitrpg.android.habitica.callbacks.TaskScoringCallback;
import com.magicmicky.habitrpgwrapper.lib.api.ApiService;
+import com.magicmicky.habitrpgwrapper.lib.api.InAppPurchasesApiService;
import com.magicmicky.habitrpgwrapper.lib.api.Server;
import com.magicmicky.habitrpgwrapper.lib.api.TypeAdapter.TagsAdapter;
+import com.magicmicky.habitrpgwrapper.lib.models.PurchaseValidationRequest;
+import com.magicmicky.habitrpgwrapper.lib.models.PurchaseValidationResult;
import com.magicmicky.habitrpgwrapper.lib.models.SkillList;
import com.magicmicky.habitrpgwrapper.lib.models.TaskDirection;
import com.magicmicky.habitrpgwrapper.lib.models.UserAuth;
@@ -50,20 +53,21 @@ public class APIHelper implements ErrorHandler, Profiler {
private static final String TAG = "ApiHelper";
// I think we don't need the APIHelper anymore we could just use ApiService
public final ApiService apiService;
+ private final InAppPurchasesApiService inAppPurchasesService;
private Context mContext;
+ private HostConfig cfg;
//private OnHabitsAPIResult mResultListener;
//private HostConfig mConfig;
public APIHelper(Context c, final HostConfig cfg) {
this.mContext = c;
+ this.cfg = cfg;
RequestInterceptor requestInterceptor = new RequestInterceptor() {
@Override
public void intercept(RequestInterceptor.RequestFacade request) {
request.addHeader("x-api-key", cfg.getApi());
request.addHeader("x-api-user", cfg.getUser());
-
-
}
};
@@ -104,6 +108,19 @@ public class APIHelper implements ErrorHandler, Profiler {
.build();
this.apiService = adapter.create(ApiService.class);
+ server = new Server(cfg.getAddress(), false);
+
+ adapter = new RestAdapter.Builder()
+ .setEndpoint(server.toString())
+ .setErrorHandler(this)
+ .setProfiler(this)
+ .setLogLevel(BuildConfig.DEBUG ? RestAdapter.LogLevel.FULL : RestAdapter.LogLevel.NONE)
+ .setRequestInterceptor(requestInterceptor)
+ .setConverter(new GsonConverter(gson))
+
+ .build();
+
+ this.inAppPurchasesService = adapter.create(InAppPurchasesApiService.class);
}
private static final TypeAdapter booleanAsIntAdapter = new TypeAdapter() {
@@ -248,4 +265,9 @@ public class APIHelper implements ErrorHandler, Profiler {
public void reviveUser(HabitRPGUserCallback cb) {
apiService.revive(cb);
}
+
+ public PurchaseValidationResult validatePurchase(PurchaseValidationRequest request)
+ {
+ return inAppPurchasesService.validatePurchase(cfg.getUser(), cfg.getApi(), request);
+ }
}
diff --git a/Habitica/src/com/habitrpg/android/habitica/HabiticaApplication.java b/Habitica/src/com/habitrpg/android/habitica/HabiticaApplication.java
index 900274cbc..0a7fb7c94 100644
--- a/Habitica/src/com/habitrpg/android/habitica/HabiticaApplication.java
+++ b/Habitica/src/com/habitrpg/android/habitica/HabiticaApplication.java
@@ -21,14 +21,11 @@ import org.solovyev.android.checkout.Checkout;
import org.solovyev.android.checkout.Inventory;
import org.solovyev.android.checkout.ProductTypes;
import org.solovyev.android.checkout.Products;
-import org.solovyev.android.checkout.Purchase;
import org.solovyev.android.checkout.PurchaseVerifier;
import org.solovyev.android.checkout.RequestListener;
import java.io.File;
-import java.util.ArrayList;
import java.util.Arrays;
-import java.util.List;
import java.util.concurrent.Executor;
/**
@@ -39,12 +36,16 @@ public class HabiticaApplication extends Application {
public static HabiticaApplication Instance;
public static HabitRPGUser User;
+ public static APIHelper ApiHelper;
+
@Override
public void onCreate() {
super.onCreate();
Instance = this;
+ billing.connect();
+
FlowManager.init(this);
FacebookSdk.sdkInitialize(getApplicationContext());
@@ -94,6 +95,7 @@ public class HabiticaApplication extends Application {
// endregion
+ // region IAP - Specific
/**
* For better performance billing class should be used as singleton
@@ -103,7 +105,7 @@ public class HabiticaApplication extends Application {
@NonNull
@Override
public String getPublicKey() {
- return "sdfsdfdfsd";
+ return "DONT-NEED-IT";
}
@Nullable
@@ -114,24 +116,7 @@ public class HabiticaApplication extends Application {
@Override
public PurchaseVerifier getPurchaseVerifier() {
- return new PurchaseVerifier() {
- @Override
- public void verify(List purchases, RequestListener> requestListener) {
- final List verifiedPurchases = new ArrayList(purchases.size());
- /* for (Purchase purchase : purchases) {
- if (Security.verifyPurchase(publicKey, purchase.data, purchase.signature)) {
- verifiedPurchases.add(purchase);
- } else {
- if (isEmpty(purchase.signature)) {
- Billing.error("Cannot verify purchase: " + purchase + ". Signature is empty");
- } else {
- Billing.error("Cannot verify purchase: " + purchase + ". Wrong signature");
- }
- }
- }*/
- //requestListener.onSuccess(verifiedPurchases);
- }
- };
+ return new HabiticaPurchaseVerifier();
}
@Override
@@ -160,4 +145,5 @@ public class HabiticaApplication extends Application {
return checkout;
}
+ // endregion
}
diff --git a/Habitica/src/com/habitrpg/android/habitica/HabiticaPurchaseVerifier.java b/Habitica/src/com/habitrpg/android/habitica/HabiticaPurchaseVerifier.java
new file mode 100644
index 000000000..6791835c4
--- /dev/null
+++ b/Habitica/src/com/habitrpg/android/habitica/HabiticaPurchaseVerifier.java
@@ -0,0 +1,44 @@
+package com.habitrpg.android.habitica;
+
+import com.magicmicky.habitrpgwrapper.lib.models.PurchaseValidationRequest;
+import com.magicmicky.habitrpgwrapper.lib.models.PurchaseValidationResult;
+import com.magicmicky.habitrpgwrapper.lib.models.Transaction;
+
+import org.solovyev.android.checkout.BasePurchaseVerifier;
+import org.solovyev.android.checkout.Purchase;
+import org.solovyev.android.checkout.RequestListener;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by Negue on 26.11.2015.
+ */
+public class HabiticaPurchaseVerifier extends BasePurchaseVerifier {
+
+ @Override
+ protected void doVerify(final List purchases, final RequestListener> requestListener) {
+ final List verifiedPurchases = new ArrayList(purchases.size());
+
+ for(final Purchase purchase : purchases)
+ {
+ PurchaseValidationRequest validationRequest = new PurchaseValidationRequest();
+ validationRequest.transaction = new Transaction();
+ validationRequest.transaction.receipt = purchase.data;
+ validationRequest.transaction.signature = purchase.signature;
+
+ PurchaseValidationResult purchaseValidationResult = HabiticaApplication.ApiHelper.validatePurchase(validationRequest);
+
+ if (purchaseValidationResult.ok) {
+ verifiedPurchases.add(purchase);
+
+ requestListener.onSuccess(verifiedPurchases);
+ }
+ else
+ {
+ requestListener.onError(purchases.indexOf(purchase), new Exception(purchaseValidationResult.data.toString()));
+ }
+
+ }
+ }
+}
diff --git a/Habitica/src/com/habitrpg/android/habitica/LoginActivity.java b/Habitica/src/com/habitrpg/android/habitica/LoginActivity.java
index ecadede72..3d2cfb0ac 100644
--- a/Habitica/src/com/habitrpg/android/habitica/LoginActivity.java
+++ b/Habitica/src/com/habitrpg/android/habitica/LoginActivity.java
@@ -58,6 +58,9 @@ public class LoginActivity extends AppCompatActivity
public Boolean isRegistering;
private Menu menu;
+ private String apiAddress = getString(R.string.SP_address_default);
+ //private String apiAddress = "http://192.168.2.155:8080/"; // local testing
+
private CallbackManager callbackManager;
protected void onCreate(Bundle savedInstanceState) {
@@ -107,7 +110,7 @@ public class LoginActivity extends AppCompatActivity
HostConfig hc= PrefsActivity.fromContext(this);
if(hc ==null) {
- hc = new HostConfig(getString(R.string.SP_address_default), "80", "", "");
+ hc = new HostConfig(apiAddress, "80", "", "");
}
mApiHelper = new APIHelper(this,hc);
diff --git a/Habitica/src/com/habitrpg/android/habitica/MainActivity.java b/Habitica/src/com/habitrpg/android/habitica/MainActivity.java
index 56540eeab..3017688dc 100644
--- a/Habitica/src/com/habitrpg/android/habitica/MainActivity.java
+++ b/Habitica/src/com/habitrpg/android/habitica/MainActivity.java
@@ -1,5 +1,6 @@
package com.habitrpg.android.habitica;
+import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.os.Bundle;
@@ -18,6 +19,7 @@ import android.widget.TextView;
import com.crashlytics.android.Crashlytics;
import com.crashlytics.android.core.CrashlyticsCore;
import com.habitrpg.android.habitica.callbacks.HabitRPGUserCallback;
+import com.habitrpg.android.habitica.events.commands.OpenGemPurchaseFragmentCommand;
import com.habitrpg.android.habitica.prefs.PrefsActivity;
import com.habitrpg.android.habitica.ui.AvatarWithBarsViewModel;
import com.habitrpg.android.habitica.ui.MainDrawerBuilder;
@@ -34,8 +36,12 @@ import com.raizlabs.android.dbflow.runtime.transaction.TransactionListener;
import com.raizlabs.android.dbflow.sql.builder.Condition;
import com.raizlabs.android.dbflow.sql.language.Select;
+import org.solovyev.android.checkout.ActivityCheckout;
+import org.solovyev.android.checkout.Checkout;
+
import butterknife.ButterKnife;
import butterknife.InjectView;
+import de.greenrobot.event.EventBus;
import io.fabric.sdk.android.Fabric;
public class MainActivity extends InstabugAppCompatActivity implements HabitRPGUserCallback.OnUserReceived {
@@ -68,6 +74,9 @@ public class MainActivity extends InstabugAppCompatActivity implements HabitRPGU
APIHelper mAPIHelper;
+ // Checkout needs to be in the Activity..
+ public static ActivityCheckout checkout = null;
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -84,7 +93,7 @@ public class MainActivity extends InstabugAppCompatActivity implements HabitRPGU
this.hostConfig = PrefsActivity.fromContext(this);
HabiticaApplication.checkUserAuthentication(this, hostConfig);
- this.mAPIHelper = new APIHelper(this, hostConfig);
+ HabiticaApplication.ApiHelper = this.mAPIHelper = new APIHelper(this, hostConfig);
new Select().from(HabitRPGUser.class).where(Condition.column("id").eq(hostConfig.getUser())).async().querySingle(userTransactionListener);
@@ -110,6 +119,14 @@ public class MainActivity extends InstabugAppCompatActivity implements HabitRPGU
.build();
drawer.setSelectionAtPosition(1);
+
+ // Create Checkout
+
+ checkout = Checkout.forActivity(this, HabiticaApplication.Instance.getCheckout());
+
+ checkout.start();
+
+ EventBus.getDefault().register(this);
}
@@ -130,6 +147,10 @@ public class MainActivity extends InstabugAppCompatActivity implements HabitRPGU
}
}
+ public void onEvent(OpenGemPurchaseFragmentCommand cmd){
+ drawer.setSelection(MainDrawerBuilder.SIDEBAR_PURCHASE);
+ }
+
@Override
protected void onResume() {
super.onResume();
@@ -246,6 +267,21 @@ public class MainActivity extends InstabugAppCompatActivity implements HabitRPGU
}
}
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ checkout.onActivityResult(requestCode, resultCode, data);
+ }
+
+ @Override
+ public void onDestroy() {
+ if(checkout != null)
+ checkout.stop();
+
+ super.onDestroy();
+ }
+
public void showSnackbar(String content) {
showSnackbar(content, SnackbarDisplayType.NORMAL);
}
diff --git a/Habitica/src/com/habitrpg/android/habitica/events/BoughtGemsEvent.java b/Habitica/src/com/habitrpg/android/habitica/events/BoughtGemsEvent.java
new file mode 100644
index 000000000..c2ac9bc2b
--- /dev/null
+++ b/Habitica/src/com/habitrpg/android/habitica/events/BoughtGemsEvent.java
@@ -0,0 +1,12 @@
+package com.habitrpg.android.habitica.events;
+
+/**
+ * Created by Negue on 29.11.2015.
+ */
+public class BoughtGemsEvent {
+ public int NewGemsToAdd;
+
+ public BoughtGemsEvent(int newGemsToAdd) {
+ NewGemsToAdd = newGemsToAdd;
+ }
+}
diff --git a/Habitica/src/com/habitrpg/android/habitica/events/commands/OpenGemPurchaseFragmentCommand.java b/Habitica/src/com/habitrpg/android/habitica/events/commands/OpenGemPurchaseFragmentCommand.java
new file mode 100644
index 000000000..9dc1fd9e0
--- /dev/null
+++ b/Habitica/src/com/habitrpg/android/habitica/events/commands/OpenGemPurchaseFragmentCommand.java
@@ -0,0 +1,7 @@
+package com.habitrpg.android.habitica.events.commands;
+
+/**
+ * Created by Negue on 29.11.2015.
+ */
+public class OpenGemPurchaseFragmentCommand {
+}
diff --git a/Habitica/src/com/habitrpg/android/habitica/ui/AvatarWithBarsViewModel.java b/Habitica/src/com/habitrpg/android/habitica/ui/AvatarWithBarsViewModel.java
index b8b03b65e..08ccaea0f 100644
--- a/Habitica/src/com/habitrpg/android/habitica/ui/AvatarWithBarsViewModel.java
+++ b/Habitica/src/com/habitrpg/android/habitica/ui/AvatarWithBarsViewModel.java
@@ -13,14 +13,18 @@ import android.widget.TextView;
import com.habitrpg.android.habitica.R;
import com.habitrpg.android.habitica.databinding.ValueBarBinding;
+import com.habitrpg.android.habitica.events.BoughtGemsEvent;
+import com.habitrpg.android.habitica.events.commands.OpenGemPurchaseFragmentCommand;
import com.habitrpg.android.habitica.userpicture.UserPicture;
import com.magicmicky.habitrpgwrapper.lib.models.HabitRPGUser;
import com.magicmicky.habitrpgwrapper.lib.models.Stats;
+import de.greenrobot.event.EventBus;
+
/**
* Created by Negue on 14.06.2015.
*/
-public class AvatarWithBarsViewModel {
+public class AvatarWithBarsViewModel implements View.OnClickListener {
private ValueBarBinding hpBar;
private ValueBarBinding xpBar;
private ValueBarBinding mpBar;
@@ -32,6 +36,7 @@ public class AvatarWithBarsViewModel {
private Context context;
private TextView lvlText, goldText, silverText, gemsText;
+ private HabitRPGUser userObject;
public AvatarWithBarsViewModel(Context context, View v) {
this.context = context;
@@ -58,10 +63,17 @@ public class AvatarWithBarsViewModel {
setValueBar(hpBar, 50, 50, context.getString(R.string.HP_default), R.color.hpColor, R.drawable.ic_header_heart);
setValueBar(xpBar, 1, 1, context.getString(R.string.XP_default), R.color.xpColor, R.drawable.ic_header_exp);
setValueBar(mpBar, 100, 100, context.getString(R.string.MP_default), R.color.mpColor, R.drawable.ic_header_magic);
+
+ EventBus.getDefault().register(this);
+
+ gemsText.setClickable(true);
+ gemsText.setOnClickListener(this);
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public void updateData(HabitRPGUser user) {
+ userObject = user;
+
Stats stats = user.getStats();
char classShort;
String userClass = "";
@@ -138,4 +150,17 @@ public class AvatarWithBarsViewModel {
valueBar.setBarForegroundColor(color);
valueBar.icHeader.setImageResource(icon);
}
+
+ public void onEvent(BoughtGemsEvent gemsEvent){
+ Double gems = new Double(userObject.getBalance() * 4);
+ gems += gemsEvent.NewGemsToAdd;
+ gemsText.setText(gems.intValue() + "");
+ }
+
+ @Override
+ public void onClick(View view) {
+ // Gems Clicked
+
+ EventBus.getDefault().post(new OpenGemPurchaseFragmentCommand());
+ }
}
diff --git a/Habitica/src/com/habitrpg/android/habitica/ui/MainDrawerBuilder.java b/Habitica/src/com/habitrpg/android/habitica/ui/MainDrawerBuilder.java
index 215aafab8..189e0fbdd 100644
--- a/Habitica/src/com/habitrpg/android/habitica/ui/MainDrawerBuilder.java
+++ b/Habitica/src/com/habitrpg/android/habitica/ui/MainDrawerBuilder.java
@@ -33,13 +33,13 @@ import com.mikepenz.materialdrawer.model.interfaces.IProfile;
public class MainDrawerBuilder {
// Change the identificationIDs to the position IDs so that its easier to set the selected entry
- static final int SIDEBAR_TASKS = 0;
- static final int SIDEBAR_SKILLS = 1;
- static final int SIDEBAR_TAVERN = 3;
- static final int SIDEBAR_PARTY = 4;
- static final int SIDEBAR_PURCHASE = 5;
- static final int SIDEBAR_SETTINGS = 7;
- static final int SIDEBAR_ABOUT = 8;
+ public static final int SIDEBAR_TASKS = 0;
+ public static final int SIDEBAR_SKILLS = 1;
+ public static final int SIDEBAR_TAVERN = 3;
+ public static final int SIDEBAR_PARTY = 4;
+ public static final int SIDEBAR_PURCHASE = 5;
+ public static final int SIDEBAR_SETTINGS = 7;
+ public static final int SIDEBAR_ABOUT = 8;
diff --git a/Habitica/src/com/habitrpg/android/habitica/ui/fragments/GemsPurchaseFragment.java b/Habitica/src/com/habitrpg/android/habitica/ui/fragments/GemsPurchaseFragment.java
index 032e7da62..e99fe9a45 100644
--- a/Habitica/src/com/habitrpg/android/habitica/ui/fragments/GemsPurchaseFragment.java
+++ b/Habitica/src/com/habitrpg/android/habitica/ui/fragments/GemsPurchaseFragment.java
@@ -8,30 +8,36 @@ import android.view.ViewGroup;
import android.widget.Button;
import com.habitrpg.android.habitica.HabiticaApplication;
+import com.habitrpg.android.habitica.MainActivity;
import com.habitrpg.android.habitica.R;
+import com.habitrpg.android.habitica.events.BoughtGemsEvent;
+import com.habitrpg.android.habitica.ui.helpers.ViewHelper;
import org.solovyev.android.checkout.ActivityCheckout;
import org.solovyev.android.checkout.BillingRequests;
import org.solovyev.android.checkout.Checkout;
import org.solovyev.android.checkout.ProductTypes;
import org.solovyev.android.checkout.Purchase;
+import org.solovyev.android.checkout.Purchases;
import org.solovyev.android.checkout.RequestListener;
import butterknife.ButterKnife;
import butterknife.InjectView;
+import butterknife.OnClick;
+import de.greenrobot.event.EventBus;
+import io.fabric.sdk.android.Fabric;
/**
* Created by Negue on 24.11.2015.
*/
public class GemsPurchaseFragment extends BaseFragment {
+ private BillingRequests billingRequests;
+
@InjectView(R.id.btn_purchase_gems)
Button btnPurchaseGems;
- private ActivityCheckout checkout = null;
-
-
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
@@ -42,29 +48,44 @@ public class GemsPurchaseFragment extends BaseFragment {
ButterKnife.inject(this, v);
- checkout = Checkout.forActivity(this.activity, HabiticaApplication.Instance.getCheckout());
+ btnPurchaseGems.setEnabled(false);
+ ViewHelper.SetBackgroundTint(btnPurchaseGems, container.getResources().getColor(R.color.brand));
- checkout.start();
- // you only need this if this activity starts purchase process
- checkout.createPurchaseFlow(new RequestListener() {
+ MainActivity.checkout.destroyPurchaseFlow();
+
+ MainActivity.checkout.createPurchaseFlow(new RequestListener() {
@Override
public void onSuccess(Purchase purchase) {
+ if(purchase.sku.equals(HabiticaApplication.Purchase20Gems)){
+ billingRequests.consume(purchase.token, new RequestListener