Panagiotis Triantafyllou

added filters request

......@@ -21,7 +21,6 @@ import ly.warp.sdk.io.models.Couponset;
import ly.warp.sdk.utils.WarpUtils;
import ly.warp.sdk.utils.WarplyManagerHelper;
import ly.warp.sdk.views.GridSpaceItemDecoration;
import ly.warp.sdk.views.VerticalSpaceItemDecoration;
public class CouponsetsActivity extends Activity implements View.OnClickListener {
// ===========================================================
......
......@@ -14,6 +14,7 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.constraintlayout.widget.ConstraintLayout;
......@@ -36,6 +37,7 @@ import ly.warp.sdk.io.callbacks.CallbackReceiver;
import ly.warp.sdk.io.models.CarouselItem;
import ly.warp.sdk.io.models.Coupon;
import ly.warp.sdk.io.models.Couponset;
import ly.warp.sdk.io.models.Filter;
import ly.warp.sdk.io.models.User;
import ly.warp.sdk.utils.WarpUtils;
import ly.warp.sdk.utils.WarplyManagerHelper;
......@@ -55,7 +57,7 @@ public class HomeActivity extends Activity implements View.OnClickListener, Coup
// ===========================================================
private RelativeLayout mPbLoading;
private TextView mTvHeaderTitle, mTvMyCouponsTitle, mTvMyCouponsValue;
private TextView mTvHeaderTitle, mTvMyCouponsTitle, mTvMyCouponsValue, mTvSearchTitle;
private LinearLayout mLlUserTags, mLlMyCoupons;
/* View Pager */
// private ViewPager2 mBannerViewPager;
......@@ -92,6 +94,7 @@ public class HomeActivity extends Activity implements View.OnClickListener, Coup
WarplyManager.getCoupons(mCouponsCallback);
WarplyManager.getCarousel(mCarouselCallback);
WarplyManager.getCouponsets(null, null, mCouponsetsCallback);
WarplyManager.getFilters(mFiltersCallback);
}
@Override
......@@ -145,9 +148,10 @@ public class HomeActivity extends Activity implements View.OnClickListener, Coup
mTvHeaderTitle = findViewById(R.id.tv_header_title);
mLlUserTags = findViewById(R.id.ll_user_tags);
mRvBannerViewPager = findViewById(R.id.banner_viewpager);
mTvSearchTitle = findViewById(R.id.tv_search_title);
WarpUtils.renderCustomFont(this, R.font.ping_lcg_bold, mTvHeaderTitle, mTvMyCouponsValue);
WarpUtils.renderCustomFont(this, R.font.ping_lcg_regular, mTvMyCouponsTitle);
WarpUtils.renderCustomFont(this, R.font.ping_lcg_regular, mTvMyCouponsTitle, mTvSearchTitle);
}
private void setUpUser() {
......@@ -403,6 +407,8 @@ public class HomeActivity extends Activity implements View.OnClickListener, Coup
private final CallbackReceiver<ArrayList<Coupon>> mCouponsCallback = new CallbackReceiver<ArrayList<Coupon>>() {
@Override
public void onSuccess(ArrayList<Coupon> result) {
Toast.makeText(HomeActivity.this, "COUPONS SUCCESS", Toast.LENGTH_SHORT).show();
int activeCoupons = 0;
for (Coupon coupon : result) {
if (coupon.getStatus() == 1) activeCoupons++;
......@@ -412,7 +418,19 @@ public class HomeActivity extends Activity implements View.OnClickListener, Coup
@Override
public void onFailure(int errorCode) {
Toast.makeText(HomeActivity.this, "COUPONS ERROR", Toast.LENGTH_SHORT).show();
}
};
private final CallbackReceiver<Filter> mFiltersCallback = new CallbackReceiver<Filter>() {
@Override
public void onSuccess(Filter result) {
Toast.makeText(HomeActivity.this, "FILTERS SUCCESS", Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure(int errorCode) {
Toast.makeText(HomeActivity.this, "FILTERS ERROR", Toast.LENGTH_SHORT).show();
}
};
}
......
......@@ -8,6 +8,7 @@ import org.json.JSONObject;
import java.io.Serializable;
/**
* Created by Panagiotis Triantafyllou on 17-Mar-26.
* Model representing a single item from the carousel (get_carousel) API response.
*/
public class CarouselItem implements Parcelable, Serializable {
......
package ly.warp.sdk.io.models;
import android.os.Parcel;
import android.os.Parcelable;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.Serializable;
import java.util.ArrayList;
/**
* Created by Panagiotis Triantafyllou on 17-Mar-26.
* Model representing the response from the getFilters API.
* Contains offer categories (with children) and regions.
*/
public class Filter implements Parcelable, Serializable {
private static final long serialVersionUID = 3312345678901234567L;
private static final String OFFER_CATEGORIES = "offer_categories";
private static final String REGIONS = "regions";
private ArrayList<OfferCategory> offerCategories;
private ArrayList<String> regions;
// ================================================================================
// Inner class
// ================================================================================
public static class OfferCategory {
private static final String ADMIN_NAME = "admin_name";
private static final String NAME = "name";
private static final String IMAGE = "image";
private static final String UUID = "uuid";
private static final String PARENT = "parent";
private static final String CHILDREN = "children";
private String adminName;
private String name;
private String image;
private String uuid;
private String parent;
private ArrayList<OfferCategory> children;
private static String optNullableString(JSONObject json, String key) {
return json.isNull(key) ? null : json.optString(key);
}
public OfferCategory() {
this.adminName = null;
this.name = null;
this.image = null;
this.uuid = null;
this.parent = null;
this.children = new ArrayList<>();
}
public OfferCategory(JSONObject json) {
if (json != null) {
this.adminName = optNullableString(json, ADMIN_NAME);
this.name = optNullableString(json, NAME);
this.image = optNullableString(json, IMAGE);
this.uuid = optNullableString(json, UUID);
this.parent = optNullableString(json, PARENT);
this.children = new ArrayList<>();
JSONArray childrenArray = json.optJSONArray(CHILDREN);
if (childrenArray != null) {
for (int i = 0; i < childrenArray.length(); i++) {
JSONObject childJson = childrenArray.optJSONObject(i);
if (childJson != null) {
this.children.add(new OfferCategory(childJson));
}
}
}
}
}
public JSONObject toJSONObject() {
JSONObject jObj = new JSONObject();
try {
jObj.put(ADMIN_NAME, this.adminName != null ? this.adminName : JSONObject.NULL);
jObj.put(NAME, this.name != null ? this.name : JSONObject.NULL);
jObj.put(IMAGE, this.image != null ? this.image : JSONObject.NULL);
jObj.put(UUID, this.uuid != null ? this.uuid : JSONObject.NULL);
jObj.put(PARENT, this.parent != null ? this.parent : JSONObject.NULL);
JSONArray childrenArray = new JSONArray();
if (this.children != null) {
for (OfferCategory child : this.children) {
childrenArray.put(child.toJSONObject());
}
}
jObj.put(CHILDREN, childrenArray);
} catch (JSONException e) {
e.printStackTrace();
}
return jObj;
}
// Getters
public String getAdminName() { return adminName; }
public String getName() { return name; }
public String getImage() { return image; }
public String getUuid() { return uuid; }
public String getParent() { return parent; }
public ArrayList<OfferCategory> getChildren() { return children; }
// Setters
public void setAdminName(String adminName) { this.adminName = adminName; }
public void setName(String name) { this.name = name; }
public void setImage(String image) { this.image = image; }
public void setUuid(String uuid) { this.uuid = uuid; }
public void setParent(String parent) { this.parent = parent; }
public void setChildren(ArrayList<OfferCategory> children) { this.children = children; }
}
// ================================================================================
// Constructors
// ================================================================================
public Filter() {
this.offerCategories = new ArrayList<>();
this.regions = new ArrayList<>();
}
public Filter(JSONObject json) {
this.offerCategories = new ArrayList<>();
this.regions = new ArrayList<>();
if (json != null) {
JSONArray categoriesArray = json.optJSONArray(OFFER_CATEGORIES);
if (categoriesArray != null) {
for (int i = 0; i < categoriesArray.length(); i++) {
JSONObject categoryJson = categoriesArray.optJSONObject(i);
if (categoryJson != null) {
this.offerCategories.add(new OfferCategory(categoryJson));
}
}
}
JSONArray regionsArray = json.optJSONArray(REGIONS);
if (regionsArray != null) {
for (int i = 0; i < regionsArray.length(); i++) {
String region = regionsArray.optString(i, null);
if (region != null && !region.isEmpty()) {
this.regions.add(region);
}
}
}
}
}
public Filter(Parcel source) {
this.regions = new ArrayList<>();
source.readStringList(this.regions);
this.offerCategories = new ArrayList<>();
try {
String categoriesStr = source.readString();
if (categoriesStr != null) {
JSONArray categoriesArray = new JSONArray(categoriesStr);
for (int i = 0; i < categoriesArray.length(); i++) {
JSONObject categoryJson = categoriesArray.optJSONObject(i);
if (categoryJson != null) {
this.offerCategories.add(new OfferCategory(categoryJson));
}
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeStringList(this.regions);
JSONArray categoriesArray = new JSONArray();
if (this.offerCategories != null) {
for (OfferCategory category : this.offerCategories) {
categoriesArray.put(category.toJSONObject());
}
}
dest.writeString(categoriesArray.toString());
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<Filter> CREATOR = new Creator<Filter>() {
@Override
public Filter createFromParcel(Parcel source) {
return new Filter(source);
}
@Override
public Filter[] newArray(int size) {
return new Filter[size];
}
};
// ================================================================================
// Getters
// ================================================================================
public ArrayList<OfferCategory> getOfferCategories() {
return offerCategories;
}
public ArrayList<String> getRegions() {
return regions;
}
// ================================================================================
// Setters
// ================================================================================
public void setOfferCategories(ArrayList<OfferCategory> offerCategories) {
this.offerCategories = offerCategories;
}
public void setRegions(ArrayList<String> regions) {
this.regions = regions;
}
}
......@@ -180,6 +180,18 @@ public interface ApiService {
@Header(WarpConstants.HEADER_WEB_ID) String webId,
@Header(WarpConstants.HEADER_SIGNATURE) String signature);
@Headers("Content-Type: application/json")
@POST("/oauth/{appUuid}/context")
Call<ResponseBody> getFilters(@Path("appUuid") String appUuid,
@Body RequestBody request,
@Header(WarpConstants.HEADER_DATE) String timeStamp,
@Header(WarpConstants.HEADER_LOYALTY_BUNDLE_ID) String bundleId,
@Header(WarpConstants.HEADER_UNIQUE_DEVICE_ID) String deviceId,
@Header(WarpConstants.HEADER_CHANNEL) String channel,
@Header(WarpConstants.HEADER_WEB_ID) String webId,
@Header(WarpConstants.HEADER_SIGNATURE) String signature,
@Header(WarpConstants.HEADER_AUTHORIZATION) String bearer);
// ===========================================================
// Getter & Setter
// ===========================================================
......
......@@ -39,6 +39,7 @@ import ly.warp.sdk.io.models.CarouselItem;
import ly.warp.sdk.io.models.Coupon;
import ly.warp.sdk.io.models.CouponList;
import ly.warp.sdk.io.models.Couponset;
import ly.warp.sdk.io.models.Filter;
import ly.warp.sdk.io.models.User;
import ly.warp.sdk.utils.managers.WarplyManager;
......@@ -63,6 +64,7 @@ public class WarplyManagerHelper {
private static ArrayList<CarouselItem> mCarouselListAll = new ArrayList<>();
private static LinkedHashMap<String, ArrayList<Couponset>> mCouponsetCategorizedMap = new LinkedHashMap<>();
private static User mUser = null;
private static Filter mFilter = null;
// ===========================================================
// Methods for/from SuperClass/Interfaces
......@@ -80,6 +82,14 @@ public class WarplyManagerHelper {
return mUser;
}
public static void setFilter(Filter filter) {
mFilter = filter;
}
public static Filter getFilter() {
return mFilter;
}
public static void setCampaignList(ArrayList<Campaign> campaignList) {
mCampaignListAll.clear();
mCampaignListAll.addAll(campaignList);
......
......@@ -65,6 +65,7 @@ import ly.warp.sdk.io.models.Campaign;
import ly.warp.sdk.io.models.Content;
import ly.warp.sdk.io.models.Coupon;
import ly.warp.sdk.io.models.Couponset;
import ly.warp.sdk.io.models.Filter;
import ly.warp.sdk.io.models.Merchant;
import ly.warp.sdk.io.models.User;
import ly.warp.sdk.io.request.WarplyRefreshTokenRequest;
......@@ -1425,4 +1426,107 @@ public class WarplyManager {
}
});
}
public static void getFilters(final CallbackReceiver<Filter> receiver) {
WarpUtils.log("************* WARPLY Filters Request ********************");
WarpUtils.log("[WARP Trace] WARPLY Filters Request is active");
WarpUtils.log("**************************************************");
ApiService service = ApiClient.getRetrofitInstance().create(ApiService.class);
ListeningExecutorService executorService = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(1));
ListenableFuture<Filter> futureFilters = getFiltersRetro(service);
ListenableFuture<List<Object>> allResultsFuture = Futures.allAsList(futureFilters);
ListenableFuture<Filter> mergedResultFuture = Futures.transformAsync(allResultsFuture, results -> {
Filter resultFilters = (Filter) results.get(0);
return executorService.submit(() -> resultFilters);
}, executorService);
Futures.addCallback(mergedResultFuture, new FutureCallback<Filter>() {
@Override
public void onSuccess(Filter mergedResult) {
executorService.shutdownNow();
new Handler(Looper.getMainLooper()).post(() -> receiver.onSuccess(mergedResult));
}
@Override
public void onFailure(Throwable throwable) {
executorService.shutdownNow();
new Handler(Looper.getMainLooper()).post(() -> receiver.onFailure(2));
}
}, executorService);
}
private static ListenableFuture<Filter> getFiltersRetro(ApiService service/*, Callback<ResponseBody> callback*/) {
SettableFuture<Filter> future = SettableFuture.create();
String timeStamp = DateFormat.format("yyyy-MM-dd hh:mm:ss", System.currentTimeMillis()).toString();
String apiKey = WarpUtils.getApiKey(Warply.getWarplyContext());
String webId = WarpUtils.getWebId(Warply.getWarplyContext());
Map<String, Object> jsonParamsFilters = new ArrayMap<>();
Map<String, Object> jsonParams = new ArrayMap<>();
jsonParams.put("action", "get_filters");
jsonParams.put("language", WarplyProperty.getLanguage(Warply.getWarplyContext()));
jsonParamsFilters.put("coupon", jsonParams);
RequestBody filtersRequest = RequestBody.create(MediaType.get("application/json; charset=utf-8"), (new JSONObject(jsonParamsFilters)).toString());
Call<ResponseBody> filtersCall = service.getFilters(
WarplyProperty.getAppUuid(Warply.getWarplyContext()),
filtersRequest,
timeStamp,
"android:" + Warply.getWarplyContext().getPackageName(),
new WarplyDeviceInfoCollector(Warply.getWarplyContext()).getUniqueDeviceId(),
"mobile",
webId,
WarpUtils.produceSignature(apiKey + timeStamp),
"Bearer " + WarplyDBHelper.getInstance(Warply.getWarplyContext()).getAuthValue("access_token")
);
filtersCall.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(@NonNull Call<ResponseBody> call, @NonNull Response<ResponseBody> response) {
if (response.code() == 200 && response.body() != null) {
JSONObject jobjFiltersResponse = null;
try {
jobjFiltersResponse = new JSONObject(response.body().string());
} catch (Exception e) {
e.printStackTrace();
}
if (jobjFiltersResponse != null && jobjFiltersResponse.has("status") && jobjFiltersResponse.optString("status", "2").equals("1")) {
JSONObject jFiltersBody = null;
try {
jFiltersBody = jobjFiltersResponse.optJSONObject("result");
} catch (Exception e) {
e.printStackTrace();
}
if (jFiltersBody != null) {
try {
Filter filter = new Filter(jFiltersBody);
WarplyManagerHelper.setFilter(filter);
future.set(filter);
} catch (Exception e) {
future.setException(e);
}
}
} else {
future.set(new Filter());
}
} else if (String.valueOf(response.code()).startsWith("5")) {
future.set(new Filter());
} else {
// future.set(new CouponsetsList());
future.setException(new Throwable());
}
}
@Override
public void onFailure(@NonNull Call<ResponseBody> call, @NonNull Throwable t) {
// future.set(new CouponsetsList());
future.setException(new Throwable());
}
});
return future;
}
}
......
......@@ -72,7 +72,7 @@
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/banner_viewpager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="130dp"
android:clipToPadding="false"
android:orientation="horizontal"
android:paddingHorizontal="16dp"
......@@ -125,6 +125,55 @@
</RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<RelativeLayout
android:id="@+id/header_layout2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:background="@color/white"
android:gravity="center_vertical"
android:paddingHorizontal="16dp">
<LinearLayout
android:id="@+id/ll_search_filter_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:background="@drawable/shape_rectangle_rounded_grey4"
android:gravity="center"
android:paddingHorizontal="20dp"
android:paddingVertical="12dp">
<TextView
android:id="@+id/tv_search_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:includeFontPadding="false"
android:text="@string/demo_search_title"
android:textColor="@color/custom_black6"
android:textSize="14sp" />
<View
android:layout_width="12dp"
android:layout_height="match_parent" />
<ImageView
android:layout_width="16dp"
android:layout_height="16dp"
android:src="@drawable/demo_filter" />
</LinearLayout>
<ImageView
android:id="@+id/location_icon"
android:layout_width="46dp"
android:layout_height="46dp"
android:layout_alignParentEnd="true"
android:background="@drawable/shape_rectangle_rounded_grey"
android:padding="14dp"
android:src="@drawable/demo_location_black" />
</RelativeLayout>
<LinearLayout
android:id="@+id/ll_sections_container"
android:layout_width="match_parent"
......@@ -184,9 +233,9 @@
<LinearLayout
android:layout_width="21dp"
android:layout_height="21dp"
android:orientation="horizontal"
android:background="@drawable/shape_rounded_transparent_white_border"
android:gravity="center"
android:background="@drawable/shape_rounded_transparent_white_border">
android:orientation="horizontal">
<TextView
android:id="@+id/tv_my_coupons_value"
......
......@@ -27,6 +27,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:background="@color/custom_skyblue3"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
......
......@@ -27,6 +27,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:background="@color/custom_skyblue3"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
......
......@@ -2,7 +2,8 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
<LinearLayout
android:id="@+id/ll_section_header"
......@@ -10,7 +11,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="horizontal"
android:paddingHorizontal="16dp">
android:paddingHorizontal="24dp">
<TextView
android:id="@+id/tv_section_title"
......@@ -28,7 +29,7 @@
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center"
android:paddingHorizontal="16dp">
android:paddingStart="16dp">
<TextView
android:id="@+id/tv_section_all"
......@@ -36,7 +37,7 @@
android:layout_height="wrap_content"
android:text="@string/demo_all"
android:includeFontPadding="false"
android:textColor="@color/custom_black3"
android:textColor="@color/custom_blue"
android:textSize="15sp" />
<View
......@@ -44,10 +45,9 @@
android:layout_height="match_parent" />
<ImageView
android:layout_width="8dp"
android:layout_height="4dp"
android:rotation="270"
android:src="@drawable/ic_arrow_down"/>
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_arrow_right_blue"/>
</LinearLayout>
</LinearLayout>
......
......@@ -43,4 +43,5 @@
<color name="custom_grey9">#ADB3B8</color>
<color name="custom_grey10">#ECEDEF</color>
<color name="custom_grey11">#E7E7E7</color>
<color name="custom_blue">#004E6E</color>
</resources>
......