Panagiotis Triantafyllou

deh part1

Showing 34 changed files with 717 additions and 2 deletions
package ly.warp.sdk.io.adapters;
import android.content.Context;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
import java.util.List;
import ly.warp.sdk.R;
import ly.warp.sdk.io.models.DummyDataProvider;
import ly.warp.sdk.io.models.OfferItem;
import ly.warp.sdk.utils.TopRoundedCornersTransformation;
/**
* Adapter for displaying offer items in a RecyclerView
*/
public class OfferAdapter extends RecyclerView.Adapter<OfferAdapter.OfferViewHolder> {
private final List<OfferItem> offerItems;
private final Context context;
private OnOfferClickListener listener;
/**
* Interface for handling offer item clicks
*/
public interface OnOfferClickListener {
void onOfferClick(OfferItem offerItem, int position);
void onFavoriteClick(OfferItem offerItem, int position);
}
/**
* Constructor
*
* @param context The context
* @param offerItems List of offer items to display
*/
public OfferAdapter(Context context, List<OfferItem> offerItems) {
this.context = context;
this.offerItems = offerItems;
}
/**
* Set click listener for offer items
*
* @param listener The listener
*/
public void setOnOfferClickListener(OnOfferClickListener listener) {
this.listener = listener;
}
@NonNull
@Override
public OfferViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.demo_item_offer, parent, false);
return new OfferViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull OfferViewHolder holder, int position) {
OfferItem offerItem = offerItems.get(position);
holder.bind(offerItem, position);
}
@Override
public int getItemCount() {
return offerItems.size();
}
/**
* ViewHolder for offer items
*/
class OfferViewHolder extends RecyclerView.ViewHolder {
private final ImageView ivOfferImage;
private final ImageView ivFavorite;
private final ImageView ivLogo;
private final TextView tvPrice;
private final TextView tvTitle;
private final TextView tvDescription;
private final TextView tvValidity;
OfferViewHolder(@NonNull View itemView) {
super(itemView);
ivOfferImage = itemView.findViewById(R.id.iv_offer_image);
ivFavorite = itemView.findViewById(R.id.iv_favorite);
ivLogo = itemView.findViewById(R.id.iv_logo);
tvPrice = itemView.findViewById(R.id.tv_price);
tvTitle = itemView.findViewById(R.id.tv_title);
tvDescription = itemView.findViewById(R.id.tv_description);
tvValidity = itemView.findViewById(R.id.tv_validity);
// Set click listeners
// itemView.setOnClickListener(v -> {
// int position = getAdapterPosition();
// if (listener != null && position != RecyclerView.NO_POSITION) {
// listener.onOfferClick(offerItems.get(position), position);
// }
// });
// ivFavorite.setOnClickListener(v -> {
// int position = getAdapterPosition();
// if (listener != null && position != RecyclerView.NO_POSITION) {
// listener.onFavoriteClick(offerItems.get(position), position);
// }
// });
}
void bind(OfferItem offerItem, int position) {
// Set offer data to views
tvTitle.setText(offerItem.getTitle());
tvDescription.setText(offerItem.getDescription());
tvPrice.setText(offerItem.getValue());
tvValidity.setText(offerItem.getEndDate());
// Set heart icon based on category
if (DummyDataProvider.CATEGORY_FAVORITES.equals(offerItem.getCategory())) {
// Use pressed/filled heart for Favorites category
ivFavorite.setImageResource(R.drawable.demo_heart_pressed);
} else {
// Use default/empty heart for other categories
ivFavorite.setImageResource(R.drawable.demo_heart);
}
// Load images from resources
loadOfferImage(offerItem.getImageUrl());
loadLogoImage(offerItem.getLogoUrl());
}
/**
* Load offer image with rounded top corners using Glide
*
* @param imageName The image resource name
*/
private void loadOfferImage(String imageName) {
try {
// Remove file extension if present
if (imageName.contains(".")) {
imageName = imageName.substring(0, imageName.lastIndexOf('.'));
}
// Get resource ID by name
int resourceId = context.getResources().getIdentifier(
imageName, "drawable", context.getPackageName());
if (resourceId != 0) {
// Convert 9dp to pixels
int radiusInPixels = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 9,
context.getResources().getDisplayMetrics());
// Load with Glide and apply transformations
Glide.with(context)
.load(resourceId)
.transform(new CenterCrop(), new TopRoundedCornersTransformation(radiusInPixels))
.into(ivOfferImage);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Load logo image without transformations
*
* @param imageName The image resource name
*/
private void loadLogoImage(String imageName) {
try {
// Remove file extension if present
if (imageName.contains(".")) {
imageName = imageName.substring(0, imageName.lastIndexOf('.'));
}
// Get resource ID by name
int resourceId = context.getResources().getIdentifier(
imageName, "drawable", context.getPackageName());
if (resourceId != 0) {
// Load logo normally without transformations
ivLogo.setImageResource(resourceId);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
package ly.warp.sdk.io.models;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* Model class representing a category of offers with its associated items.
*/
public class OfferCategory implements Serializable {
private String id;
private String name;
private List<OfferItem> items;
/**
* Default constructor
*/
public OfferCategory() {
this.items = new ArrayList<>();
}
/**
* Constructor with id and name
*
* @param id Unique identifier for the category
* @param name Display name of the category
*/
public OfferCategory(String id, String name) {
this.id = id;
this.name = name;
this.items = new ArrayList<>();
}
/**
* Full constructor
*
* @param id Unique identifier for the category
* @param name Display name of the category
* @param items List of offer items in this category
*/
public OfferCategory(String id, String name, List<OfferItem> items) {
this.id = id;
this.name = name;
this.items = items != null ? items : new ArrayList<>();
}
// Getters and Setters
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<OfferItem> getItems() {
return items;
}
public void setItems(List<OfferItem> items) {
this.items = items != null ? items : new ArrayList<>();
}
/**
* Add a single item to the category
*
* @param item The offer item to add
*/
public void addItem(OfferItem item) {
if (items == null) {
items = new ArrayList<>();
}
items.add(item);
}
/**
* Get the number of items in this category
*
* @return The count of items
*/
public int getItemCount() {
return items != null ? items.size() : 0;
}
/**
* Get the formatted name with item count
*
* @return Category name with item count in parentheses
*/
public String getFormattedName() {
return name + " (" + getItemCount() + ")";
}
}
package ly.warp.sdk.io.models;
import java.io.Serializable;
/**
* Model class representing an offer item to be displayed in the home screen.
*/
public class OfferItem implements Serializable {
private String id;
private String title;
private String description;
private String endDate;
private String value;
private String imageUrl;
private String logoUrl;
private String category;
/**
* Default constructor
*/
public OfferItem() {
}
/**
* Full constructor for creating an offer item
*
* @param id Unique identifier for the offer
* @param title Title of the offer
* @param description Description of the offer
* @param endDate End date of the offer (formatted as string)
* @param value Value of the offer (formatted as string, e.g., "50%", "€20")
* @param imageUrl URL or resource name for the offer image
* @param logoUrl URL or resource name for the merchant logo
* @param category Category this offer belongs to
*/
public OfferItem(String id, String title, String description, String endDate,
String value, String imageUrl, String logoUrl, String category) {
this.id = id;
this.title = title;
this.description = description;
this.endDate = endDate;
this.value = value;
this.imageUrl = imageUrl;
this.logoUrl = logoUrl;
this.category = category;
}
// Getters and Setters
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getEndDate() {
return endDate;
}
public void setEndDate(String endDate) {
this.endDate = endDate;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getImageUrl() {
return imageUrl;
}
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
public String getLogoUrl() {
return logoUrl;
}
public void setLogoUrl(String logoUrl) {
this.logoUrl = logoUrl;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
/**
* Returns the value (already formatted with % or € symbol)
* @return Value string
*/
public String getFormattedValue() {
return value;
}
}
package ly.warp.sdk.utils;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Shader;
import androidx.annotation.NonNull;
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
import java.security.MessageDigest;
/**
* Glide transformation to round only the top corners of an image
*/
public class TopRoundedCornersTransformation extends BitmapTransformation {
private static final String ID = "ly.warp.sdk.utils.TopRoundedCornersTransformation";
private final int radius;
/**
* Constructor
*
* @param radius Corner radius in pixels
*/
public TopRoundedCornersTransformation(int radius) {
this.radius = radius;
}
@Override
protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) {
return roundTopCorners(pool, toTransform);
}
private Bitmap roundTopCorners(BitmapPool pool, Bitmap source) {
if (source == null) return null;
Bitmap result = pool.get(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
if (result == null) {
result = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
}
Canvas canvas = new Canvas(result);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setShader(new BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
// Create path with rounded top corners
Path path = new Path();
RectF rectF = new RectF(0, 0, source.getWidth(), source.getHeight());
float[] radii = new float[]{
radius, radius, // top-left
radius, radius, // top-right
0, 0, // bottom-right
0, 0 // bottom-left
};
path.addRoundRect(rectF, radii, Path.Direction.CW);
// Draw rounded rectangle
canvas.drawPath(path, paint);
return result;
}
@Override
public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {
messageDigest.update((ID + radius).getBytes());
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TopRoundedCornersTransformation that = (TopRoundedCornersTransformation) o;
return radius == that.radius;
}
@Override
public int hashCode() {
return ID.hashCode() + radius;
}
}
......@@ -167,6 +167,30 @@ public class WarplyManagerHelper {
context.startActivity(WarpViewActivity.createIntentFromURL(context, (WarplyProperty.getSupermarketsUrl(context) + WarpConstants.SUPERMARKETS_MAP)));
}
public static void openContest(Context context) {
final String mContestUrl = "https://warply.s3.amazonaws.com/dei/campaigns/DehEasterContest_stage/index.html";
JSONObject params = new JSONObject();
try {
params.putOpt("web_id", WarpUtils.getWebId(context));
params.putOpt("app_uuid", WarplyProperty.getAppUuid(context));
params.putOpt("api_key", WarpUtils.getApiKey(context));
params.putOpt("session_uuid", "");
params.putOpt("access_token", WarplyDBHelper.getInstance(context).getAuthValue("access_token"));
params.putOpt("refresh_token", WarplyDBHelper.getInstance(context).getAuthValue("refresh_token"));
params.putOpt("client_id", WarplyDBHelper.getInstance(context).getClientValue("client_id"));
params.putOpt("client_secret", WarplyDBHelper.getInstance(context).getClientValue("client_secret"));
params.putOpt("map", "true");
params.putOpt("lan", WarpUtils.getApplicationLocale(context));
params.putOpt("dark", String.valueOf(WarpUtils.getIsDarkModeEnabled(context)));
} catch (JSONException e) {
e.printStackTrace();
}
WarpUtils.setWebviewParams(context, params);
context.startActivity(WarpViewActivity.createIntentFromURL(context, mContestUrl));
}
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
......
package ly.warp.sdk.views;
import android.graphics.Rect;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
/**
* ItemDecoration for adding horizontal spacing between RecyclerView items.
* Adds spacing to the right of each item except the last one.
*/
public class HorizontalSpaceItemDecoration extends RecyclerView.ItemDecoration {
private final int spaceWidth;
/**
* Constructor
*
* @param spaceWidth Space width in pixels
*/
public HorizontalSpaceItemDecoration(int spaceWidth) {
this.spaceWidth = spaceWidth;
}
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
// Add spacing to the right of each item except the last one
int position = parent.getChildAdapterPosition(view);
if (position != RecyclerView.NO_POSITION && position != parent.getAdapter().getItemCount() - 1) {
outRect.right = spaceWidth;
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<corners android:radius="1000dp" />
<solid android:color="@color/pink" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
android:bottomLeftRadius="0dp"
android:bottomRightRadius="0dp"
android:topLeftRadius="9dp"
android:topRightRadius="9dp" />
<solid android:color="@android:color/transparent" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="4dp" />
<solid android:color="@android:color/transparent" />
<stroke
android:width="1dp"
android:color="@color/black2" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="9dp" />
<solid android:color="@color/white" />
<stroke
android:width="1dp"
android:color="@color/grey" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="260dp"
android:layout_height="250dp"
android:background="@drawable/demo_shape_white_border_grey">
<!-- Main Offer Image -->
<ImageView
android:id="@+id/iv_offer_image"
android:layout_width="match_parent"
android:layout_height="140dp"
android:scaleType="centerCrop"
tools:src="@drawable/demo_home_banner" />
<!-- Heart Icon (Favorite) -->
<ImageView
android:id="@+id/iv_favorite"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_margin="8dp"
android:src="@drawable/demo_heart" />
<!-- Price Badge -->
<TextView
android:id="@+id/tv_price"
android:layout_width="68dp"
android:layout_height="68dp"
android:layout_alignParentEnd="true"
android:layout_margin="8dp"
android:background="@drawable/demo_shape_pink"
android:gravity="center"
android:textColor="@android:color/white"
android:textSize="16sp"
android:textStyle="bold"
tools:text="17,95€" />
<!-- Content Section -->
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/iv_offer_image"
android:orientation="vertical"
android:padding="12dp">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/gl_vertical_70"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.7" />
<!-- Title -->
<TextView
android:id="@+id/tv_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:maxLines="1"
android:textColor="@color/black2"
android:textSize="16sp"
android:textStyle="bold"
app:layout_constraintEnd_toStartOf="@+id/gl_vertical_70"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Móvo 17,95" />
<!-- Description -->
<TextView
android:id="@+id/tv_description"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:maxLines="2"
android:textColor="@color/black3"
android:textSize="13sp"
app:layout_constraintEnd_toStartOf="@+id/gl_vertical_70"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_title"
tools:text="2 πίτσες &amp; Coca-COLA 1,5lt" />
<!-- Validity Date -->
<TextView
android:id="@+id/tv_validity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_marginTop="12dp"
android:maxLines="1"
android:textColor="#757575"
android:textSize="12sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_description"
tools:text="έως 30-09" />
<!-- Brand Logo -->
<ImageView
android:id="@+id/iv_logo"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:scaleType="centerInside"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/demo_avis" />
</androidx.constraintlayout.widget.ConstraintLayout>
</RelativeLayout>
......@@ -13,6 +13,10 @@
<color name="blue_dark">#3A5266</color>
<color name="white">#FFFFFF</color>
<color name="cos_green5">#79BF14</color>
<color name="black2">#000F1E</color>
<color name="black3">#00111B</color>
<color name="grey">#CCCCCC</color>
<color name="pink">#EE417D</color>
<!-- Used in styles -->
<color name="cos_light_blue">#00A5E3</color>
......
<resources>
<string name="lbl_cosmote_webview_permission_title">COSMOTE</string>
<string name="lbl_cosmote_webview_permission_message">Το COSMOTE ζητάει πρόσβαση στην τοποθεσία σας.</string>
<string name="lbl_cosmote_webview_permission_title">Demo App</string>
<string name="lbl_cosmote_webview_permission_message">Το Demo App ζητάει πρόσβαση στην τοποθεσία σας.</string>
<string name="lbl_take_photo_accept">Οκ</string>
<string name="lbl_take_photo_decline">Άκυρο</string>
<string name="welcome_user">Γεια σου %1$s !</string>
......@@ -10,4 +10,5 @@
<string name="menu_home">Αρχική</string>
<string name="demo_sm_flow">Open SM Flow</string>
<string name="demo_sm_map">Open SM Map</string>
<string name="demo_all">Όλα</string>
</resources>
......